diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d936616077..ada020d8722 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,12 +103,24 @@ jobs: run: pyright working-directory: ./worktree-image - - name: Build (fallback to non-incremental) - id: build + - name: Clean (fallback to non-incremental) + id: clean if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' run: | set -ex - ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status && make build + ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status + working-directory: ./worktree-image + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 + + - name: Build + # This step is needed because building the modularized distributions installs some optional packages, + # so the editable install of sagelib needs to build the corresponding optional extension modules. + id: build + if: always() && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success') + run: | + make build working-directory: ./worktree-image env: MAKE: make -j2 @@ -125,14 +137,14 @@ jobs: COLUMNS: 120 - name: Test all files (sage -t --all --long) - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' run: | ../sage -python -m pip install coverage ../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303 working-directory: ./worktree-image/src - name: Prepare coverage results - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' run: | ./venv/bin/python3 -m coverage combine src/.coverage/ ./venv/bin/python3 -m coverage xml @@ -140,7 +152,7 @@ jobs: working-directory: ./worktree-image - name: Upload coverage to codecov - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' uses: codecov/codecov-action@v3 with: files: ./worktree-image/coverage.xml diff --git a/CITATION.cff b/CITATION.cff index 6f4f46a6d8a..effa2901c0c 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.1.beta8 +version: 10.1.rc0 doi: 10.5281/zenodo.593563 -date-released: 2023-07-30 +date-released: 2023-08-13 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/README.md b/README.md index 9982460cd78..2e5419541af 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ your Windows. Make sure you allocate WSL sufficient RAM; 5GB is known to work, w Then all instructions for installation in Linux apply. As an alternative, you can also run Linux on Windows using Docker (see -above) or other virtualization solutions. +below) or other virtualization solutions. [macOS] Preparing the Platform ------------------------------ @@ -416,6 +416,18 @@ You need to install `sage_conf`, a wheelhouse of various python packages. You ca **NOTE:** You can find `sage` and `sagemath` pip packages but with these packages, you will encounter `ModuleNotFoundError`. +SageMath Docker images +---------------------- + +[![Docker Status](http://dockeri.co/image/sagemath/sagemath)](https://hub.docker.com/r/sagemath/sagemath) + +SageMath is available on Docker Hub and can be downloaded by: +``` bash +docker pull sagemath/sagemath +``` + +Currently, only stable versions are kept up to date. + Troubleshooting --------------- diff --git a/VERSION.txt b/VERSION.txt index d9562f0204a..a62521f032f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.1.beta8, Release Date: 2023-07-30 +SageMath version 10.1.rc0, Release Date: 2023-08-13 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index e489dd26d2e..ba26592020a 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=5930a5bb8c0164176122d6ffb1143df61b990213 -md5=b70ab1eaa247dce59a59910ec8e89051 -cksum=3869087595 +sha1=139bcabc03fbf74d05379ff27713c7e3496fc362 +md5=2631cd73e85221b77dea105e30f6165d +cksum=2003135383 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 33340576bb6..b18e430562c 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -79dc3510abb05344ac7ef23d42d1228f186b7493 +50208b761995b49bf6f0702f4b9d36da24fae1a0 diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 308956090b6..69a6f60f50b 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.1b8 +sage-conf ~= 10.1rc0 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index f2408da3bef..76cee94895b 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.1b8 +sage-docbuild ~= 10.1rc0 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 3fb4f9bd897..ec6e85e090c 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.1b8 +sage-setup ~= 10.1rc0 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 5705cd5cef9..440d25adb32 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.1b8 +sage-sws2rst ~= 10.1rc0 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 09ddf8e9f0e..cb3d1c3382f 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.1b8 +sagemath-standard ~= 10.1rc0 diff --git a/build/pkgs/sagemath_bliss/install-requires.txt b/build/pkgs/sagemath_bliss/install-requires.txt index 175856b245f..8a64ef0c0b1 100644 --- a/build/pkgs/sagemath_bliss/install-requires.txt +++ b/build/pkgs/sagemath_bliss/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.1b8 +sagemath-bliss ~= 10.1rc0 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 2bc854cfebc..c9666be341e 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.1b8 +sagemath-categories ~= 10.1rc0 diff --git a/build/pkgs/sagemath_coxeter3/install-requires.txt b/build/pkgs/sagemath_coxeter3/install-requires.txt index 7576be637d3..8db0a45278c 100644 --- a/build/pkgs/sagemath_coxeter3/install-requires.txt +++ b/build/pkgs/sagemath_coxeter3/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.1b8 +sagemath-coxeter3 ~= 10.1rc0 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index ac5083c4105..1bf65f70706 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.1b8 +sagemath-environment ~= 10.1rc0 diff --git a/build/pkgs/sagemath_mcqd/install-requires.txt b/build/pkgs/sagemath_mcqd/install-requires.txt index 211e612c18e..ad1d463c994 100644 --- a/build/pkgs/sagemath_mcqd/install-requires.txt +++ b/build/pkgs/sagemath_mcqd/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.1b8 +sagemath-mcqd ~= 10.1rc0 diff --git a/build/pkgs/sagemath_meataxe/install-requires.txt b/build/pkgs/sagemath_meataxe/install-requires.txt index 1ca467ef1b7..0fbda8ca0a9 100644 --- a/build/pkgs/sagemath_meataxe/install-requires.txt +++ b/build/pkgs/sagemath_meataxe/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.1b8 +sagemath-meataxe ~= 10.1rc0 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index c8da8347647..47b1fbbe689 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.1b8 +sagemath-objects ~= 10.1rc0 diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt index da36117bd6e..dc870d02cfd 100644 --- a/build/pkgs/sagemath_repl/install-requires.txt +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.1b8 +sagemath-repl ~= 10.1rc0 diff --git a/build/pkgs/sagemath_sirocco/install-requires.txt b/build/pkgs/sagemath_sirocco/install-requires.txt index 417fc0e71cf..03021ff49a6 100644 --- a/build/pkgs/sagemath_sirocco/install-requires.txt +++ b/build/pkgs/sagemath_sirocco/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.1b8 +sagemath-sirocco ~= 10.1rc0 diff --git a/build/pkgs/sagemath_tdlib/install-requires.txt b/build/pkgs/sagemath_tdlib/install-requires.txt index 949a775737d..57437e13652 100644 --- a/build/pkgs/sagemath_tdlib/install-requires.txt +++ b/build/pkgs/sagemath_tdlib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.1b8 +sagemath-tdlib ~= 10.1rc0 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-bliss/MANIFEST.in b/pkgs/sagemath-bliss/MANIFEST.in index 689b87560e0..6d981b9d30e 100644 --- a/pkgs/sagemath-bliss/MANIFEST.in +++ b/pkgs/sagemath-bliss/MANIFEST.in @@ -1,5 +1,3 @@ -global-include all__sagemath_bliss.py - include VERSION.txt graft sage/graphs/bliss_cpp @@ -7,6 +5,9 @@ graft sage/graphs/bliss_cpp global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_bliss.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 361132e0cfa..b2e35673ec0 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -3,7 +3,6 @@ prune sage include VERSION.txt -global-include all__sagemath_categories.py graft sage/categories # Exclude what is already shipped in sagemath-objects exclude sage/categories/action.* @@ -42,6 +41,9 @@ graft sage/typeset # dep of sage.categories.tensor global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_categories.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-coxeter3/MANIFEST.in b/pkgs/sagemath-coxeter3/MANIFEST.in index 003ab8d5180..a69f2e71363 100644 --- a/pkgs/sagemath-coxeter3/MANIFEST.in +++ b/pkgs/sagemath-coxeter3/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_coxeter3.py - include VERSION.txt graft sage/libs/coxeter3 @@ -9,6 +7,9 @@ graft sage/libs/coxeter3 global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_coxeter3.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-environment/MANIFEST.in b/pkgs/sagemath-environment/MANIFEST.in index 36f8fae1845..ca4266e2bf4 100644 --- a/pkgs/sagemath-environment/MANIFEST.in +++ b/pkgs/sagemath-environment/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_environment.py - include sage/env.py include sage/version.py include sage/misc/package.py @@ -12,4 +10,14 @@ graft sage/features include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_environment.py + +global-exclude __pycache__ global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-mcqd/MANIFEST.in b/pkgs/sagemath-mcqd/MANIFEST.in index 392d97b78e0..801e1b3e48d 100644 --- a/pkgs/sagemath-mcqd/MANIFEST.in +++ b/pkgs/sagemath-mcqd/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_mcqd.py - include VERSION.txt include sage/graphs/mcqd.p* @@ -9,6 +7,9 @@ include sage/graphs/mcqd.p* global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_mcqd.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-meataxe/MANIFEST.in b/pkgs/sagemath-meataxe/MANIFEST.in index 4cf78dd5d02..c69ce68fc40 100644 --- a/pkgs/sagemath-meataxe/MANIFEST.in +++ b/pkgs/sagemath-meataxe/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_meataxe.py - include VERSION.txt include sage/libs/meataxe.p* @@ -10,6 +8,9 @@ include sage/matrix/matrix_gfpn_dense.p* global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_meataxe.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-meataxe/README.rst b/pkgs/sagemath-meataxe/README.rst index 088ce86478b..659edb3cf9f 100644 --- a/pkgs/sagemath-meataxe/README.rst +++ b/pkgs/sagemath-meataxe/README.rst @@ -28,8 +28,8 @@ About this pip-installable source distribution This pip-installable source distribution ``sagemath-meataxe`` is a small optional distribution for use with ``sagemath-standard``. -This distribution provides the SageMath modules :mod:`sage.libs.meataxe` -and :mod:`sage.matrix.matrix_gfpn_dense`. +This distribution provides the SageMath modules ``sage.libs.meataxe`` +and ``sage.matrix.matrix_gfpn_dense``. It provides a specialized implementation of matrices over the finite field F_q, where q <= 255, using the `SharedMeatAxe ` diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index 00c5e0dc4a1..98b6910849a 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -3,8 +3,6 @@ graft sage/cpython include VERSION.txt -global-include all__sagemath_objects.py - graft sage/structure include sage/categories/action.* include sage/categories/algebra_functor.* @@ -85,6 +83,8 @@ graft sage/libs/gmp include sage/misc/misc.* # some_tuples used in sage.misc.sage_unittest include sage/misc/timing.p* # walltime, cputime used in sage.doctest +global-exclude all__*.py +global-include all__sagemath_objects.py global-exclude *.c global-exclude *.cpp diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in index c54f63b15ee..ba331ec2931 100644 --- a/pkgs/sagemath-repl/MANIFEST.in +++ b/pkgs/sagemath-repl/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_repl.py - graft sage/doctest graft sage/repl include sage/misc/banner.py @@ -11,6 +9,9 @@ include sage/misc/sage_eval.py include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_repl.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-sirocco/MANIFEST.in b/pkgs/sagemath-sirocco/MANIFEST.in index 7fab4dffc5d..815a868524d 100644 --- a/pkgs/sagemath-sirocco/MANIFEST.in +++ b/pkgs/sagemath-sirocco/MANIFEST.in @@ -1,10 +1,11 @@ -global-include all__sagemath_sirocco.py - include VERSION.txt global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_sirocco.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/pkgs/sagemath-tdlib/MANIFEST.in b/pkgs/sagemath-tdlib/MANIFEST.in index f3fbc97a588..614186d89ab 100644 --- a/pkgs/sagemath-tdlib/MANIFEST.in +++ b/pkgs/sagemath-tdlib/MANIFEST.in @@ -1,5 +1,3 @@ -global-include all__sagemath_tdlib.py - include VERSION.txt global-exclude *.c @@ -7,6 +5,9 @@ global-exclude *.cpp include sage/graphs/graph_decompositions/sage_tdlib.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_tdlib.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/src/.relint.yml b/src/.relint.yml index d0eafb0d8fc..97bf2ac1dbc 100644 --- a/src/.relint.yml +++ b/src/.relint.yml @@ -51,7 +51,18 @@ # Keep in sync with SAGE_ROOT/src/sage/misc/replace_dot_all.py pattern: 'from\s+sage(|[.](arith|categories|combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|symbolic|tensor)[a-z0-9_.]*|[.]libs)[.]all\s+import' # imports from .all are allowed in all.py; also allow in some modules that need sage.all - filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval))[^/.]*[.](py|pyx|pxi)$' + filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval|explain_pickle|.*_test))[^/.]*[.](py|pyx|pxi)$' + +- name: 'namespace_pkg_all_import_2: Module-level import of .all of a namespace package' + hint: | + Sage library code should not import sage.PAC.KAGE.all when sage.PAC.KAGE is an implicit + namespace package. Type import_statements("SOME_IDENTIFIER") to find a more specific import, + and rewrite the import statement as "from sage.PAC.KAGE.MODULE import ..." + or "lazy_import('sage.PAC.KAGE.MODULE', '...')". + # Keep in sync with above; but for now we ignore sage.{arith,categories} + pattern: '^import\s+sage(|[.](combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|symbolic|tensor)[a-z0-9_.]*|[.]libs)[.]all' + # imports from .all are allowed in all.py; also allow in some modules that need sage.all + filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval|explain_pickle|.*_test))[^/.]*[.](py|pyx|pxi)$' # Magic doctest comments diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 0f6e2a37890..bbed8838199 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -21,7 +21,6 @@ global-exclude *.cpp include sage/cpython/debugimpl.c include sage/graphs/base/boost_interface.cpp include sage/graphs/cliquer/cl.c -include sage/graphs/graph_decompositions/sage_tdlib.cpp include sage/libs/eclib/wrap.cpp include sage/libs/linkages/padics/relaxed/flint_helper.c include sage/misc/inherit_comparison_impl.c @@ -45,7 +44,21 @@ include sage/geometry/triangulation/data.cc include sage/geometry/triangulation/functions.cc # Exclude extension modules shipped by optional packages -exclude sage/graphs/bliss.pyx +exclude sage/graphs/bliss.p* +prune sage/graphs/bliss_cpp +prune sage/libs/coxeter3 +exclude sage/graphs/mcqd.p* +exclude sage/libs/meataxe.p* +exclude sage/matrix/matrix_gfpn_dense.p* +exclude sage/graphs/graph_decomposition/tdlib.p* + +# Exclude all__*.py files belonging to distributions related to optional packages +global-exclude all__sagemath_bliss.py +global-exclude all__sagemath_coxeter3.py +global-exclude all__sagemath_mcqd.py +global-exclude all__sagemath_meataxe.py +global-exclude all__sagemath_sirocco.py +global-exclude all__sagemath_tdlib.py global-exclude __pycache__ global-exclude *.py[co] diff --git a/src/VERSION.txt b/src/VERSION.txt index d06eca61e5a..72237f23c26 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.rc0 diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 0c06d448887..50387881ad3 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -40,7 +40,7 @@ import sys from argparse import ArgumentParser, FileType from pathlib import Path -from sage.doctest.control import skipfile +from sage.doctest.control import DocTestDefaults, DocTestController from sage.doctest.parsing import parse_file_optional_tags, parse_optional_tags, unparse_optional_tags, update_optional_tags from sage.env import SAGE_ROOT from sage.features import PythonModule @@ -189,8 +189,12 @@ def process_block(block, src_in_lines, file_optional_tags): return # Error testing. - if m := re.search(r"ModuleNotFoundError: No module named '([^']*)'", block): - module = m.group(1) + if m := re.search(r"(?:ModuleNotFoundError: No module named|ImportError: cannot import name '([^']*)' from) '([^']*)'", block): + if m.group(1): + # "ImportError: cannot import name 'function_field_polymod' from 'sage.rings.function_field' (unknown location)" + module = m.group(2) + '.' + m.group(1) + else: + module = m.group(2) asked_why = re.search('#.*(why|explain)', src_in_lines[first_line_num - 1]) optional = module_feature(module) if optional and optional.name not in file_optional_tags: @@ -224,6 +228,8 @@ def process_block(block, src_in_lines, file_optional_tags): # NameError from top level, so keep it brief if m := re.match("NameError: name '(.*)'", got[index_NameError:]): name = m.group(1) + if name == 'x': # Don't mark it '# needs sage.symbolic'; that's almost always wrong + return if feature := name_feature(name): add_tags = [feature.name] else: @@ -305,17 +311,21 @@ def process_block(block, src_in_lines, file_optional_tags): # set input and output files -if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: - inputs, outputs = [args.filename[0]], [args.filename[1]] - print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " - "this is deprecated. To pass two input filenames, use the option --overwrite.") -elif args.no_overwrite: - inputs, outputs = args.filename, [input + ".fixed" for input in args.filename] -else: - inputs = outputs = args.filename +def output_filename(filename): + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + if args.filename[0] == filename: + return args.filename[1] + else: + return None + return filename + ".fixed" + if args.no_overwrite: + return filename + ".fixed" + return filename # Test the doctester, putting the output of the test into sage's temporary directory -if not args.no_test: +if args.no_test: + doc_out = '' +else: executable = f'{os.path.relpath(args.venv)}/bin/sage' if args.venv else 'sage' environment_args = f'--environment {args.environment} ' if args.environment != runtest_default_environment else '' long_args = f'--long ' if args.long else '' @@ -329,38 +339,61 @@ if not args.no_test: if status := os.waitstatus_to_exitcode(os.system(f'{cmdline} > {shlex.quote(doc_file)}')): print(f'Doctester exited with error status {status}') sys.exit(status) + # Run the doctester, putting the output of the test into sage's temporary directory + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " + "this is deprecated. To pass two input filenames, use the option --overwrite.") -for input, output in zip(inputs, outputs): - if (skipfile_result := skipfile(input, True, log=print)) is True: - continue - - if args.no_test: - doc_out = '' + input_filenames = [args.filename[0]] else: - # Run the doctester, putting the output of the test into sage's temporary directory - cmdline = f'{shlex.quote(executable)} -t {environment_args}{long_args}{probe_args}{lib_args}{shlex.quote(input)}' - print(f'Running "{cmdline}"') - os.system(f'{cmdline} > {shlex.quote(doc_file)}') + input_filenames = args.filename + input_args = " ".join(shlex.quote(f) for f in input_filenames) + cmdline = f'{shlex.quote(executable)} -t -p {environment_args}{long_args}{probe_args}{lib_args}{input_args}' + print(f'Running "{cmdline}"') + os.system(f'{cmdline} > {shlex.quote(doc_file)}') - with open(doc_file, 'r') as doc: - doc_out = doc.read() + with open(doc_file, 'r') as doc: + doc_out = doc.read() # echo control messages for m in re.finditer('^Skipping .*', doc_out, re.MULTILINE): print('sage-runtests: ' + m.group(0)) - break - else: - sep = "**********************************************************************\n" - doctests = doc_out.split(sep) + +sep = "**********************************************************************\n" +doctests = doc_out.split(sep) + +seen = set() + +def block_filename(block): + if not (m := re.match('File "([^"]*)", line ([0-9]+), in ', block)): + return None + return m.group(1) + +def expanded_filename_args(): + DD = DocTestDefaults(optional='all', warn_long=10000) + DC = DocTestController(DD, input_filenames) + DC.add_files() + DC.expand_files_into_sources() + for source in DC.sources: + yield source.path + +def process_grouped_blocks(grouped_iterator): + + for input, blocks in grouped_iterator: + + if not input: # Blocks of noise + continue + if input in seen: + continue + seen.add(input) with open(input, 'r') as test_file: src_in = test_file.read() src_in_lines = src_in.splitlines() shallow_copy_of_src_in_lines = list(src_in_lines) - file_optional_tags = set(parse_file_optional_tags(enumerate(src_in_lines))) - for block in doctests: + for block in blocks: process_block(block, src_in_lines, file_optional_tags) # Now source line numbers do not matter any more, and lines can be real lines again @@ -392,20 +425,26 @@ for input, output in zip(inputs, outputs): persistent_optional_tags = {} if src_in_lines != shallow_copy_of_src_in_lines: - with open(output, 'w') as test_output: - for line in src_in_lines: - if line is None: - continue - test_output.write(line) - test_output.write('\n') - - # Show summary of changes - if input != output: - print("The fixed doctests have been saved as '{0}'.".format(output)) + if (output := output_filename(input)) is None: + print(f"Not saving modifications made in '{input}'") else: - relative = os.path.relpath(output, SAGE_ROOT) - print(f"The input file '{output}' has been overwritten.") - if not relative.startswith('..'): - subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) + with open(output, 'w') as test_output: + for line in src_in_lines: + if line is None: + continue + test_output.write(line) + test_output.write('\n') + # Show summary of changes + if input != output : + print("The fixed doctests have been saved as '{0}'.".format(output)) + else: + relative = os.path.relpath(output, SAGE_ROOT) + print(f"The input file '{output}' has been overwritten.") + if not relative.startswith('..'): + subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) else: print(f"No fixes made in '{input}'") + +process_grouped_blocks( + itertools.chain(itertools.groupby(doctests, block_filename), + ((filename, []) for filename in expanded_filename_args()))) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 4d606c5a3a8..01b7ca44868 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -175,13 +175,18 @@ if __name__ == "__main__": pytest_options = [] if args.verbose: pytest_options.append("-v") - # #31924: Do not run pytest on individual Python files unless - # they match the pytest file pattern. However, pass names - # of directories. We use 'not os.path.isfile(f)' for this so that - # we do not silently hide typos. - filenames = [f for f in args.filenames - if f.endswith("_test.py") or not os.path.isfile(f)] - if filenames or not args.filenames: + + # #35999: no filename in arguments defaults to "src" + if not args.filenames: + filenames = [SAGE_SRC] + else: + # #31924: Do not run pytest on individual Python files unless + # they match the pytest file pattern. However, pass names + # of directories. We use 'not os.path.isfile(f)' for this so that + # we do not silently hide typos. + filenames = [f for f in args.filenames + if f.endswith("_test.py") or not os.path.isfile(f)] + if filenames: print(f"Running pytest on {filenames} with options {pytest_options}") exit_code_pytest = pytest.main(filenames + pytest_options) if exit_code_pytest == 5: diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 1800ec2771f..5cbb47685ea 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.1.beta8' -SAGE_RELEASE_DATE='2023-07-30' -SAGE_VERSION_BANNER='SageMath version 10.1.beta8, Release Date: 2023-07-30' +SAGE_VERSION='10.1.rc0' +SAGE_RELEASE_DATE='2023-08-13' +SAGE_VERSION_BANNER='SageMath version 10.1.rc0, Release Date: 2023-08-13' diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index a4f05a0fdc7..92ae74b30db 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -143,7 +143,6 @@ Comprehensive Module List sage/combinat/integer_vector_weighted sage/combinat/integer_vectors_mod_permgroup sage/combinat/interval_posets - sage/combinat/k_regular_sequence sage/combinat/k_tableau sage/combinat/kazhdan_lusztig sage/combinat/key_polynomial @@ -206,6 +205,7 @@ Comprehensive Module List sage/combinat/quickref sage/combinat/ranker sage/combinat/recognizable_series + sage/combinat/regular_sequence sage/combinat/restricted_growth sage/combinat/ribbon sage/combinat/ribbon_shaped_tableau diff --git a/src/doc/en/website/root_index.html b/src/doc/en/website/root_index.html index 3ae4d4cd272..21a6086ed72 100644 --- a/src/doc/en/website/root_index.html +++ b/src/doc/en/website/root_index.html @@ -113,7 +113,7 @@

Sage Documentation

English
A Tour of Sage
-
Tutorial
+
Tutorial
Thematic Tutorials
PREP Tutorials
Constructions
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 6388fa79e60..7c2fe4a2210 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -59,9 +59,9 @@ def normalize_names_markov(names, markov_trace_version): if markov_trace_version: names = normalize_names(4, names) else: - if type(names) == tuple: + if isinstance(names, tuple): names = list(names) - if type(names) == list and len(names) > 3: + if isinstance(names, list) and len(names) > 3: names = normalize_names(3, names[0:3]) else: names = normalize_names(3, names) @@ -641,10 +641,10 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non # corresponding specialized extension ring. # ---------------------------------------------------------------------- - if type(im_cubic_equation_roots) == tuple: + if isinstance(im_cubic_equation_roots, tuple): im_cubic_equation_roots = list(im_cubic_equation_roots) - if type(im_cubic_equation_roots) != list: + if not isinstance(im_cubic_equation_roots, list): raise TypeError('cubic_equation_roots must be a list of three elements') if len(im_cubic_equation_roots) != 3: @@ -1226,10 +1226,10 @@ def create_specialization(self, im_cubic_equation_parameters, im_writhe_paramete # ---------------------------------------------------------------------- # setting the base_ring according to the cubic_equation_parameters # ---------------------------------------------------------------------- - if type(im_cubic_equation_parameters) == tuple: + if isinstance(im_cubic_equation_parameters, tuple): im_cubic_equation_parameters = list(im_cubic_equation_parameters) - if type(im_cubic_equation_parameters) != list: + if not isinstance(im_cubic_equation_parameters, list): raise TypeError('cubic_equation_parameters must be a list of three elements') if len(im_cubic_equation_parameters) != 3: diff --git a/src/sage/algebras/letterplace/free_algebra_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_letterplace.pyx index 6913bbc26fc..e9c70c9de29 100644 --- a/src/sage/algebras/letterplace/free_algebra_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_letterplace.pyx @@ -176,7 +176,6 @@ cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring, blocks): (Lexicographic term order of length 3, Lexicographic term order of length 3) """ - n = base_ring.ngens() T0 = base_ring.term_order() T = T0 cdef i @@ -680,7 +679,6 @@ cdef class FreeAlgebra_letterplace(Algebra): C = self.current_ring() cdef FreeAlgebraElement_letterplace x ngens = self.__ngens - degbound = self._degbound cdef list G = [C(x._poly) for x in g] from sage.groups.perm_gps.permgroup_named import CyclicPermutationGroup CG = CyclicPermutationGroup(C.ngens()) diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index b901c3b8225..5e991dd80bc 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - gap_package_quagroup """ Quantum Groups Using GAP's QuaGroup Package @@ -57,8 +58,8 @@ def __init__(self, parent, libgap_elt): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: TestSuite(Q.an_element()).run() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: TestSuite(Q.an_element()).run() """ self._libgap = libgap(libgap_elt) Element.__init__(self, parent) @@ -69,13 +70,13 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: Q.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: Q.an_element() 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: Q.F_simple() # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: Q.F_simple() Finite family {1: F[a1], 2: F[a2], 3: F[a3], 4: F[a4]} """ # We add some space between the terms @@ -99,13 +100,13 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: latex(Q.an_element()) # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: latex(Q.an_element()) 1+{(q)} F_{\alpha_{1}}+E_{\alpha_{1}}+{(q^{2}-1-q^{-2}+q^{-4})} [ K_{1} ; 2 ]+K_{1}+{(-q^{-1}+q^{-3})} K_{1}[ K_{1} ; 1 ] - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: latex(list(Q.F_simple())) # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: latex(list(Q.F_simple())) \left[F_{\alpha_{1}}, F_{\alpha_{2}}, F_{\alpha_{3}}, F_{\alpha_{4}}\right] """ @@ -135,9 +136,9 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: loads(dumps(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: x = Q.an_element() + sage: loads(dumps(x)) == x True """ data = self._libgap.ExtRepOfObj() @@ -154,9 +155,9 @@ def __hash__(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',3]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: hash(x) == hash(x.gap()) # optional - gap_packages + sage: Q = QuantumGroup(['B',3]) + sage: x = Q.an_element() + sage: hash(x) == hash(x.gap()) True """ return hash(self._libgap) @@ -167,17 +168,17 @@ def _richcmp_(self, other, op): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: F1, F12, F2 = Q.F() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x == F1 # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: x = Q.an_element() + sage: F1, F12, F2 = Q.F() + sage: q = Q.q() + sage: x == F1 False - sage: x != F1 # optional - gap_packages + sage: x != F1 True - sage: F2 * F1 # optional - gap_packages + sage: F2 * F1 (q)*F[a1]*F[a2] + F[a1+a2] - sage: F2 * F1 == q * F1 * F2 + F12 # optional - gap_packages + sage: F2 * F1 == q * F1 * F2 + F12 True """ return richcmp(self._libgap, other._libgap, op) @@ -188,9 +189,9 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',3]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: x.gap() # optional - gap_packages + sage: Q = QuantumGroup(['B',3]) + sage: x = Q.an_element() + sage: x.gap() 1+(q)*F1+E1+(q^4-1-q^-4+q^-8)*[ K1 ; 2 ]+K1+(-q^-2+q^-6)*K1[ K1 ; 1 ] """ return self._libgap @@ -203,9 +204,9 @@ def _add_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 + F2 * F1 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 + F2 * F1 (q^3 + 1)*F[a1]*F[a2] + F[a1+a2] """ return self.__class__(self.parent(), self._libgap + other._libgap) @@ -216,9 +217,9 @@ def _sub_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 - F2 * F1 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 - F2 * F1 (-q^3 + 1)*F[a1]*F[a2] + (-1)*F[a1+a2] """ return self.__class__(self.parent(), self._libgap - other._libgap) @@ -229,17 +230,17 @@ def _acted_upon_(self, scalar, self_on_left=True): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = Q.one().f_tilde([1,2,1,1,2,2]); x # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: q = Q.q() + sage: x = Q.one().f_tilde([1,2,1,1,2,2]); x F[a1+a2]^(3) - sage: 3 * x # optional - gap_packages + sage: 3 * x (3)*F[a1+a2]^(3) - sage: x * (5/3) # optional - gap_packages + sage: x * (5/3) (5/3)*F[a1+a2]^(3) - sage: q^-10 * x # optional - gap_packages + sage: q^-10 * x (q^-10)*F[a1+a2]^(3) - sage: (1 + q^2 - q^-1) * x # optional - gap_packages + sage: (1 + q^2 - q^-1) * x (q^2 + 1-q^-1)*F[a1+a2]^(3) """ try: @@ -261,9 +262,9 @@ def e_tilde(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: x = Q.one().f_tilde([1,2,1,1,2,2]) # optional - gap_packages - sage: x.e_tilde([2,2,1,2]) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: x = Q.one().f_tilde([1,2,1,1,2,2]) + sage: x.e_tilde([2,2,1,2]) F[a1]^(2) """ # Do not override this method, instead implement _et @@ -288,12 +289,12 @@ def f_tilde(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: Q.one().f_tilde(1) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: Q.one().f_tilde(1) F[a1] - sage: Q.one().f_tilde(2) # optional - gap_packages + sage: Q.one().f_tilde(2) F[a2] - sage: Q.one().f_tilde([1,2,1,1,2]) # optional - gap_packages + sage: Q.one().f_tilde([1,2,1,1,2]) F[a1]*F[a1+a2]^(2) """ # Do not override this method, instead implement _ft @@ -321,19 +322,19 @@ class QuantumGroup(UniqueRepresentation, Parent): We verify the Serre relations for type `A_2`:: - sage: Q = algebras.QuantumGroup(['A',2]) # optional - gap_packages - sage: F1,F12,F2 = Q.F() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: F1^2*F2 - q_binomial(2,1,q) * F1*F2*F1 + F2*F1^2 # optional - gap_packages + sage: Q = algebras.QuantumGroup(['A',2]) + sage: F1,F12,F2 = Q.F() + sage: q = Q.q() + sage: F1^2*F2 - q_binomial(2,1,q) * F1*F2*F1 + F2*F1^2 0 We verify the Serre relations for type `B_2`:: - sage: Q = algebras.QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F12, F122, F2 = Q.F() # optional - gap_packages - sage: F1^2*F2 - q_binomial(2,1,q^2) * F1*F2*F1 + F2*F1^2 # optional - gap_packages + sage: Q = algebras.QuantumGroup(['B',2]) + sage: F1, F12, F122, F2 = Q.F() + sage: F1^2*F2 - q_binomial(2,1,q^2) * F1*F2*F1 + F2*F1^2 0 - sage: (F2^3*F1 - q_binomial(3,1,q) * F2^2*F1*F2 # optional - gap_packages + sage: (F2^3*F1 - q_binomial(3,1,q) * F2^2*F1*F2 ....: + q_binomial(3,2,q) * F2*F1*F2^2 - F1*F2^3) 0 @@ -348,8 +349,8 @@ def __classcall_private__(cls, cartan_type, q=None): TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q is QuantumGroup('A2', None) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q is QuantumGroup('A2', None) True """ cartan_type = CartanType(cartan_type) @@ -361,14 +362,14 @@ def __init__(self, cartan_type, q): TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: TestSuite(Q).run() # long time # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: TestSuite(Q).run() # long time - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: TestSuite(Q).run() # long time # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: TestSuite(Q).run() # long time """ self._cartan_type = cartan_type - GapPackage("QuaGroup", spkg="gap_packages").require() + GapPackage("QuaGroup", spkg="gap_package_quagroup").require() libgap.LoadPackage('QuaGroup') R = libgap.eval('RootSystem("%s",%s)' % (cartan_type.type(), cartan_type.rank())) Q = self._cartan_type.root_system().root_lattice() @@ -397,7 +398,7 @@ def _repr_(self): EXAMPLES:: - sage: QuantumGroup(['A',2]) # optional - gap_packages + sage: QuantumGroup(['A',2]) Quantum Group of type ['A', 2] with q=q """ return "Quantum Group of type {} with q={}".format(self._cartan_type, self._q) @@ -408,10 +409,10 @@ def _latex_(self): EXAMPLES:: - sage: latex(QuantumGroup(['A',3])) # optional - gap_packages + sage: latex(QuantumGroup(['A',3])) U_{q}(A_{3}) - sage: zeta3 = CyclotomicField(3).gen() # optional - gap_packages - sage: latex(QuantumGroup(['G',2], q=zeta3)) # optional - gap_packages + sage: zeta3 = CyclotomicField(3).gen() + sage: latex(QuantumGroup(['G',2], q=zeta3)) U_{\zeta_{3}}(G_2) """ from sage.misc.latex import latex @@ -423,8 +424,8 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.gap() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.gap() QuantumUEA( , Qpar = q ) """ return self._libgap @@ -437,8 +438,8 @@ def cartan_type(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.cartan_type() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.cartan_type() ['A', 2] """ return self._cartan_type @@ -449,16 +450,16 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q(0) 0 - sage: Q(4) # optional - gap_packages + sage: Q(4) (4)*1 - sage: Q(4).parent() is Q # optional - gap_packages + sage: Q(4).parent() is Q True - sage: Q(Q.q()).parent() is Q # optional - gap_packages + sage: Q(Q.q()).parent() is Q True - sage: Q(Q.an_element()) == Q.an_element() # optional - gap_packages + sage: Q(Q.an_element()) == Q.an_element() True """ if not elt: @@ -477,8 +478,8 @@ def one(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.one() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.one() 1 """ return self.element_class(self, self._libgap.One()) @@ -490,8 +491,8 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.zero() 0 """ return self.element_class(self, self._libgap.ZeroImmutable()) @@ -503,8 +504,8 @@ def gens(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.gens() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.gens() (F[a1], F[a1+a2], F[a2], K1, (-q + q^-1)*[ K1 ; 1 ] + K1, K2, (-q + q^-1)*[ K2 ; 1 ] + K2, @@ -520,8 +521,8 @@ def E(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: list(Q.E()) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: list(Q.E()) [E[a1], E[a1+a2], E[a1+2*a2], E[a2]] """ N = len(self._pos_roots) + len(self._cartan_type.index_set()) * 2 @@ -534,8 +535,8 @@ def E_simple(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: Q.E_simple() # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: Q.E_simple() Finite family {1: E[a1], 2: E[a2]} """ I = self._cartan_type.index_set() @@ -550,8 +551,8 @@ def F(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: list(Q.F()) # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: list(Q.F()) [F[a1], F[3*a1+a2], F[2*a1+a2], F[3*a1+2*a2], F[a1+a2], F[a2]] """ d = {al: self.gens()[i] for i, al in enumerate(self._pos_roots)} @@ -563,8 +564,8 @@ def F_simple(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: Q.F_simple() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: Q.F_simple() Finite family {1: F[a1], 2: F[a2]} """ I = self._cartan_type.index_set() @@ -578,10 +579,10 @@ def K(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.K() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.K() Finite family {1: K1, 2: K2, 3: K3} - sage: Q.K_inverse() # optional - gap_packages + sage: Q.K_inverse() Finite family {1: (-q + q^-1)*[ K1 ; 1 ] + K1, 2: (-q + q^-1)*[ K2 ; 1 ] + K2, 3: (-q + q^-1)*[ K3 ; 1 ] + K3} @@ -597,8 +598,8 @@ def K_inverse(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.K_inverse() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.K_inverse() Finite family {1: (-q + q^-1)*[ K1 ; 1 ] + K1, 2: (-q + q^-1)*[ K2 ; 1 ] + K2, 3: (-q + q^-1)*[ K3 ; 1 ] + K3} @@ -615,8 +616,8 @@ def algebra_generators(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: list(Q.algebra_generators()) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: list(Q.algebra_generators()) [F[a1], F[a2], K1, K2, (-q + q^-1)*[ K1 ; 1 ] + K1, (-q + q^-1)*[ K2 ; 1 ] + K2, @@ -641,8 +642,8 @@ def _an_element_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.an_element() 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] """ @@ -656,8 +657,8 @@ def some_elements(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: Q.some_elements() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: Q.some_elements() [1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ], K1, F[a1], E[a1]] @@ -671,12 +672,12 @@ def q(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.q() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.q() q - sage: zeta3 = CyclotomicField(3).gen() # optional - gap_packages - sage: Q = QuantumGroup(['B',2], q=zeta3) # optional - gap_packages - sage: Q.q() # optional - gap_packages + sage: zeta3 = CyclotomicField(3).gen() + sage: Q = QuantumGroup(['B',2], q=zeta3) + sage: Q.q() zeta3 """ return self._q @@ -690,12 +691,12 @@ def _Hom_(self, Y, category): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: H = Hom(Q, B); H # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: H = Hom(Q, B); H Set of Morphisms from Quantum Group of type ['A', 2] with q=q to Lower Half of Quantum Group of type ['A', 2] with q=q in Category of rings - sage: type(H) # optional - gap_packages + sage: type(H) """ if category is not None and not category.is_subcategory(Rings()): @@ -710,8 +711,8 @@ def highest_weight_module(self, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.highest_weight_module([1,3]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.highest_weight_module([1,3]) Highest weight module of weight Lambda[1] + 3*Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -723,8 +724,8 @@ def lower_half(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() Lower Half of Quantum Group of type ['A', 2] with q=q """ return LowerHalfQuantumGroup(self) @@ -749,8 +750,8 @@ def coproduct(self, elt, n=1): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: [Q.coproduct(e) for e in Q.E()] # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: [Q.coproduct(e) for e in Q.E()] [1*(E[a1]1) + 1*(K1E[a1]), 1*(E[a1+a2]1) + 1*(K1*K2E[a1+a2]) + q^2-q^-2*(K2*E[a1]E[a2]), q^4-q^2-1 + q^-2*(E[a1]E[a2]^(2)) + 1*(E[a1+2*a2]1) @@ -758,7 +759,7 @@ def coproduct(self, elt, n=1): + q-q^-1*(K2*E[a1+a2]E[a2]) + q^5-2*q^3 + 2*q^-1-q^-3*(K2[ K2 ; 1 ]*E[a1]E[a2]^(2)), 1*(E[a2]1) + 1*(K2E[a2])] - sage: [Q.coproduct(f, 2) for f in Q.F_simple()] # optional - gap_packages + sage: [Q.coproduct(f, 2) for f in Q.F_simple()] [1*(11F[a1]) + -q^2 + q^-2*(1F[a1][ K1 ; 1 ]) + 1*(1F[a1]K1) + q^4-2 + q^-4*(F[a1][ K1 ; 1 ][ K1 ; 1 ]) + -q^2 + q^-2*(F[a1][ K1 ; 1 ]K1) + -q^2 @@ -787,8 +788,8 @@ def antipode(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: [Q.antipode(f) for f in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: [Q.antipode(f) for f in Q.F()] [(-1)*F[a1]*K1, (-q^6 + q^2)*F[a1]*F[a2]*K1*K2 + (-q^4)*F[a1+a2]*K1*K2, (-q^8 + q^6 + q^4-q^2)*F[a1]*F[a2]^(2)*K1 @@ -815,13 +816,13 @@ def counit(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: x = Q.an_element()^2 # optional - gap_packages - sage: Q.counit(x) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: x = Q.an_element()^2 + sage: Q.counit(x) 4 - sage: Q.counit(Q.one()) # optional - gap_packages + sage: Q.counit(Q.one()) 1 - sage: Q.counit(Q.zero()) # optional - gap_packages + sage: Q.counit(Q.zero()) 0 """ # We need to extract the constant coefficient because the @@ -847,14 +848,14 @@ def _mul_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 * F1 * F2 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 * F1 * F2 F[a1]*F[a1+a2]*F[a2] + (q^7 + q^5 + q + q^-1)*F[a1]^(2)*F[a2]^(2) - sage: E1, E2 = Q.E_simple() # optional - gap_packages - sage: F1 * E1 # optional - gap_packages + sage: E1, E2 = Q.E_simple() + sage: F1 * E1 F[a1]*E[a1] - sage: E1 * F1 # optional - gap_packages + sage: E1 * F1 F[a1]*E[a1] + [ K1 ; 1 ] """ return self.__class__(self.parent(), self._libgap * other._libgap) @@ -873,8 +874,8 @@ def bar(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.bar() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.bar() for gen in Q.gens()] [F[a1], (q-q^-1)*F[a1]*F[a2] + F[a1+a2], F[a2], @@ -901,8 +902,8 @@ def omega(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.omega() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.omega() for gen in Q.gens()] [E[a1], (-q)*E[a1+a2], E[a2], @@ -931,8 +932,8 @@ def tau(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.tau() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.tau() for gen in Q.gens()] [F[a1], (-q^2 + 1)*F[a1]*F[a2] + (-q)*F[a1+a2], F[a2], @@ -973,13 +974,13 @@ def braid_group_action(self, braid): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1 = Q.F_simple()[1] # optional - gap_packages - sage: F1.braid_group_action([1]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1 = Q.F_simple()[1] + sage: F1.braid_group_action([1]) (q-q^-1)*[ K1 ; 1 ]*E[a1] + (-1)*K1*E[a1] - sage: F1.braid_group_action([1,2]) # optional - gap_packages + sage: F1.braid_group_action([1,2]) F[a2] - sage: F1.braid_group_action([2,1]) # optional - gap_packages + sage: F1.braid_group_action([2,1]) (-q^3 + 3*q-3*q^-1 + q^-3)*[ K1 ; 1 ]*[ K2 ; 1 ]*E[a1]*E[a2] + (q^3-2*q + q^-1)*[ K1 ; 1 ]*[ K2 ; 1 ]*E[a1+a2] + (q^2-2 + q^-2)*[ K1 ; 1 ]*K2*E[a1]*E[a2] @@ -987,9 +988,9 @@ def braid_group_action(self, braid): + (q^2-2 + q^-2)*K1*[ K2 ; 1 ]*E[a1]*E[a2] + (-q^2 + 1)*K1*[ K2 ; 1 ]*E[a1+a2] + (-q + q^-1)*K1*K2*E[a1]*E[a2] + (q)*K1*K2*E[a1+a2] - sage: F1.braid_group_action([1,2,1]) == F1.braid_group_action([2,1,2]) # optional - gap_packages + sage: F1.braid_group_action([1,2,1]) == F1.braid_group_action([2,1,2]) True - sage: F1.braid_group_action([]) == F1 # optional - gap_packages + sage: F1.braid_group_action([]) == F1 True """ if not braid: @@ -1013,17 +1014,17 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: [(g.e_tilde(1), g.e_tilde(2)) for g in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: [(g.e_tilde(1), g.e_tilde(2)) for g in Q.F()] [(1, 0), (0, F[a1]^(3)), (0, F[a1]^(2)), (0, F[3*a1+a2]), (0, F[a1]), (0, 1)] TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.one()._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.one()._et(1) 0 - sage: Q.zero().e_tilde(1) # optional - gap_packages + sage: Q.zero().e_tilde(1) 0 """ if not self: # self == 0 @@ -1040,21 +1041,21 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: [(g._ft(1), g._ft(2)) for g in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: [(g._ft(1), g._ft(2)) for g in Q.F()] [(F[a1]^(2), F[a1+a2]), (F[a1]*F[3*a1+a2], F[3*a1+2*a2]), (F[a1]*F[2*a1+a2], F[a1+a2]^(2)), (F[a1]*F[3*a1+2*a2], F[a1+a2]^(3)), (F[a1]*F[a1+a2], F[a1+a2]*F[a2]), (F[a1]*F[a2], F[a2]^(2))] - sage: Q.one().f_tilde([1,2,1,1,2,2]) # optional - gap_packages + sage: Q.one().f_tilde([1,2,1,1,2,2]) F[2*a1+a2]*F[a1+a2]*F[a2] TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.zero().f_tilde(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.zero().f_tilde(1) 0 """ if not self: # self == 0 @@ -1078,10 +1079,10 @@ def __init__(self, parent, im_gens, check=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: TestSuite(phi).run(skip="_test_category") # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: TestSuite(phi).run(skip="_test_category") """ self._repr_type_str = "Quantum group homomorphism" Morphism.__init__(self, parent) @@ -1097,10 +1098,10 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: loads(dumps(phi)) == phi # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: loads(dumps(phi)) == phi True """ return (self.parent(), (self._im_gens,)) @@ -1111,18 +1112,18 @@ def _call_(self, val): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: phi(F) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: phi(F) E[a1] - sage: phi(E*F) # optional - gap_packages + sage: phi(E*F) F[a1]*E[a1] - sage: phi(F*E) # optional - gap_packages + sage: phi(F*E) F[a1]*E[a1] + [ K1 ; 1 ] - sage: phi(E*K) # optional - gap_packages + sage: phi(E*K) (-q + q^-1)*F[a1]*[ K1 ; 1 ] + F[a1]*K1 - sage: phi(F*E) == phi(F) * phi(E) # optional - gap_packages + sage: phi(F*E) == phi(F) * phi(E) True """ try: @@ -1136,31 +1137,31 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: psi = Q.hom([F, K, Ki, E]) # optional - gap_packages - sage: phi == Q.hom([E, Ki, K, F]) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: psi = Q.hom([F, K, Ki, E]) + sage: phi == Q.hom([E, Ki, K, F]) True - sage: phi == psi # optional - gap_packages + sage: phi == psi False - sage: psi != Q.hom([F, K, Ki, E]) # optional - gap_packages + sage: psi != Q.hom([F, K, Ki, E]) False - sage: phi != psi # optional - gap_packages + sage: phi != psi True - sage: QB = QuantumGroup(['B',3]) # optional - gap_packages - sage: QC = QuantumGroup(['C',3]) # optional - gap_packages - sage: x = ZZ.one() # optional - gap_packages - sage: phi = QB.hom([x]*len(QB.algebra_generators())) # optional - gap_packages - sage: psi = QC.hom([x]*len(QC.algebra_generators())) # optional - gap_packages - sage: phi.im_gens() == psi.im_gens() # optional - gap_packages + sage: QB = QuantumGroup(['B',3]) + sage: QC = QuantumGroup(['C',3]) + sage: x = ZZ.one() + sage: phi = QB.hom([x]*len(QB.algebra_generators())) + sage: psi = QC.hom([x]*len(QC.algebra_generators())) + sage: phi.im_gens() == psi.im_gens() True - sage: phi == psi # optional - gap_packages + sage: phi == psi False """ if op == op_EQ: - return (type(self) == type(other) + return (type(self) is type(other) and self.domain() is other.domain() and self._im_gens == other._im_gens) if op == op_NE: @@ -1173,10 +1174,10 @@ def im_gens(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: phi.im_gens() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: phi.im_gens() (E[a1], (-q + q^-1)*[ K1 ; 1 ] + K1, K1, F[a1]) """ return self._im_gens @@ -1187,10 +1188,10 @@ def _repr_defn(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: print(phi._repr_defn()) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: print(phi._repr_defn()) F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 @@ -1210,21 +1211,21 @@ def __call__(self, im_gens, check=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: H = Hom(Q, Q) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = H([E, Ki, K, F]); phi # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: H = Hom(Q, Q) + sage: F, K, Ki, E = Q.gens() + sage: phi = H([E, Ki, K, F]); phi Quantum group homomorphism endomorphism of Quantum Group of type ['A', 1] with q=q Defn: F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 E[a1] |--> F[a1] - sage: H(phi) == phi # optional - gap_packages + sage: H(phi) == phi True - sage: H2 = Hom(Q, Q, Modules(Fields())) # optional - gap_packages - sage: H == H2 # optional - gap_packages + sage: H2 = Hom(Q, Q, Modules(Fields())) + sage: H == H2 False - sage: H2(phi) # optional - gap_packages + sage: H2(phi) Quantum group homomorphism endomorphism of Quantum Group of type ['A', 1] with q=q Defn: F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 @@ -1247,8 +1248,8 @@ def projection_lower_half(Q): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import projection_lower_half - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: phi = projection_lower_half(Q); phi # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: phi = projection_lower_half(Q); phi Quantum group homomorphism endomorphism of Quantum Group of type ['G', 2] with q=q Defn: F[a1] |--> F[a1] F[a2] |--> F[a2] @@ -1258,11 +1259,11 @@ def projection_lower_half(Q): (-q^3 + q^-3)*[ K2 ; 1 ] + K2 |--> 0 E[a1] |--> 0 E[a2] |--> 0 - sage: all(phi(f) == f for f in Q.F()) # optional - gap_packages + sage: all(phi(f) == f for f in Q.F()) True - sage: all(phi(e) == Q.zero() for e in Q.E()) # optional - gap_packages + sage: all(phi(e) == Q.zero() for e in Q.E()) True - sage: all(phi(K) == Q.zero() for K in Q.K()) # optional - gap_packages + sage: all(phi(K) == Q.zero() for K in Q.K()) True """ I = Q._cartan_type.index_set() @@ -1282,13 +1283,13 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V = Q.highest_weight_module([2,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: x = (2 - q) * v + F1*v + q*F2*F1*v # optional - gap_packages - sage: loads(dumps(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: V = Q.highest_weight_module([2,1]) + sage: v = V.highest_weight_vector() + sage: x = (2 - q) * v + F1*v + q*F2*F1*v + sage: loads(dumps(x)) == x True """ return (self.parent(), (self.monomial_coefficients(),)) @@ -1299,24 +1300,24 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V = Q.highest_weight_module([2,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: F1 * v # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: V = Q.highest_weight_module([2,1]) + sage: v = V.highest_weight_vector() + sage: F1 * v F[a1]*v0 - sage: F2 * v # optional - gap_packages + sage: F2 * v F[a2]*v0 - sage: F1^2 * v # optional - gap_packages + sage: F1^2 * v (q^2 + q^-2)*F[a1]^(2)*v0 - sage: F2^2 * v # optional - gap_packages + sage: F2^2 * v 0*v0 - sage: (F1 * F2) * v # optional - gap_packages + sage: (F1 * F2) * v F[a1]*F[a2]*v0 - sage: F1 * (F2 * v) # optional - gap_packages + sage: F1 * (F2 * v) F[a1]*F[a2]*v0 - sage: (2 - q) * v + F1*v + q*F2*F1*v # optional - gap_packages + sage: (2 - q) * v + F1*v + q*F2*F1*v (-q + 2)*1*v0 + F[a1]*v0 + (q^3)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 """ try: @@ -1336,12 +1337,12 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: v._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: v._et(1) 0*v0 - sage: V.zero().e_tilde(1) # optional - gap_packages + sage: V.zero().e_tilde(1) 0*v0 """ if not self: # self == 0 @@ -1356,22 +1357,22 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['C',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: v._ft(1) # optional - gap_packages + sage: Q = QuantumGroup(['C',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: v._ft(1) F[a1]*v0 - sage: v._ft(2) # optional - gap_packages + sage: v._ft(2) F[a2]*v0 - sage: v.f_tilde([1,1]) # optional - gap_packages + sage: v.f_tilde([1,1]) 0*v0 - sage: v.f_tilde([2,2]) # optional - gap_packages + sage: v.f_tilde([2,2]) 0*v0 - sage: v.f_tilde([2,1,1]) # optional - gap_packages + sage: v.f_tilde([2,1,1]) (-q^-3)*F[a1]*F[a1+a2]*v0 + (-q^-4)*F[2*a1+a2]*v0 - sage: v.f_tilde([1,2,2]) # optional - gap_packages + sage: v.f_tilde([1,2,2]) F[a1+a2]*F[a2]*v0 - sage: V.zero().f_tilde(1) # optional - gap_packages + sage: V.zero().f_tilde(1) 0*v0 """ if not self: # self == 0 @@ -1387,14 +1388,14 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = v + F1*v + q*F2*F1*v; x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: x = v + F1*v + q*F2*F1*v; x 1*v0 + F[a1]*v0 + (q^2)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 - sage: sorted(x.monomial_coefficients().items(), key=str) # optional - gap_packages + sage: sorted(x.monomial_coefficients().items(), key=str) [(0, 1), (1, 1), (3, q^2), (4, q)] """ R = self.parent()._Q.base_ring() @@ -1408,25 +1409,25 @@ def _vector_(self, R=None, order=None, sparse=False): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: vector(v) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: vector(v) (1, 0, 0, 0, 0, 0, 0, 0) - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = v + F1*v + q*F2*F1*v; x # optional - gap_packages + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: x = v + F1*v + q*F2*F1*v; x 1*v0 + F[a1]*v0 + (q^2)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 - sage: vector(x) # optional - gap_packages + sage: vector(x) (1, 1, 0, q^2, q, 0, 0, 0) - sage: v._vector_(sparse=True) # optional - gap_packages + sage: v._vector_(sparse=True) (1, 0, 0, 0, 0, 0, 0, 0) - sage: x._vector_(sparse=True) # optional - gap_packages + sage: x._vector_(sparse=True) (1, 1, 0, q^2, q, 0, 0, 0) - sage: M = V.submodule([V.an_element()]) # optional - gap_packages - sage: M # optional - gap_packages + sage: M = V.submodule([V.an_element()]) + sage: M Free module generated by {0} over Fraction Field of Univariate Polynomial Ring in q over Rational Field """ V = self.parent()._dense_free_module(R) @@ -1456,10 +1457,10 @@ def __init__(self, V, s): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '') # optional - gap_packages - sage: TestSuite(v).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '') + sage: TestSuite(v).run() """ self.V = V self.s = s @@ -1471,10 +1472,10 @@ def __hash__(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '') # optional - gap_packages - sage: hash(v) == hash('') # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '') + sage: hash(v) == hash('') True """ return hash(self.s) @@ -1486,14 +1487,14 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '') # optional - gap_packages - sage: vp = CrystalGraphVertex(V, '') # optional - gap_packages - sage: v == vp # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '') + sage: vp = CrystalGraphVertex(V, '') + sage: v == vp True - sage: vpp = CrystalGraphVertex(V, '<1*v0>') # optional - gap_packages - sage: v == vpp # optional - gap_packages + sage: vpp = CrystalGraphVertex(V, '<1*v0>') + sage: v == vpp False """ return isinstance(other, CrystalGraphVertex) and self.s == other.s @@ -1505,9 +1506,9 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: CrystalGraphVertex(V, '') # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: CrystalGraphVertex(V, '') """ return self.s @@ -1519,10 +1520,10 @@ def _latex_(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '') # optional - gap_packages - sage: latex(v) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '') + sage: latex(v) \langle F_{\alpha_{1} + \alpha_{2}} v_0 \rangle """ # Essentially same as QuaGroupModuleElement._latex_ @@ -1556,9 +1557,9 @@ def __init__(self, Q, category): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: TestSuite(V).run() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: TestSuite(V).run() """ self._Q = Q self._libgap_q = Q._libgap_q @@ -1573,11 +1574,11 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: latex(S) # optional - gap_packages # random (depends on dot2tex) + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: latex(S) \begin{tikzpicture} ... \end{tikzpicture} @@ -1591,9 +1592,9 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.gap() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.gap() <8-dimensional left-module over QuantumUEA( , Qpar = q )> """ @@ -1607,12 +1608,12 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: q = Q.q() + sage: V(0) 0*v0 - sage: V({1: q^2 - q^-2, 3: 2}) # optional - gap_packages + sage: V({1: q^2 - q^-2, 3: 2}) (q^2-q^-2)*F[a1]*v0 + (2)*F[a1]*F[a2]*v0 """ if not elt: @@ -1628,9 +1629,9 @@ def basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.basis() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.basis() Family (1*v0, F[a1]*v0, F[a2]*v0, F[a1]*F[a2]*v0, F[a1+a2]*v0, F[a1]*F[a1+a2]*v0, F[a1+a2]*F[a2]*v0, F[a1+a2]^(2)*v0) """ @@ -1643,9 +1644,9 @@ def crystal_basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.crystal_basis() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.crystal_basis() Family (1*v0, F[a1]*v0, F[a2]*v0, F[a1]*F[a2]*v0, (q)*F[a1]*F[a2]*v0 + F[a1+a2]*v0, F[a1+a2]*F[a2]*v0, (-q^-2)*F[a1]*F[a1+a2]*v0, (-q^-1)*F[a1+a2]^(2)*v0) @@ -1659,9 +1660,9 @@ def R_matrix(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: V = Q.highest_weight_module([1]) # optional - gap_packages - sage: V.R_matrix() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: V = Q.highest_weight_module([1]) + sage: V.R_matrix() [ 1 0 0 0] [ 0 q -q^2 + 1 0] [ 0 0 q 0] @@ -1680,13 +1681,13 @@ def crystal_graph(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: G = V.crystal_graph(); G # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: G = V.crystal_graph(); G Digraph on 8 vertices - sage: B = crystals.Tableaux(['A',2], shape=[2,1]) # optional - gap_packages - sage: G.is_isomorphic(B.digraph(), edge_labels=True) # optional - gap_packages + sage: B = crystals.Tableaux(['A',2], shape=[2,1]) + sage: G.is_isomorphic(B.digraph(), edge_labels=True) True """ G = self._libgap.CrystalGraph() @@ -1708,9 +1709,9 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.zero() 0*v0 """ return self.element_class(self, self._libgap.ZeroImmutable()) @@ -1727,10 +1728,10 @@ def __classcall_private__(cls, Q, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: La = Q.cartan_type().root_system().weight_lattice().fundamental_weights() # optional - gap_packages - sage: V = Q.highest_weight_module([1,3]) # optional - gap_packages - sage: V is Q.highest_weight_module(La[1]+3*La[2]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: La = Q.cartan_type().root_system().weight_lattice().fundamental_weights() + sage: V = Q.highest_weight_module([1,3]) + sage: V is Q.highest_weight_module(La[1]+3*La[2]) True """ P = Q._cartan_type.root_system().weight_lattice() @@ -1747,9 +1748,9 @@ def __init__(self, Q, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: TestSuite(V).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: TestSuite(V).run() """ self._libgap = Q._libgap.HighestWeightModule(list(weight.to_vector())) self._weight = weight @@ -1762,8 +1763,8 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.highest_weight_module([1,1]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.highest_weight_module([1,1]) Highest weight module of weight Lambda[1] + Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -1775,9 +1776,9 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,2]) # optional - gap_packages - sage: latex(V) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,2]) + sage: latex(V) V(\Lambda_{1} + 2 \Lambda_{2}) """ from sage.misc.latex import latex @@ -1790,9 +1791,9 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.highest_weight_vector() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.highest_weight_vector() 1*v0 """ return self.element_class(self, self._libgap.HighestWeightsAndVectors()[1][0][0]) @@ -1805,10 +1806,10 @@ def tensor(self, *V, **options): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: Vp = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: Vp.tensor(V) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: Vp = Q.highest_weight_module([1,0]) + sage: Vp.tensor(V) Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q # Highest weight module of weight Lambda[1] + Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -1824,10 +1825,10 @@ def __init__(self, *modules, **options): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: TestSuite(T).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: T = tensor([V,V]) + sage: TestSuite(T).run() """ Q = modules[0]._Q self._modules = tuple(modules) @@ -1841,10 +1842,10 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q # Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q """ @@ -1856,10 +1857,10 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: latex(T) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: latex(T) V(\Lambda_{1}) \otimes V(\Lambda_{1}) """ from sage.misc.latex import latex @@ -1876,10 +1877,10 @@ def _highest_weights_and_vectors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([0,1]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T._highest_weights_and_vectors # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([0,1]) + sage: T = tensor([V,V]) + sage: T._highest_weights_and_vectors [ [ [ 0, 2 ], [ 1, 0 ] ], [ [ 1*(1*v01*v0) ], [ -q^-1*(1*v0F3*v0)+1*(F3*v01*v0) ] ] ] """ @@ -1891,10 +1892,10 @@ def highest_weight_vectors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_vectors() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_vectors() [1*(1*v01*v0), -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)] """ return [self.element_class(self, v) @@ -1909,10 +1910,10 @@ def _an_element_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.an_element() 1*(1*v01*v0) """ return self.highest_weight_vectors()[0] @@ -1924,10 +1925,10 @@ def highest_weight_decomposition(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_decomposition() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_decomposition() [Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v01*v0), Highest weight submodule with weight Lambda[2] generated by -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)] """ @@ -1941,10 +1942,10 @@ def tensor_factors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.tensor_factors() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.tensor_factors() (Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q, Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q) """ @@ -1960,11 +1961,11 @@ def __init__(self, ambient, gen, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: TestSuite(S).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: TestSuite(S).run() """ self._ambient = ambient # We do not use the generic ambient category since submodules of tensor @@ -1989,10 +1990,10 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_decomposition() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_decomposition() [Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v01*v0), Highest weight submodule with weight Lambda[2] @@ -2007,11 +2008,11 @@ def _ambient_basis_map(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S._ambient_basis_map # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S._ambient_basis_map {0: 1*(1*v01*v0), 1: 1*(1*v0F[a1]*v0) + q^-1*(F[a1]*v01*v0), 2: 1*(F[a1]*v0F[a1]*v0), @@ -2038,11 +2039,11 @@ def ambient(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S.ambient() is T # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S.ambient() is T True """ return self._ambient @@ -2054,16 +2055,16 @@ def lift(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S.lift # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S.lift Generic morphism: From: Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v01*v0) To: Highest weight module ... # Highest weight module ... - sage: x = sum(S.basis()) # optional - gap_packages - sage: x.lift() # optional - gap_packages + sage: x = sum(S.basis()) + sage: x.lift() 1*(1*v01*v0) + 1*(1*v0F[a1]*v0) + 1*(1*v0F[a1+a2]*v0) + q^-1*(F[a1]*v01*v0) + 1*(F[a1]*v0F[a1]*v0) + 1*(F[a1]*v0F[a1+a2]*v0) + q^-1*(F[a1+a2]*v01*v0) @@ -2078,10 +2079,10 @@ def retract(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: all(S.retract(S.lift(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: all(S.retract(S.lift(x)) == x ....: for S in T.highest_weight_decomposition() ....: for x in S.basis()) True @@ -2095,13 +2096,13 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[1] # optional - gap_packages - sage: u = S.highest_weight_vector(); u # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[1] + sage: u = S.highest_weight_vector(); u (1)*e.1 - sage: u.lift() # optional - gap_packages + sage: u.lift() -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0) """ I = self._cartan_type.index_set() @@ -2124,16 +2125,16 @@ def crystal_graph(self, use_ambient=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[1] # optional - gap_packages - sage: G = S.crystal_graph() # optional - gap_packages - sage: sorted(G.vertices(sort=False), key=str) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[1] + sage: G = S.crystal_graph() + sage: sorted(G.vertices(sort=False), key=str) [<-q^-1*(1*v0F[a1+a2]*v0) + 1*(F[a1+a2]*v01*v0)>, <-q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)>, <-q^-1*(F[a1]*v0F[a1+a2]*v0) + 1*(F[a1+a2]*v0F[a1]*v0)>] - sage: sorted(S.crystal_graph(False).vertices(sort=False), key=str) # optional - gap_packages + sage: sorted(S.crystal_graph(False).vertices(sort=False), key=str) [<(1)*e.1>, <(1)*e.2>, <(1)*e.3>] """ G = self._libgap.CrystalGraph() @@ -2171,8 +2172,8 @@ def __classcall_private__(cls, Q): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import LowerHalfQuantumGroup - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() is LowerHalfQuantumGroup(Q) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() is LowerHalfQuantumGroup(Q) True """ from sage.combinat.root_system.cartan_type import CartanType_abstract @@ -2186,9 +2187,9 @@ def __init__(self, Q): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: TestSuite(B).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: TestSuite(B).run() """ self._Q = Q self._libgap = Q._libgap @@ -2206,8 +2207,8 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() Lower Half of Quantum Group of type ['A', 2] with q=q """ return "Lower Half of {}".format(self._Q) @@ -2218,8 +2219,8 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: latex(Q.lower_half()) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: latex(Q.lower_half()) U^-_{q}(A_{2}) """ from sage.misc.latex import latex @@ -2231,14 +2232,14 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: q = Q.q() + sage: B(0) 0 - sage: B(1 + q^2) # optional - gap_packages + sage: B(1 + q^2) (q^2 + 1)*1 - sage: B({(1,2,0): q, (0,0,2): q^2 - 2}) # optional - gap_packages + sage: B({(1,2,0): q, (0,0,2): q^2 - 2}) (q)*F[a1]*F[a1+a2]^(2) + (q^2-2)*F[a2]^(2) """ if not elt: @@ -2257,9 +2258,9 @@ def ambient(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.ambient() is Q # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.ambient() is Q True """ return self._Q @@ -2271,9 +2272,9 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.highest_weight_vector() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.highest_weight_vector() 1 """ return self.element_class(self, self._Q.one()._libgap) @@ -2288,9 +2289,9 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.zero() 0 """ return self.element_class(self, self._Q._libgap.ZeroImmutable()) @@ -2302,9 +2303,9 @@ def algebra_generators(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.algebra_generators() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.algebra_generators() Finite family {1: F[a1], 2: F[a2]} """ F = self._Q.F_simple() @@ -2320,11 +2321,11 @@ def _construct_monomial(self, k): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B._construct_monomial((1,2,1)) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B._construct_monomial((1,2,1)) F[a1]*F[a1+a2]^(2)*F[a2] - sage: B._construct_monomial((3,0,1)) # optional - gap_packages + sage: B._construct_monomial((3,0,1)) F[a1]^(3)*F[a2] """ F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) @@ -2348,16 +2349,16 @@ def basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: basis = B.basis(); basis # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: basis = B.basis(); basis Lazy family (monomial(i))_{i in The Cartesian product of (Non negative integers, Non negative integers, Non negative integers)} - sage: basis[1,2,1] # optional - gap_packages + sage: basis[1,2,1] F[a1]*F[a1+a2]^(2)*F[a2] - sage: basis[1,2,4] # optional - gap_packages + sage: basis[1,2,4] F[a1]*F[a1+a2]^(2)*F[a2]^(4) - sage: basis[1,0,4] # optional - gap_packages + sage: basis[1,0,4] F[a1]*F[a2]^(4) """ I = cartesian_product([NonNegativeIntegers()]*len(self._pos_roots)) @@ -2369,9 +2370,9 @@ def _construct_canonical_basis_elts(self, k): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B._construct_canonical_basis_elts((1,2)) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B._construct_canonical_basis_elts((1,2)) [F[a1]*F[a2]^(2), (q^2)*F[a1]*F[a2]^(2) + F[a1+a2]*F[a2]] """ B = self._libgap.CanonicalBasis() @@ -2384,14 +2385,14 @@ def canonical_basis_elements(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: C = B.canonical_basis_elements(); C # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: C = B.canonical_basis_elements(); C Lazy family (Canonical basis(i))_{i in The Cartesian product of (Non negative integers, Non negative integers)} - sage: C[2,1] # optional - gap_packages + sage: C[2,1] [F[a1]^(2)*F[a2], F[a1]*F[a1+a2] + (q^2)*F[a1]^(2)*F[a2]] - sage: C[1,2] # optional - gap_packages + sage: C[1,2] [F[a1]*F[a2]^(2), (q^2)*F[a1]*F[a2]^(2) + F[a1+a2]*F[a2]] """ I = cartesian_product([NonNegativeIntegers()]*len(self._cartan_type.index_set())) @@ -2403,11 +2404,11 @@ def lift(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B.lift(B.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = B.lift(B.an_element()); x 1 - sage: x.parent() is Q # optional - gap_packages + sage: x.parent() is Q True """ return self._Q.element_class(self._Q, elt._libgap) @@ -2418,12 +2419,12 @@ def retract(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = Q.an_element(); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = Q.an_element(); x 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] - sage: B.retract(x) # optional - gap_packages + sage: B.retract(x) 1 + (q)*F[a1] """ return self.element_class(self, self._proj(elt)._libgap) @@ -2438,20 +2439,20 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: v = B.highest_weight_vector(); v # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: F1, F2 = Q.F_simple() + sage: v = B.highest_weight_vector(); v 1 - sage: 2 * v # optional - gap_packages + sage: 2 * v (2)*1 - sage: v * (3/2) # optional - gap_packages + sage: v * (3/2) (3/2)*1 - sage: F1 * v # optional - gap_packages + sage: F1 * v F[a1] - sage: F2 * (F1 * v) # optional - gap_packages + sage: F2 * (F1 * v) (q)*F[a1]*F[a2] + F[a1+a2] - sage: (F1 * v) * F2 # optional - gap_packages + sage: (F1 * v) * F2 F[a1]*F[a2] """ try: @@ -2473,16 +2474,16 @@ def _mul_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: v = B.highest_weight_vector() # optional - gap_packages - sage: f1, f2 = F1 * v, F2 * v # optional - gap_packages - sage: f1 * f2 # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: F1, F2 = Q.F_simple() + sage: v = B.highest_weight_vector() + sage: f1, f2 = F1 * v, F2 * v + sage: f1 * f2 F[a1]*F[a2] - sage: f1^2 * f2 # optional - gap_packages + sage: f1^2 * f2 (q + q^-1)*F[a1]^(2)*F[a2] - sage: f2 * f1^2 * f2 # optional - gap_packages + sage: f2 * f1^2 * f2 (q + q^-1)*F[a1]*F[a1+a2]*F[a2] + (q^4 + 2*q^2 + 1)*F[a1]^(2)*F[a2]^(2) """ @@ -2496,11 +2497,11 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B.retract(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = B.retract(Q.an_element()); x 1 + (q)*F[a1] - sage: sorted(x.monomial_coefficients().items(), key=str) # optional - gap_packages + sage: sorted(x.monomial_coefficients().items(), key=str) [((0, 0, 0), 1), ((1, 0, 0), q)] """ ext_rep = self._libgap.ExtRepOfObj() @@ -2521,27 +2522,27 @@ def bar(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1, F2 = Q.F_simple() + sage: B = Q.lower_half() + sage: x = B(Q.an_element()); x 1 + (q)*F[a1] - sage: x.bar() # optional - gap_packages + sage: x.bar() 1 + (q^-1)*F[a1] - sage: (F1*x).bar() == F1 * x.bar() # optional - gap_packages + sage: (F1*x).bar() == F1 * x.bar() True - sage: (F2*x).bar() == F2 * x.bar() # optional - gap_packages + sage: (F2*x).bar() == F2 * x.bar() True - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(q^-2*F1*F2^2*F1) # optional - gap_packages - sage: x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: B = Q.lower_half() + sage: x = B(q^-2*F1*F2^2*F1) + sage: x (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) - sage: x.bar() # optional - gap_packages + sage: x.bar() (q^5 + q^-1)*F[a1]*F[a1+a2]*F[a2] + (q^12 + q^10 + q^6 + q^4)*F[a1]^(2)*F[a2]^(2) """ @@ -2555,27 +2556,27 @@ def tau(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1, F2 = Q.F_simple() + sage: B = Q.lower_half() + sage: x = B(Q.an_element()); x 1 + (q)*F[a1] - sage: x.tau() # optional - gap_packages + sage: x.tau() 1 + (q)*F[a1] - sage: (F1*x).tau() == x.tau() * F1.tau() # optional - gap_packages + sage: (F1*x).tau() == x.tau() * F1.tau() True - sage: (F2*x).tau() == x.tau() * F2.tau() # optional - gap_packages + sage: (F2*x).tau() == x.tau() * F2.tau() True - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(q^-2*F1*F2^2*F1) # optional - gap_packages - sage: x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: B = Q.lower_half() + sage: x = B(q^-2*F1*F2^2*F1) + sage: x (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) - sage: x.tau() # optional - gap_packages + sage: x.tau() (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) """ @@ -2594,13 +2595,13 @@ def braid_group_action(self, braid): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector().f_tilde([1,2,2,1]); v # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector().f_tilde([1,2,2,1]); v F[a1]*F[a1+a2]*F[a2] - sage: v.braid_group_action([1]) # optional - gap_packages + sage: v.braid_group_action([1]) (-q^3-q)*F[a2]^(2) - sage: v.braid_group_action([]) == v # optional - gap_packages + sage: v.braid_group_action([]) == v True """ if not braid: @@ -2625,18 +2626,18 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector() # optional - gap_packages - sage: v._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector() + sage: v._et(1) 0 - sage: w = v.f_tilde([1,2,1]); w # optional - gap_packages + sage: w = v.f_tilde([1,2,1]); w F[a1]*F[a1+a2] - sage: w._et(1) # optional - gap_packages + sage: w._et(1) F[a1+a2] - sage: w._et(2) # optional - gap_packages + sage: w._et(2) F[a1]^(2) - sage: L.zero().e_tilde(1) # optional - gap_packages + sage: L.zero().e_tilde(1) 0 """ if not self: # self == 0 @@ -2653,12 +2654,12 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector() # optional - gap_packages - sage: v._ft(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector() + sage: v._ft(1) F[a1] - sage: L.zero().f_tilde(1) # optional - gap_packages + sage: L.zero().f_tilde(1) 0 """ if not self: # self == 0 @@ -2676,9 +2677,9 @@ def _unpickle_generic_element(parent, data): EXAMPLES:: - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: loads(dumps(x)) == x # indirect doctest # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: x = Q.an_element() + sage: loads(dumps(x)) == x # indirect doctest True """ F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(parent._libgap)) diff --git a/src/sage/arith/constants.pxd b/src/sage/arith/constants.pxd index 6e5e713707f..371960ec3bc 100644 --- a/src/sage/arith/constants.pxd +++ b/src/sage/arith/constants.pxd @@ -13,14 +13,14 @@ # cdef extern from *: - double M_PI "0x3.243f6a8885a3p+0" # π - double M_EULER "0x9.3c467e37db0c8p-4" # γ - double M_LN2 "0xb.17217f7d1cf78p-4" # log(2) - double M_LN10 "0x2.4d763776aaa2cp+0" # log(10) - double M_LNPI "0x1.250d048e7a1bdp+0" # log(π) - double M_1_LN2 "0x1.71547652b82fep+0" # 1/log(2) - double M_1_LN10 "0x6.f2dec549b9438p-4" # 1/log(10) - double M_1_LNPI "0xd.fa22fdd8cfd98p-4" # 1/log(π) - double M_LN2_LN10 "0x4.d104d427de7fcp-4" # log(2)/log(10) + double M_PI "0x3.243f6a8885a3p+0" # π + double M_EULER "0x9.3c467e37db0c8p-4" # γ + double M_LN2 "0xb.17217f7d1cf78p-4" # log(2) + double M_LN10 "0x2.4d763776aaa2cp+0" # log(10) + double M_LNPI "0x1.250d048e7a1bdp+0" # log(π) + double M_1_LN2 "0x1.71547652b82fep+0" # 1/log(2) + double M_1_LN10 "0x6.f2dec549b9438p-4" # 1/log(10) + double M_1_LNPI "0xd.fa22fdd8cfd98p-4" # 1/log(π) + double M_LN2_LN10 "0x4.d104d427de7fcp-4" # log(2)/log(10) double LOG_TEN_TWO_PLUS_EPSILON "0x3.5269e12f346e4p+0" # log(10,2) rounded up diff --git a/src/sage/arith/multi_modular.pyx b/src/sage/arith/multi_modular.pyx index 50b79b016c1..83f9df2a7c7 100644 --- a/src/sage/arith/multi_modular.pyx +++ b/src/sage/arith/multi_modular.pyx @@ -391,7 +391,7 @@ cdef class MultiModularBasis_base(): new_partial_products.append(M) mpz_clear(height) return self.extend_with_primes(new_moduli, new_partial_products, - check=False) + check=False) def _extend_moduli_to_count(self, int count): r""" @@ -470,7 +470,7 @@ cdef class MultiModularBasis_base(): Compute and store `\prod_j=1^{i-1} m_j^{-1} (mod m_i)` for i >= start. """ if start == 0: - start = 1 # first one is trivial, never used + start = 1 # first one is trivial, never used self.C[0] = 1 for i in range(start, self.n): self.C[i] = ai.c_inverse_mod_longlong(mpz_fdiv_ui(self.partial_products[i-1], self.moduli[i]), self.moduli[i]) @@ -483,7 +483,7 @@ cdef class MultiModularBasis_base(): self._extend_moduli_to_height_c(height) cdef int count - count = self.n * mpz_sizeinbase(height, 2) / mpz_sizeinbase(self.partial_products[self.n-1], 2) # an estimate + count = self.n * mpz_sizeinbase(height, 2) / mpz_sizeinbase(self.partial_products[self.n-1], 2) # an estimate count = max(min(count, self.n), 1) while count > 1 and mpz_cmp(height, self.partial_products[count-1]) < 0: count -= 1 @@ -568,7 +568,7 @@ cdef class MultiModularBasis_base(): s = 1 mpz_init_set_si(z, b[0]) if b[0] == 0: - while s < len and b[s] == 0: # fast forward to first non-zero + while s < len and b[s] == 0: # fast forward to first non-zero s += 1 else: s = 0 @@ -619,10 +619,10 @@ cdef class MultiModularBasis_base(): if offset == 0: mpz_set_si(z[j], b[0][j]) if b[0][j] == 0: - while i < len and b[i][j] == 0: # fast forward to first non-zero + while i < len and b[i][j] == 0: # fast forward to first non-zero i += 1 while i < len: - mpz_set_si(u, ((b[i][j] + m[i] - mpz_fdiv_ui(z[j], m[i])) * self.C[i]) % m[i]) # u = ((b_i - z) * C_i) % m_i + mpz_set_si(u, ((b[i][j] + m[i] - mpz_fdiv_ui(z[j], m[i])) * self.C[i]) % m[i]) # u = ((b_i - z) * C_i) % m_i mpz_mul(u, u, self.partial_products[i-1]) mpz_add(z[j], z[j], u) i += 1 @@ -831,7 +831,7 @@ cdef class MultiModularBasis_base(): """ if isinstance(ix, slice): return self.__class__(self.list()[ix], l_bound = self._l_bound, - u_bound = self._u_bound) + u_bound = self._u_bound) cdef Py_ssize_t i = ix if i != ix: @@ -850,7 +850,7 @@ cdef class MultiModularBasis_base(): sage: MultiModularBasis_base([10007]) MultiModularBasis with moduli [10007] """ - return "MultiModularBasis with moduli "+str(self.list()) + return "MultiModularBasis with moduli " + str(self.list()) cdef class MultiModularBasis(MultiModularBasis_base): diff --git a/src/sage/arith/numerical_approx.pyx b/src/sage/arith/numerical_approx.pyx index 005b88621c4..37a78833e61 100644 --- a/src/sage/arith/numerical_approx.pyx +++ b/src/sage/arith/numerical_approx.pyx @@ -2,15 +2,15 @@ r""" Generic numerical approximation function """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent cimport Parent from sage.structure.element cimport parent diff --git a/src/sage/arith/power.pyx b/src/sage/arith/power.pyx index 2900d9f2a45..acd5f885e85 100644 --- a/src/sage/arith/power.pyx +++ b/src/sage/arith/power.pyx @@ -5,15 +5,15 @@ This implements powering of arbitrary objects using a square-and-multiply algorithm. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_check diff --git a/src/sage/arith/rational_reconstruction.pyx b/src/sage/arith/rational_reconstruction.pyx index 6d2a4886bb3..8342f672cc2 100644 --- a/src/sage/arith/rational_reconstruction.pyx +++ b/src/sage/arith/rational_reconstruction.pyx @@ -11,7 +11,7 @@ AUTHORS: - Jeroen Demeyer (2014-10-20): move this function from ``gmp.pxi``, simplify and fix some bugs, see :trac:`17180` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 ??? # Copyright (C) 2014 Jeroen Demeyer # @@ -19,8 +19,8 @@ AUTHORS: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 6ffe90f7dda..34abf305f70 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -80,23 +80,23 @@ :: - sage: f(x,y)=x^2*y+y^2+y - sage: f.diff() # gradient + sage: f(x,y) = x^2*y + y^2 + y + sage: f.diff() # gradient (x, y) |--> (2*x*y, x^2 + 2*y + 1) - sage: solve(list(f.diff()),[x,y]) + sage: solve(list(f.diff()), [x,y]) [[x == -I, y == 0], [x == I, y == 0], [x == 0, y == (-1/2)]] sage: H=f.diff(2); H # Hessian matrix [(x, y) |--> 2*y (x, y) |--> 2*x] [(x, y) |--> 2*x (x, y) |--> 2] - sage: H(x=0,y=-1/2) + sage: H(x=0, y=-1/2) [-1 0] [ 0 2] - sage: H(x=0,y=-1/2).eigenvalues() + sage: H(x=0, y=-1/2).eigenvalues() [-1, 2] Here we calculate the Jacobian for the polar coordinate transformation:: - sage: T(r,theta)=[r*cos(theta),r*sin(theta)] + sage: T(r,theta) = [r*cos(theta),r*sin(theta)] sage: T (r, theta) |--> (r*cos(theta), r*sin(theta)) sage: T.diff() # Jacobian matrix @@ -117,7 +117,7 @@ ValueError: No differentiation variable specified. Simplifying symbolic sums is also possible, using the -sum command, which also uses Maxima in the background:: +:func:`sum` command, which also uses Maxima in the background:: sage: k, m = var('k, m') sage: sum(1/k^4, k, 1, oo) @@ -182,19 +182,19 @@ sage: f(x=pi) 0 -We can also make a ``CallableSymbolicExpression``, -which is a ``SymbolicExpression`` that is a function of +We can also make a :class:`CallableSymbolicExpression`, +which is a :class:`SymbolicExpression` that is a function of specified variables in a fixed order. Each -``SymbolicExpression`` has a +:class:`SymbolicExpression` has a ``function(...)`` method that is used to create a -``CallableSymbolicExpression``, as illustrated below:: +:class:`CallableSymbolicExpression`, as illustrated below:: sage: u = log((2-x)/(y+5)) sage: f = u.function(x, y); f (x, y) |--> log(-(x - 2)/(y + 5)) There is an easier way of creating a -``CallableSymbolicExpression``, which relies on the +:class:`CallableSymbolicExpression`, which relies on the Sage preparser. :: @@ -267,7 +267,8 @@ sage: CC(f) 1.12762596520638 + 1.17520119364380*I sage: ComplexField(200)(f) - 1.1276259652063807852262251614026720125478471180986674836290 + 1.1752011936438014568823818505956008151557179813340958702296*I + 1.1276259652063807852262251614026720125478471180986674836290 + + 1.1752011936438014568823818505956008151557179813340958702296*I sage: ComplexField(100)(f) 1.1276259652063807852262251614 + 1.1752011936438014568823818506*I @@ -286,8 +287,9 @@ We can, of course, substitute:: - sage: f(n9=9,n7=n6) - 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + 387420490/387420489 + sage: f(n9=9, n7=n6) + 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + + 387420490/387420489 TESTS: @@ -317,7 +319,7 @@ sage: maxima.eval('expand((x+y)^3)') '27' -If the copy of maxima used by the symbolic calculus package were +If the copy of Maxima used by the symbolic calculus package were the same as the default one, then the following would return 27, which would be very confusing indeed! @@ -446,27 +448,27 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the sum + - ``a`` -- lower endpoint of the sum - - ``b`` - upper endpoint of the sum + - ``b`` -- upper endpoint of the sum - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'maple'`` - (optional) use Maple + - ``'maple'`` -- (optional) use Maple - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``'giac'`` - (optional) use Giac + - ``'giac'`` -- (optional) use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` -- (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -493,13 +495,13 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): And some truncations thereof:: sage: assume(n>1) - sage: symbolic_sum(binomial(n,k),k,1,n) + sage: symbolic_sum(binomial(n,k), k, 1, n) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,2,n) + sage: symbolic_sum(binomial(n,k), k, 2, n) 2^n - n - 1 - sage: symbolic_sum(binomial(n,k),k,0,n-1) + sage: symbolic_sum(binomial(n,k), k, 0, n-1) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,1,n-1) + sage: symbolic_sum(binomial(n,k), k, 1, n-1) 2^n - 2 The binomial theorem:: @@ -556,22 +558,22 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): ... ValueError: Sum is divergent. sage: forget() - sage: assumptions() # check the assumptions were really forgotten + sage: assumptions() # check the assumptions were really forgotten [] A summation performed by Mathematica:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'mathematica') # optional - mathematica + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='mathematica') # optional - mathematica pi*coth(pi) An example of this summation with Giac:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'giac') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='giac') (pi*e^(2*pi) - pi*e^(-2*pi))/(e^(2*pi) + e^(-2*pi) - 2) The same summation is solved by SymPy:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'sympy') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='sympy') pi/tanh(pi) SymPy and Maxima 5.39.0 can do the following (see @@ -584,7 +586,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): Use Maple as a backend for summation:: - sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm = 'maple') # optional - maple + sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm='maple') # optional - maple (x + 1)^n If you don't want to evaluate immediately give the ``hold`` keyword:: @@ -686,17 +688,17 @@ def nintegral(ex, x, a, b, INPUT: - - ``x`` - variable to integrate with respect to + - ``x`` -- variable to integrate with respect to - - ``a`` - lower endpoint of integration + - ``a`` -- lower endpoint of integration - - ``b`` - upper endpoint of integration + - ``b`` -- upper endpoint of integration - - ``desired_relative_error`` - (default: '1e-8') the + - ``desired_relative_error`` -- (default: ``1e-8``) the desired relative error - - ``maximum_num_subintervals`` - (default: 200) - maxima number of subintervals + - ``maximum_num_subintervals`` -- (default: 200) + maximal number of subintervals OUTPUT: @@ -709,26 +711,26 @@ def nintegral(ex, x, a, b, - an error code: - - ``0`` - no problems were encountered + - ``0`` -- no problems were encountered - - ``1`` - too many subintervals were done + - ``1`` -- too many subintervals were done - - ``2`` - excessive roundoff error + - ``2`` -- excessive roundoff error - - ``3`` - extremely bad integrand behavior + - ``3`` -- extremely bad integrand behavior - - ``4`` - failed to converge + - ``4`` -- failed to converge - - ``5`` - integral is probably divergent or slowly + - ``5`` -- integral is probably divergent or slowly convergent - - ``6`` - the input is invalid; this includes the case of - desired_relative_error being too small to be achieved + - ``6`` -- the input is invalid; this includes the case of + ``desired_relative_error`` being too small to be achieved - ALIAS: nintegrate is the same as nintegral + ALIAS: :func:`nintegrate` is the same as :func:`nintegral` REMARK: There is also a function - ``numerical_integral`` that implements numerical + :func:`numerical_integral` that implements numerical integration using the GSL C library. It is potentially much faster and applies to arbitrary user defined functions. @@ -741,7 +743,7 @@ def nintegral(ex, x, a, b, :: sage: f = x - sage: f.nintegral(x,0,1,1e-14) + sage: f.nintegral(x, 0, 1, 1e-14) (0.0, 0.0, 0, 6) EXAMPLES:: @@ -750,7 +752,7 @@ def nintegral(ex, x, a, b, sage: f.nintegral(x, 0, 1) (0.5284822353142306, 4.163...e-11, 231, 0) - We can also use the ``numerical_integral`` function, + We can also use the :func:`numerical_integral` function, which calls the GSL C library. :: @@ -785,7 +787,7 @@ def nintegral(ex, x, a, b, sage: f.nintegrate(x,0,1) (-480.000000000000..., 5.32907051820075...e-12, 21, 0) - It is just because every floating point evaluation of return -480.0 + It is just because every floating point evaluation of `f` returns `-480.0` in floating point. Important note: using PARI/GP one can compute numerical integrals @@ -831,25 +833,25 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the product + - ``a`` -- lower endpoint of the product - - ``b`` - upper endpoint of the prduct + - ``b`` -- upper endpoint of the prduct - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` - (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -935,50 +937,50 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): r""" - Return the minimal polynomial of self, if possible. + Return the minimal polynomial of ``self``, if possible. INPUT: - - ``var`` - polynomial variable name (default 'x') + - ``var`` -- polynomial variable name (default 'x') - - ``algorithm`` - 'algebraic' or 'numerical' (default + - ``algorithm`` -- ``'algebraic'`` or ``'numerical'`` (default both, but with numerical first) - - ``bits`` - the number of bits to use in numerical + - ``bits`` -- the number of bits to use in numerical approx - - ``degree`` - the expected algebraic degree + - ``degree`` -- the expected algebraic degree - - ``epsilon`` - return without error as long as + - ``epsilon`` -- return without error as long as f(self) epsilon, in the case that the result cannot be proven. - All of the above parameters are optional, with epsilon=0, bits and - degree tested up to 1000 and 24 by default respectively. The + All of the above parameters are optional, with epsilon=0, ``bits`` and + ``degree`` tested up to 1000 and 24 by default respectively. The numerical algorithm will be faster if bits and/or degree are given explicitly. The algebraic algorithm ignores the last three parameters. - OUTPUT: The minimal polynomial of self. If the numerical algorithm - is used then it is proved symbolically when epsilon=0 (default). + OUTPUT: The minimal polynomial of ``self``. If the numerical algorithm + is used, then it is proved symbolically when ``epsilon=0`` (default). If the minimal polynomial could not be found, two distinct kinds of errors are raised. If no reasonable candidate was found with the - given bit/degree parameters, a ``ValueError`` will be + given ``bits``/``degree`` parameters, a :class:`ValueError` will be raised. If a reasonable candidate was found but (perhaps due to limits in the underlying symbolic package) was unable to be proved - correct, a ``NotImplementedError`` will be raised. + correct, a :class:`NotImplementedError` will be raised. ALGORITHM: Two distinct algorithms are used, depending on the algorithm parameter. By default, the numerical algorithm is attempted first, then the algebraic one. - Algebraic: Attempt to evaluate this expression in QQbar, using + Algebraic: Attempt to evaluate this expression in ``QQbar``, using cyclotomic fields to resolve exponential and trig functions at - rational multiples of pi, field extensions to handle roots and + rational multiples of `\pi`, field extensions to handle roots and rational exponents, and computing compositums to represent the full expression as an element of a number field where the minimal - polynomial can be computed exactly. The bits, degree, and epsilon + polynomial can be computed exactly. The ``bits``, ``degree``, and ``epsilon`` parameters are ignored. Numerical: Computes a numerical approximation of @@ -989,8 +991,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): vanishing. If this fails, and ``epsilon`` is non-zero, return `f` if and only if `f(\mathtt{self}) < \mathtt{epsilon}`. - Otherwise raise a ``ValueError`` (if no suitable - candidate was found) or a ``NotImplementedError`` (if a + Otherwise raise a :class:`ValueError` (if no suitable + candidate was found) or a :class:`NotImplementedError` (if a likely candidate was found but could not be proved correct). EXAMPLES: First some simple examples:: @@ -1014,7 +1016,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: sin(pi/7).minpoly() x^6 - 7/4*x^4 + 7/8*x^2 - 7/64 sage: minpoly(exp(I*pi/17)) - x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 + x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 + - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 Here we verify it gives the same result as the abstract number field. @@ -1027,14 +1030,15 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: (a+b+a*b).absolute_minpoly() x^4 - 22*x^2 - 48*x - 23 - The minpoly function is used implicitly when creating + The :func:`minpoly` function is used implicitly when creating number fields:: sage: x = var('x') sage: eqn = x^3 + sqrt(2)*x + 5 == 0 sage: a = solve(eqn, x)[0].rhs() sage: QQ[a] - Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 with a = 0.7185272465828846? - 1.721353471724806?*I + Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 + with a = 0.7185272465828846? - 1.721353471724806?*I Here we solve a cubic and then recover it from its complicated radical expansion. @@ -1043,7 +1047,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = x^3 - x + 1 sage: a = f.solve(x)[0].rhs(); a - -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) + -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) + - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) sage: a.minpoly() x^3 - x + 1 @@ -1056,7 +1061,9 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = a.minpoly(); f x^8 - 40*x^6 + 352*x^4 - 960*x^2 + 576 sage: f(a) - (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + 576 + (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + + 576 sage: f(a).expand() 0 @@ -1083,9 +1090,11 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): :: sage: cos(pi/33).minpoly(algorithm='algebraic') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 sage: cos(pi/33).minpoly(algorithm='numerical') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 Sometimes it fails, as it must given that some numbers aren't algebraic:: @@ -1162,12 +1171,12 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): INPUT: - - ``dir`` - (default: None); dir may have the value - 'plus' (or '+' or 'right' or 'above') for a limit from above, - 'minus' (or '-' or 'left' or 'below') for a limit from below, or may be omitted + - ``dir`` -- (default: ``None``); may have the value + ``'plus'`` (or ``'+'`` or ``'right'`` or ``'above'``) for a limit from above, + ``'minus'`` (or ``'-'`` or ``'left'`` or ``'below'``) for a limit from below, or may be omitted (implying a two-sided limit is to be computed). - - ``taylor`` - (default: False); if True, use Taylor + - ``taylor`` -- (default: ``False``); if ``True``, use Taylor series, which allows more limits to be computed (but may also crash in some obscure cases due to bugs in Maxima). @@ -1175,8 +1184,8 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): .. note:: - The output may also use 'und' (undefined), 'ind' - (indefinite but bounded), and 'infinity' (complex + The output may also use ``und`` (undefined), ``ind`` + (indefinite but bounded), and ``infinity`` (complex infinity). EXAMPLES:: @@ -1488,7 +1497,7 @@ def mma_free_limit(expression, v, a, dir=None): - ``expression`` -- symbolic expression - ``v`` -- variable - ``a`` -- value where the variable goes to - - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default:``None``) + - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default: ``None``) EXAMPLES:: @@ -1547,19 +1556,19 @@ def laplace(ex, t, s, algorithm='maxima'): INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``t`` - independent variable + - ``t`` -- independent variable - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. NOTE:: @@ -1622,7 +1631,7 @@ def laplace(ex, t, s, algorithm='maxima'): Next we form the augmented matrix of the above system:: - sage: A = matrix([[s, 16, 270],[1, s, 90+1/s]]) + sage: A = matrix([[s, 16, 270], [1, s, 90+1/s]]) sage: E = A.echelon_form() sage: xt = E[0,2].inverse_laplace(s,t) sage: yt = E[1,2].inverse_laplace(s,t) @@ -1630,11 +1639,11 @@ def laplace(ex, t, s, algorithm='maxima'): -91/2*e^(4*t) + 629/2*e^(-4*t) + 1 sage: yt 91/8*e^(4*t) + 629/8*e^(-4*t) - sage: p1 = plot(xt,0,1/2,rgbcolor=(1,0,0)) - sage: p2 = plot(yt,0,1/2,rgbcolor=(0,1,0)) + sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # needs sage.plot + sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # needs sage.plot sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: - ....: (p1+p2).save(f.name) + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot + ....: (p1 + p2).save(f.name) Another example:: @@ -1789,19 +1798,19 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``t`` - independent variable + - ``t`` -- independent variable - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. SEEALSO:: @@ -1843,9 +1852,11 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): Transform a rational expression:: - sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, algorithm='giac') - -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + - e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) + sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, + ....: algorithm='giac') + -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) + - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + e^(-t + 1))*heaviside(t - 1) + + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) sage: inverse_laplace(1/(s - 1), s, x) e^x @@ -1955,7 +1966,7 @@ def at(ex, *args, **kwds): We do not import ``at`` at the top level, but we can use it as a synonym for substitution if we import it:: - sage: g = x^3-3 + sage: g = x^3 - 3 sage: from sage.calculus.calculus import at sage: at(g, x=1) -2 @@ -1970,15 +1981,16 @@ def at(ex, *args, **kwds): u(h + x) sage: diff(u(x+h), x) D[0](u)(h + x) - sage: taylor(u(x+h),h,0,4) - 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) + sage: taylor(u(x+h), h, 0, 4) + 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) We compute a Laplace transform:: sage: var('s,t') (s, t) - sage: f=function('f')(t) - sage: f.diff(t,2) + sage: f = function('f')(t) + sage: f.diff(t, 2) diff(f(t), t, t) sage: f.diff(t,2).laplace(t,s) s^2*laplace(f(t), t, s) - s*f(0) - D[0](f)(0) @@ -2078,7 +2090,7 @@ def dummy_laplace(*args): sage: from sage.calculus.calculus import dummy_laplace sage: s,t = var('s,t') sage: f = function('f') - sage: dummy_laplace(f(t),t,s) + sage: dummy_laplace(f(t), t, s) laplace(f(t), t, s) """ return _laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2086,7 +2098,7 @@ def dummy_laplace(*args): def dummy_inverse_laplace(*args): """ - This function is called to create formal wrappers of inverse laplace + This function is called to create formal wrappers of inverse Laplace transforms that Maxima can't compute: EXAMPLES:: @@ -2094,7 +2106,7 @@ def dummy_inverse_laplace(*args): sage: from sage.calculus.calculus import dummy_inverse_laplace sage: s,t = var('s,t') sage: F = function('F') - sage: dummy_inverse_laplace(F(s),s,t) + sage: dummy_inverse_laplace(F(s), s, t) ilt(F(s), s, t) """ return _inverse_laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2108,7 +2120,7 @@ def dummy_pochhammer(*args): sage: from sage.calculus.calculus import dummy_pochhammer sage: s,t = var('s,t') - sage: dummy_pochhammer(s,t) + sage: dummy_pochhammer(s, t) gamma(s + t)/gamma(s) """ x, y = args @@ -2224,12 +2236,12 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): INPUT: - - ``x`` - a string + - ``x`` -- a string - - ``equals_sub`` - (default: False) if True, replace + - ``equals_sub`` -- (default: ``False``) if ``True``, replace '=' by '==' in self - - ``maxima`` - (default: the calculus package's + - ``maxima`` -- (default: the calculus package's copy of Maxima) the Maxima interpreter to use. EXAMPLES:: @@ -2415,7 +2427,7 @@ def mapped_opts(v): INPUT: - - ``v`` - an object + - ``v`` -- an object OUTPUT: a string. @@ -2548,13 +2560,13 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars INPUT: - - ``s`` - a string + - ``s`` -- a string - - ``syms`` - (default: {}) dictionary of - strings to be regarded as symbols or functions ; + - ``syms`` -- (default: ``{}``) dictionary of + strings to be regarded as symbols or functions; keys are pairs (string, number of arguments) - - ``accept_sequence`` - (default: False) controls whether + - ``accept_sequence`` -- (default: ``False``) controls whether to allow a (possibly nested) set of lists and tuples as input @@ -2562,23 +2574,25 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars EXAMPLES:: + sage: from sage.calculus.calculus import symbolic_expression_from_string sage: y = var('y') - sage: sage.calculus.calculus.symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]',syms={('spam',0):y},accept_sequence=True) + sage: symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]', + ....: syms={('spam',0): y}, accept_sequence=True) [0, 3*y + e^pi] TESTS: Check that the precision is preserved (:trac:`28814`):: - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(1/3))) + sage: symbolic_expression_from_string(str(RealField(100)(1/3))) 0.3333333333333333333333333333 - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(10^-500/3))) + sage: symbolic_expression_from_string(str(RealField(100)(10^-500/3))) 3.333333333333333333333333333e-501 The Giac interface uses a different parser (:trac:`30133`):: sage: from sage.calculus.calculus import SR_parser_giac - sage: sage.calculus.calculus.symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) + sage: symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) e """ if syms is None: diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 6dabb5b1121..afe63ccb954 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -874,8 +874,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): :: - sage: P1 = plot([solx,soly], (0,1)) - sage: P2 = parametric_plot((solx,soly), (0,1)) + sage: P1 = plot([solx,soly], (0,1)) # needs sage.plot + sage: P2 = parametric_plot((solx,soly), (0,1)) # needs sage.plot Now type ``show(P1)``, ``show(P2)`` to view these plots. @@ -892,7 +892,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): sage: desolve_system([de1, de2], [x1, x2], ics=[1,1], ivar=t) Traceback (most recent call last): ... - ValueError: Initial conditions aren't complete: number of vars is different from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] + ValueError: Initial conditions aren't complete: number of vars is different + from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] Check that :trac:`9825` is fixed:: @@ -1013,9 +1014,9 @@ def eulers_method(f, x0, y0, h, x1, algorithm="table"): :: sage: pts = eulers_method(5*x+y-5,0,1,1/2,1,algorithm="none") - sage: P1 = list_plot(pts) - sage: P2 = line(pts) - sage: (P1+P2).show() + sage: P1 = list_plot(pts) # needs sage.plot + sage: P2 = line(pts) # needs sage.plot + sage: (P1 + P2).show() # needs sage.plot AUTHORS: @@ -1163,7 +1164,7 @@ def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1): sage: from sage.calculus.desolvers import eulers_method_2x2_plot sage: f = lambda z : z[2]; g = lambda z : -sin(z[1]) - sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # needs sage.plot """ from sage.plot.line import line @@ -1430,13 +1431,14 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 Lotka Volterra system:: sage: from sage.calculus.desolvers import desolve_system_rk4 - sage: x,y,t=var('x y t') - sage: P=desolve_system_rk4([x*(1-y),-y*(1-x)],[x,y],ics=[0,0.5,2],ivar=t,end_points=20) - sage: Q=[ [i,j] for i,j,k in P] - sage: LP=list_plot(Q) + sage: x,y,t = var('x y t') + sage: P = desolve_system_rk4([x*(1-y),-y*(1-x)], [x,y], ics=[0,0.5,2], + ....: ivar=t, end_points=20) + sage: Q = [[i,j] for i,j,k in P] + sage: LP = list_plot(Q) # needs sage.plot - sage: Q=[ [j,k] for i,j,k in P] - sage: LP=list_plot(Q) + sage: Q = [[j,k] for i,j,k in P] + sage: LP = list_plot(Q) # needs sage.plot ALGORITHM: @@ -1570,49 +1572,52 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() Lotka Volterra Equations:: sage: from sage.calculus.desolvers import desolve_odeint - sage: x,y=var('x,y') - sage: f=[x*(1-y),-y*(1-x)] - sage: sol=desolve_odeint(f,[0.5,2],srange(0,10,0.1),[x,y]) - sage: p=line(zip(sol[:,0],sol[:,1])) - sage: p.show() + sage: x,y = var('x,y') + sage: f = [x*(1-y), -y*(1-x)] + sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # needs scipy + sage: p = line(zip(sol[:,0],sol[:,1])) # needs scipy sage.plot + sage: p.show() # needs scipy sage.plot Lorenz Equations:: - sage: x,y,z=var('x,y,z') + sage: x,y,z = var('x,y,z') sage: # Next we define the parameters - sage: sigma=10 - sage: rho=28 - sage: beta=8/3 + sage: sigma = 10 + sage: rho = 28 + sage: beta = 8/3 sage: # The Lorenz equations - sage: lorenz=[sigma*(y-x),x*(rho-z)-y,x*y-beta*z] + sage: lorenz = [sigma*(y-x),x*(rho-z)-y,x*y-beta*z] sage: # Time and initial conditions - sage: times=srange(0,50.05,0.05) - sage: ics=[0,1,1] - sage: sol=desolve_odeint(lorenz,ics,times,[x,y,z],rtol=1e-13,atol=1e-14) + sage: times = srange(0,50.05,0.05) + sage: ics = [0,1,1] + sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # needs scipy + ....: rtol=1e-13, atol=1e-14) One-dimensional stiff system:: - sage: y= var('y') - sage: epsilon=0.01 - sage: f=y^2*(1-y) - sage: ic=epsilon - sage: t=srange(0,2/epsilon,1) - sage: sol=desolve_odeint(f,ic,t,y,rtol=1e-9,atol=1e-10,compute_jac=True) - sage: p=points(zip(t,sol[:,0])) - sage: p.show() + sage: y = var('y') + sage: epsilon = 0.01 + sage: f = y^2*(1-y) + sage: ic = epsilon + sage: t = srange(0,2/epsilon,1) + sage: sol = desolve_odeint(f, ic, t, y, # needs scipy + ....: rtol=1e-9, atol=1e-10, compute_jac=True) + sage: p = points(zip(t,sol[:,0])) # needs scipy sage.plot + sage: p.show() # needs scipy sage.plot Another stiff system with some optional parameters with no default value:: - sage: y1,y2,y3=var('y1,y2,y3') - sage: f1=77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) - sage: f2=1/77.27*(y3-(1+y1)*y2) - sage: f3=0.16*(y1-y3) - sage: f=[f1,f2,f3] - sage: ci=[0.2,0.4,0.7] - sage: t=srange(0,10,0.01) - sage: v=[y1,y2,y3] - sage: sol=desolve_odeint(f,ci,t,v,rtol=1e-3,atol=1e-4,h0=0.1,hmax=1,hmin=1e-4,mxstep=1000,mxords=17) + sage: y1,y2,y3 = var('y1,y2,y3') + sage: f1 = 77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) + sage: f2 = 1/77.27*(y3-(1+y1)*y2) + sage: f3 = 0.16*(y1-y3) + sage: f = [f1,f2,f3] + sage: ci = [0.2,0.4,0.7] + sage: t = srange(0,10,0.01) + sage: v = [y1,y2,y3] + sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # needs scipy + ....: h0=0.1, hmax=1, hmin=1e-4, mxstep=1000, mxords=17) AUTHOR: diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index 2f769a8f327..03ea8bbd294 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Functional notation support for common calculus methods diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 6c47b0d2fc9..11a23aac323 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,9 +1,12 @@ +# sage.doctest: needs sage.symbolic r""" Calculus functions """ -from sage.matrix.constructor import matrix +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix, is_Vector, Expression +lazy_import('sage.matrix.constructor', 'matrix') + from .functional import diff diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 04ef352a906..19b2dc2e4c8 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Numerical Integration diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index e31d3606cc4..21b82388461 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -55,9 +55,9 @@ cdef class Spline: This example is in the GSL documentation:: - sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] + sage: v = [(i + RDF(i).sin()/2, i + RDF(i^2).cos()) for i in range(10)] sage: s = spline(v) - sage: show(point(v) + plot(s,0,9, hue=.8)) + sage: show(point(v) + plot(s,0,9, hue=.8)) # needs sage.plot We compute the area underneath the spline:: @@ -77,13 +77,13 @@ cdef class Spline: We compute the first and second-order derivatives at a few points:: sage: s.derivative(5) - -0.16230085261803... + -0.1623008526180... sage: s.derivative(6) - 0.20997986285714... + 0.2099798628571... sage: s.derivative(5, order=2) - -3.08747074561380... + -3.0874707456138... sage: s.derivative(6, order=2) - 2.61876848274853... + 2.6187684827485... Only the first two derivatives are supported:: @@ -118,7 +118,7 @@ cdef class Spline: Replace `0`-th point, which changes the spline:: - sage: S[0]=(0,1); S + sage: S[0] = (0,1); S [(0, 1), (2, 3), (4, 5)] sage: S(1.5) 2.5 diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index ded37516d62..fb057f0fc2e 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs numpy """ Complex Interpolation @@ -49,9 +50,10 @@ def polygon_spline(pts): sage: ps = polygon_spline(pts) sage: fx = lambda x: ps.value(x).real sage: fy = lambda x: ps.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: ps.value(real(x))], [lambda x: ps.derivative(real(x))],0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot + sage: m = Riemann_Map([lambda x: ps.value(real(x))], + ....: [lambda x: ps.derivative(real(x))], 0) + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of an circle:: @@ -119,7 +121,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.value(.5) (-0.363380227632...-1j) - sage: ps.value(0) - ps.value(2*pi) + sage: ps.value(0) - ps.value(2*RDF.pi()) 0j sage: ps.value(10) (0.26760455264...+1j) @@ -152,6 +154,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.derivative(1 / 3) (1.27323954473...+0j) + sage: from math import pi sage: ps.derivative(0) - ps.derivative(2*pi) 0j sage: ps.derivative(10) @@ -171,7 +174,7 @@ def complex_cubic_spline(pts): INPUT: - - ``pts`` A list or array of complex numbers, or tuples of the form + - ``pts`` -- A list or array of complex numbers, or tuples of the form `(x,y)`. EXAMPLES: @@ -182,13 +185,16 @@ def complex_cubic_spline(pts): sage: cs = complex_cubic_spline(pts) sage: fx = lambda x: cs.value(x).real sage: fy = lambda x: cs.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: cs.value(real(x))], [lambda x: cs.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: from math import pi + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot + sage: m = Riemann_Map([lambda x: cs.value(real(x))], + ....: [lambda x: cs.derivative(real(x))], 0) + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of a circle:: - sage: pts = [e^(I*t / 25) for t in range(25)] + sage: from cmath import exp + sage: pts = [exp(1j * t / 25) for t in range(25)] sage: cs = complex_cubic_spline(pts) sage: cs.derivative(2) (-0.0497765406583...+0.151095006434...j) @@ -273,6 +279,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.value(4 / 7) (-0.303961332787...-1.34716728183...j) + sage: from math import pi sage: cs.value(0) - cs.value(2*pi) 0j sage: cs.value(-2.73452) @@ -304,6 +311,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.derivative(3 / 5) (1.40578892327...-0.225417136326...j) + sage: from math import pi sage: cs.derivative(0) - cs.derivative(2 * pi) 0j sage: cs.derivative(-6) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 74bac5b0811..a7fbb87dffb 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -109,30 +109,31 @@ cdef int c_f(double t,double* y, double* dydt,void *params): class ode_solver(): r""" - :meth:`ode_solver` is a class that wraps the GSL libraries ode - solver routines To use it instantiate a class,:: + :meth:`ode_solver` is a class that wraps the GSL library's ode solver routines. - sage: T=ode_solver() + To use it, instantiate the class:: - To solve a system of the form ``dy_i/dt=f_i(t,y)``, you must + sage: T = ode_solver() + + To solve a system of the form `dy_i/dt=f_i(t,y)`, you must supply a vector or tuple/list valued function ``f`` representing - ``f_i``. The functions ``f`` and the jacobian should have the + `f_i`. The functions `f` and the jacobian should have the form ``foo(t,y)`` or ``foo(t,y,params)``. ``params`` which is optional allows for your function to depend on one or a tuple of parameters. Note if you use it, ``params`` must be a tuple even if it only has one component. For example if you wanted to solve - `y''+y=0`. You need to write it as a first order system:: + `y''+y=0`, you would need to write it as a first order system:: y_0' = y_1 y_1' = -y_0 In code:: - sage: f = lambda t,y:[y[1],-y[0]] - sage: T.function=f + sage: f = lambda t, y: [y[1], -y[0]] + sage: T.function = f - For some algorithms the jacobian must be supplied as well, the - form of this should be a function return a list of lists of the + For some algorithms, the jacobian must be supplied as well, the + form of this should be a function returning a list of lists of the form ``[ [df_1/dy_1,...,df_1/dy_n], ..., [df_n/dy_1,...,df_n,dy_n], [df_1/dt,...,df_n/dt] ]``. @@ -143,45 +144,45 @@ class ode_solver(): There are a variety of algorithms available for different types of systems. Possible algorithms are - - ``rkf45`` - runga-kutta-felhberg (4,5) + - ``'rkf45'`` -- Runge-Kutta-Fehlberg (4,5) - - ``rk2`` - embedded runga-kutta (2,3) + - ``'rk2'`` -- embedded Runge-Kutta (2,3) - - ``rk4`` - 4th order classical runga-kutta + - ``'rk4'`` -- 4th order classical Runge-Kutta - - ``rk8pd`` - runga-kutta prince-dormand (8,9) + - ``'rk8pd'`` -- Runge-Kutta Prince-Dormand (8,9) - - ``rk2imp`` - implicit 2nd order runga-kutta at gaussian points + - ``'rk2imp'`` -- implicit 2nd order Runge-Kutta at gaussian points - - ``rk4imp`` - implicit 4th order runga-kutta at gaussian points + - ``'rk4imp'`` -- implicit 4th order Runge-Kutta at gaussian points - - ``bsimp`` - implicit burlisch-stoer (requires jacobian) + - ``'bsimp'`` -- implicit Burlisch-Stoer (requires jacobian) - - ``gear1`` - M=1 implicit gear + - ``'gear1'`` -- M=1 implicit gear - - ``gear2`` - M=2 implicit gear + - ``'gear2'`` -- M=2 implicit gear - The default algorithm is ``rkf45``. If you instead wanted to use - ``bsimp`` you would do:: + The default algorithm is ``'rkf45'``. If you instead wanted to use + ``'bsimp'`` you would do:: - sage: T.algorithm="bsimp" + sage: T.algorithm = "bsimp" - The user should supply initial conditions in y_0. For example if - your initial conditions are y_0=1,y_1=1, do:: + The user should supply initial conditions in ``y_0``. For example if + your initial conditions are `y_0=1, y_1=1`, do:: - sage: T.y_0=[1,1] + sage: T.y_0 = [1,1] The actual solver is invoked by the method :meth:`ode_solve`. It has arguments ``t_span``, ``y_0``, ``num_points``, ``params``. ``y_0`` must be supplied either as an argument or above by assignment. Params which are optional and only necessary if your - system uses params can be supplied to ``ode_solve`` or by + system uses ``params`` can be supplied to ``ode_solve`` or by assignment. ``t_span`` is the time interval on which to solve the ode. There are two ways to specify ``t_span``: - * If ``num_points`` is not specified then the sequence ``t_span`` + * If ``num_points`` is not specified, then the sequence ``t_span`` is used as the time points for the solution. Note that the first element ``t_span[0]`` is the initial time, where the initial condition ``y_0`` is the specified solution, and @@ -192,10 +193,10 @@ class ode_solver(): and the solution will be computed at ``num_points`` equally spaced points between ``t_span[0]`` and ``t_span[1]``. The initial condition is also included in the output so that - ``num_points``\ +1 total points are returned. E.g. if ``t_span + ``num_points + 1`` total points are returned. E.g. if ``t_span = [0.0, 1.0]`` and ``num_points = 10``, then solution is returned at the 11 time points ``[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, - 0.6, 0.7, 0.8, 0.9, 1.0]``\ . + 0.6, 0.7, 0.8, 0.9, 1.0]``. (Note that if ``num_points`` is specified and ``t_span`` is not length 2 then ``t_span`` are used as the time points and @@ -203,13 +204,19 @@ class ode_solver(): Error is estimated via the expression ``D_i = error_abs*s_i+error_rel*(a|y_i|+a_dydt*h*|y_i'|)``. The user can - specify ``error_abs`` (1e-10 by default), ``error_rel`` (1e-10 by - default) ``a`` (1 by default), ``a_(dydt)`` (0 by default) and - ``s_i`` (as scaling_abs which should be a tuple and is 1 in all - components by default). If you specify one of ``a`` or ``a_dydt`` + specify + + - ``error_abs`` (1e-10 by default), + - ``error_rel`` (1e-10 by default), + - ``a`` (1 by default), + - ``a_dydt`` (0 by default) and + - ``s_i`` (as ``scaling_abs`` which should be a tuple and is 1 in all + components by default). + + If you specify one of ``a`` or ``a_dydt`` you must specify the other. You may specify ``a`` and ``a_dydt`` without ``scaling_abs`` (which will be taken =1 be default). - ``h`` is the initial step size which is (1e-2) by default. + ``h`` is the initial step size, which is 1e-2 by default. ``ode_solve`` solves the solution as a list of tuples of the form, ``[ (t_0,[y_1,...,y_n]),(t_1,[y_1,...,y_n]),...,(t_n,[y_1,...,y_n])]``. @@ -223,27 +230,29 @@ class ode_solver(): Consider solving the Van der Pol oscillator `x''(t) + ux'(t)(x(t)^2-1)+x(t)=0` between `t=0` and `t= 100`. As a first order system it is `x'=y`, `y'=-x+uy(1-x^2)`. Let us take `u=10` - and use initial conditions `(x,y)=(1,0)` and use the runga-kutta - prince-dormand algorithm. :: + and use initial conditions `(x,y)=(1,0)` and use the Runge-Kutta + Prince-Dormand algorithm. :: - sage: def f_1(t,y,params): - ....: return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)] + sage: def f_1(t, y, params): + ....: return [y[1], -y[0] - params[0]*y[1]*(y[0]**2-1.0)] - sage: def j_1(t,y,params): - ....: return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ] + sage: def j_1(t, y, params): + ....: return [[0.0, 1.0], + ....: [-2.0*params[0]*y[0]*y[1] - 1.0, -params[0]*(y[0]*y[0]-1.0)], + ....: [0.0, 0.0]] - sage: T=ode_solver() - sage: T.algorithm="rk8pd" - sage: T.function=f_1 - sage: T.jacobian=j_1 - sage: T.ode_solve(y_0=[1,0],t_span=[0,100],params=[10.0],num_points=1000) + sage: T = ode_solver() + sage: T.algorithm = "rk8pd" + sage: T.function = f_1 + sage: T.jacobian = j_1 + sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(filename=f.name) The solver line is equivalent to:: - sage: T.ode_solve(y_0=[1,0],t_span=[x/10.0 for x in range(1000)],params = [10.0]) + sage: T.ode_solve(y_0=[1,0], t_span=[x/10.0 for x in range(1000)], params=[10.0]) Let's try a system:: @@ -254,40 +263,42 @@ class ode_solver(): We will not use the jacobian this time and will change the error tolerances. :: - sage: g_1= lambda t,y: [y[1]*y[2],-y[0]*y[2],-0.51*y[0]*y[1]] - sage: T.function=g_1 - sage: T.y_0=[0,1,1] - sage: T.scale_abs=[1e-4,1e-4,1e-5] - sage: T.error_rel=1e-4 - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: g_1 = lambda t,y: [y[1]*y[2], -y[0]*y[2], -0.51*y[0]*y[1]] + sage: T.function = g_1 + sage: T.y_0 = [0,1,1] + sage: T.scale_abs = [1e-4, 1e-4, 1e-5] + sage: T.error_rel = 1e-4 + sage: T.ode_solve(t_span=[0,12], num_points=100) - By default T.plot_solution() plots the y_0, to plot general y_i use:: + By default ``T.plot_solution()`` plots the `y_0`; to plot general `y_i`, use:: - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(i=0, filename=f.name) ....: T.plot_solution(i=1, filename=f.name) ....: T.plot_solution(i=2, filename=f.name) The method interpolate_solution will return a spline interpolation - through the points found by the solver. By default y_0 is - interpolated. You can interpolate y_i through the keyword - argument i. :: + through the points found by the solver. By default, `y_0` is + interpolated. You can interpolate `y_i` through the keyword + argument ``i``. :: sage: f = T.interpolate_solution() - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=1) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=2) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution() + sage: from math import pi sage: f(pi) 0.5379... The solver attributes may also be set up using arguments to ode_solver. The previous example can be rewritten as:: - sage: T = ode_solver(g_1,y_0=[0,1,1],scale_abs=[1e-4,1e-4,1e-5],error_rel=1e-4, algorithm="rk8pd") - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: T = ode_solver(g_1, y_0=[0,1,1], scale_abs=[1e-4,1e-4,1e-5], + ....: error_rel=1e-4, algorithm="rk8pd") + sage: T.ode_solve(t_span=[0,12], num_points=100) sage: f = T.interpolate_solution() sage: f(pi) 0.5379... @@ -295,7 +306,7 @@ class ode_solver(): Unfortunately because Python functions are used, this solver is slow on systems that require many function evaluations. It is possible to pass a compiled function by deriving from the - class ``ode_sysem`` and overloading ``c_f`` and ``c_j`` with C + class :class:`ode_system` and overloading ``c_f`` and ``c_j`` with C functions that specify the system. The following will work in the notebook: @@ -382,11 +393,11 @@ class ode_solver(): sage: T.function = lambda t,y: [cos(y[0]) * sin(t)] sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]] sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000) - sage: T.plot_solution() + sage: T.plot_solution() # needs sage.plot And with some options:: - sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) + sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # needs sage.plot """ if interpolate: from sage.plot.line import line2d diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 46e2964eade..05d5b1ec60a 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs numpy sage.symbolic """ Riemann Mapping @@ -1190,9 +1191,10 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, sage: from sage.calculus.riemann import complex_to_spiderweb sage: import numpy - sage: zval = numpy.array([[0, 1, 1000],[.2+.3j,1,-.3j],[0,0,0]],dtype = numpy.complex128) + sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], + ....: dtype=numpy.complex128) sage: deriv = numpy.array([[.1]],dtype = numpy.float64) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,False,0.001) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) array([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], @@ -1205,7 +1207,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, [1., 1., 1.], [1., 1., 1.]]]) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,True,0.001) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]], @@ -1280,12 +1282,12 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): sage: from sage.calculus.riemann import complex_to_rgb sage: import numpy - sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype = numpy.complex128)) + sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]]]) - sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype = numpy.complex128)) + sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [0.52779177, 1. , 0.05558355], [0.08650622, 0.17301243, 0. ]]]) diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 927e6ee4fb6..b99d5d7857e 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" A Sample Session using SymPy @@ -102,46 +102,47 @@ And here are some actual tests of sympy:: - sage: from sympy import Symbol, cos, sympify, pprint - sage: from sympy.abc import x + sage: from sympy import Symbol, cos, sympify, pprint # needs sympy + sage: from sympy.abc import x # needs sympy :: - sage: e = (1/cos(x)^3)._sympy_(); e + sage: e = (1/cos(x)^3)._sympy_(); e # needs sympy cos(x)**(-3) - sage: f = e.series(x, 0, int(10)); f + sage: f = e.series(x, 0, int(10)); f # needs sympy 1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10) And the pretty-printer. Since unicode characters are not working on some architectures, we disable it:: - sage: from sympy.printing import pprint_use_unicode - sage: prev_use = pprint_use_unicode(False) - sage: pprint(e) + sage: from sympy.printing import pprint_use_unicode # needs sympy + sage: prev_use = pprint_use_unicode(False) # needs sympy + sage: pprint(e) # needs sympy 1 ------- 3 cos (x) - sage: pprint(f) + sage: pprint(f) # needs sympy 2 4 6 8 3*x 11*x 241*x 8651*x / 10\ 1 + ---- + ----- + ------ + ------- + O\x / 2 8 240 13440 - sage: pprint_use_unicode(prev_use) + sage: pprint_use_unicode(prev_use) # needs sympy False And the functionality to convert from sympy format to Sage format:: - sage: e._sage_() + sage: e._sage_() # needs sympy cos(x)^(-3) - sage: e._sage_().taylor(x._sage_(), 0, 8) + sage: e._sage_().taylor(x._sage_(), 0, 8) # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + 1 - sage: f._sage_() + sage: f._sage_() # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + Order(x^10) + 1 Mixing SymPy with Sage:: + sage: # needs sympy sage: import sympy sage: var("x")._sympy_() + var("y")._sympy_() x + y @@ -155,7 +156,7 @@ sage: t1, t2 (omega + x, omega + x) - sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) + sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) sage: type(e) sage: e @@ -172,23 +173,24 @@ :: - sage: a = sympy.Matrix([1, 2, 3]) - sage: a[1] + sage: a = sympy.Matrix([1, 2, 3]) # needs sympy + sage: a[1] # needs sympy 2 :: - sage: sympify(1.5) + sage: sympify(1.5) # needs sympy 1.50000000000000 - sage: sympify(2) + sage: sympify(2) # needs sympy 2 - sage: sympify(-2) + sage: sympify(-2) # needs sympy -2 TESTS: This was fixed in Sympy, see :trac:`14437`:: + sage: # needs sympy sage: from sympy import Function, Symbol, rsolve sage: u = Function('u') sage: n = Symbol('n', integer=True) diff --git a/src/sage/calculus/transforms/all.py b/src/sage/calculus/transforms/all.py index 06ed525b868..379b3b69c37 100644 --- a/src/sage/calculus/transforms/all.py +++ b/src/sage/calculus/transforms/all.py @@ -1,3 +1,5 @@ -from .fft import FastFourierTransform, FFT -from .dwt import WaveletTransform, DWT +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.calculus.transforms.fft", ["FastFourierTransform", "FFT"]) +lazy_import("sage.calculus.transforms.dwt", ["WaveletTransform", "DWT"]) from .dft import IndexedSequence diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index db18a20e129..b413bc0ea81 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -16,7 +16,7 @@ - plotting, printing -- :meth:`IndexedSequence.plot`, :meth:`IndexedSequence.plot_histogram`, :meth:`_repr_`, :meth:`__str__` -- dft -- computes the discrete Fourier transform for the following cases: +- :meth:`dft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or :class:`CyclotomicField`) indexed by ``range(N)`` or `\ZZ / N \ZZ` @@ -26,21 +26,21 @@ * a sequence (as above) indexed by a complete set of representatives of the conjugacy classes of a finite matrix group -- idft -- computes the discrete Fourier transform for the following cases: +- :meth:`idft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or CyclotomicField) indexed by ``range(N)`` or `\ZZ / N \ZZ` -- dct, dst (for discrete Fourier/Cosine/Sine transform) +- :meth:`dct`, :meth:`dst` (for discrete Fourier/Cosine/Sine transform) - convolution (in :meth:`IndexedSequence.convolution` and :meth:`IndexedSequence.convolution_periodic`) -- fft, ifft -- (fast Fourier transforms) wrapping GSL's +- :meth:`fft`, :meth:`ifft` -- (fast Fourier transforms) wrapping GSL's ``gsl_fft_complex_forward()``, ``gsl_fft_complex_inverse()``, using William Stein's :func:`FastFourierTransform` -- dwt, idwt -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, +- :meth:`dwt`, :meth:`idwt` -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, ``gsl_dwt_backward()`` using Joshua Kantor's :func:`WaveletTransform` class. Allows for wavelets of type: @@ -71,20 +71,20 @@ # # https://www.gnu.org/licenses/ ########################################################################## -from sage.rings.number_field.number_field import CyclotomicField +from sage.functions.trig import sin, cos from sage.misc.lazy_import import lazy_import -from sage.groups.abelian_gps.abelian_group import AbelianGroup -from sage.groups.perm_gps.permgroup_element import is_PermutationGroupElement -from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.functions.all import sin, cos -from sage.calculus.transforms.fft import FastFourierTransform -from sage.calculus.transforms.dwt import WaveletTransform from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence + +lazy_import("sage.calculus.transforms.dwt", "WaveletTransform") +lazy_import("sage.calculus.transforms.fft", "FastFourierTransform") +lazy_import("sage.groups.abelian_gps.abelian_group", "AbelianGroup") +lazy_import("sage.groups.perm_gps.permgroup_element", "PermutationGroupElement") lazy_import("sage.plot.all", ["polygon", "line", "text"]) +lazy_import("sage.rings.number_field.number_field", "CyclotomicField") class IndexedSequence(SageObject): @@ -218,8 +218,7 @@ def _repr_(self): indexed by [0, 1, 2] sage: I = GF(3) sage: A = [i^2 for i in I] - sage: s = IndexedSequence(A,I) - sage: s + sage: s = IndexedSequence(A,I); s Indexed sequence: [0, 1, 1] indexed by Finite Field of size 3 """ @@ -240,9 +239,10 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: J = list(range(3)) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) - sage: P = s.plot_histogram() - sage: show(P) # Not tested + sage: P = s.plot_histogram() # needs sage.plot + sage: show(P) # not tested # needs sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() N = len(I) @@ -268,9 +268,10 @@ def plot(self): sage: I = list(range(3)) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) - sage: P = s.plot() - sage: show(P) # Not tested + sage: P = s.plot() # needs sage.plot + sage: show(P) # not tested # needs sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() S = self.list() @@ -286,30 +287,44 @@ def dft(self, chi=lambda x: x): sage: J = list(range(6)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: s.dft(lambda x:x^2) + sage: s.dft(lambda x: x^2) # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: s.dft() + sage: s.dft() # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] + + sage: # needs sage.groups sage: G = SymmetricGroup(3) sage: J = G.conjugacy_classes_representatives() - sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G + sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn Indexed sequence: [8, 2, 2] indexed by [(), (1,2), (1,2,3)] - sage: J = AbelianGroup(2,[2,3],names='ab') - sage: s = IndexedSequence([1,2,3,4,5,6],J) + sage: J = AbelianGroup(2, [2,3], names='ab') + sage: s = IndexedSequence([1,2,3,4,5,6], J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Multiplicative Abelian group isomorphic to C2 x C3 + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Multiplicative Abelian group isomorphic to C2 x C3 sage: J = CyclicPermutationGroup(6) - sage: s = IndexedSequence([1,2,3,4,5,6],J) + sage: s = IndexedSequence([1,2,3,4,5,6], J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Cyclic group of order 6 as a permutation group + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Cyclic group of order 6 as a permutation group + + sage: # needs sage.rings.number_field sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] - sage: s = IndexedSequence(A,J) + sage: s = IndexedSequence(A, J) sage: Fs = s.dft() sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() [0, 1, 1, -1, 1, -1, -1] @@ -336,7 +351,7 @@ def dft(self, chi=lambda x: x): zeta = CyclotomicField(N).gen() FT = [sum([S[i] * chi(zeta**(i * j)) for i in J]) for j in J] elif (J[0] not in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring() == QQ): - if is_PermutationGroupElement(J[0]): + if isinstance(J[0], PermutationGroupElement): # J is a CyclicPermGp n = G.order() a = list(n.factor()) @@ -364,13 +379,13 @@ def idft(self): sage: J = list(range(5)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: fs = s.dft(); fs + sage: fs = s.dft(); fs # needs sage.rings.number_field Indexed sequence: [5, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4] - sage: it = fs.idft(); it + sage: it = fs.idft(); it # needs sage.rings.number_field Indexed sequence: [1, 1, 1, 1, 1] indexed by [0, 1, 2, 3, 4] - sage: it == s + sage: it == s # needs sage.rings.number_field True """ F = self.base_ring() # elements must be coercible into QQ(zeta_N) @@ -390,18 +405,23 @@ def dct(self): EXAMPLES:: sage: J = list(range(5)) - sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) - sage: s.dct() + sage: A = [exp(-2*pi*i*I/5) for i in J] # needs sage.symbolic + sage: s = IndexedSequence(A, J) # needs sage.symbolic + sage: s.dct() # needs sage.symbolic Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() - PI = 2 * F(pi) / N + PI = 2 * pi / N FT = [sum([S[i] * cos(PI * i * j) for i in J]) for j in J] return IndexedSequence(FT, J) @@ -412,16 +432,21 @@ def dst(self): EXAMPLES:: sage: J = list(range(5)) - sage: I = CC.0; pi = CC(pi) + sage: I = CC.0; pi = CC.pi() sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) + sage: s = IndexedSequence(A, J) sage: s.dst() # discrete sine Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...] indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() @@ -711,6 +736,7 @@ def dwt(self, other="haar", wavelet_k=2): Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 @@ -788,6 +814,7 @@ def idwt(self, other="haar", wavelet_k=2): sage: t.idwt("bspline", 103) == s True """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 9296afb7824..807169f2886 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -64,27 +64,28 @@ def WaveletTransform(n, wavelet_type, wavelet_k): sage: for i in range(1, 11): ....: a[i] = 1 ....: a[128-i] = 1 - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # needs sage.plot sage: a = WaveletTransform(128,'haar',2) sage: for i in range(1, 11): a[i] = 1; a[128-i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a = WaveletTransform(128,'bspline_centered',103) sage: for i in range(1, 11): a[i] = 1; a[100+i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot This example gives a simple example of wavelet compression:: + sage: # needs sage.symbolic sage: a = DWT(2048,'daubechies',6) sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage: a.forward_transform() sage: for i in range(1800): a[2048-i-1] = 0 sage: a.backward_transform() - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot """ cdef size_t _n, _k _n = int(n) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 05db8f5e3e7..168698957c4 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -22,7 +22,6 @@ AUTHORS: from cysignals.memory cimport sig_malloc, sig_free -import sage.libs.pari.all from sage.rings.integer import Integer from sage.rings.complex_mpfr import ComplexNumber @@ -70,9 +69,9 @@ def FastFourierTransform(size, base_ring=None): ....: a[128-i] = 1 sage: a[:6:2] [(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)] - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # needs sage.plot """ return FastFourierTransform_complex(int(size)) @@ -152,6 +151,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: + sage: # needs sage.rings.mpfr sage.symbolic sage: I = CC(I) sage: a = FastFourierTransform(4) sage: a[0] = 1 @@ -243,18 +243,19 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_polar(0,2) + sage: a._plot_polar(0,2) # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point + from sage.symbolic.constants import pi, I cdef int i v = [] - pi = sage.symbolic.constants.pi.n() - I = sage.symbolic.constants.I.n() - s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3 + pi = pi.n() + I = I.n() + s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3. for i from xmin <= i < xmax: z = self.data[2*i] + I*self.data[2*i+1] @@ -282,15 +283,15 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_rect(0,3) + sage: a._plot_rect(0,3) # needs sage.plot Graphics object consisting of 3 graphics primitives """ + from sage.plot.point import point + cdef int i cdef double x, h v = [] - point = sage.plot.all.point - for i in range(xmin, xmax): x = self.data[2*i] h = self.data[2*i+1] @@ -302,10 +303,12 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): Plot a slice of the array. - ``style`` -- Style of the plot, options are ``"rect"`` or ``"polar"`` - - ``rect`` -- height represents real part, color represents - imaginary part. - - ``polar`` -- height represents absolute value, color - represents argument. + + - ``rect`` -- height represents real part, color represents + imaginary part. + - ``polar`` -- height represents absolute value, color + represents argument. + - ``xmin`` -- The lower bound of the slice to plot. 0 by default. - ``xmax`` -- The upper bound of the slice to plot. ``len(self)`` by default. - ``**args`` -- passed on to the line plotting function. @@ -318,11 +321,11 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(16) sage: for i in range(16): a[i] = (random(),random()) - sage: A = plot(a) - sage: B = plot(a, style='polar') - sage: type(A) + sage: A = plot(a) # needs sage.plot + sage: B = plot(a, style='polar') # needs sage.plot + sage: type(A) # needs sage.plot - sage: type(B) + sage: type(B) # needs sage.plot sage: a = FastFourierTransform(125) sage: b = FastFourierTransform(125) @@ -330,7 +333,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives """ @@ -408,7 +411,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives sage: abs(sum([CDF(a[i])-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -421,7 +424,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 256 graphics primitives """ @@ -459,7 +462,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011) + sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011), needs sage.plot sage: abs(sum([CDF(a[i])/125-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -471,7 +474,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) + sage: (a.plot() + b.plot()).show(ymin=0) # needs sage.plot """ cdef gsl_fft_complex_wavetable * wt cdef gsl_fft_complex_workspace * mem diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py index 766ce586eb2..e33409a49ac 100644 --- a/src/sage/calculus/wester.py +++ b/src/sage/calculus/wester.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Further examples from Wester's paper diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 7f0a20bbd0a..7bb97cd83fd 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -202,7 +202,7 @@ def __eq__(self, other): sage: I == I # indirect doctest True """ - return type(self) == type(other) + return type(self) is type(other) def __ne__(self, other): """ @@ -525,7 +525,7 @@ def __eq__(self, other): if isinstance(other, CompositeConstructionFunctor): return self.all == other.all else: - return type(self) == type(other) + return type(self) is type(other) def __ne__(self, other): """ @@ -677,7 +677,7 @@ def __eq__(self, other): sage: I == QQ.construction()[0] False """ - c = (type(self) == type(other)) + c = (type(self) is type(other)) if not c: if isinstance(other, IdentityFunctor_generic): return True @@ -2986,7 +2986,7 @@ def __eq__(self, other): """ if not isinstance(other, QuotientFunctor): return False - return (type(self) == type(other) and + return (type(self) is type(other) and self.domain() == other.domain() and self.codomain() == other.codomain() and self.names == other.names and diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index 9b82bb74b50..5b9ebedc06e 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -255,11 +255,11 @@ def codesize_upper_bound(n, d, q, algorithm=None): 93 sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 - sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_package_guava 85 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 - sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_package_guava 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 @@ -270,7 +270,7 @@ def codesize_upper_bound(n, d, q, algorithm=None): sage: codes.bounds.codesize_upper_bound(19,10,2) 20 - sage: codes.bounds.codesize_upper_bound(19,10,2,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(19,10,2,algorithm="gap") # optional - gap_package_guava 20 Meaningless parameters are rejected:: @@ -379,7 +379,7 @@ def plotkin_upper_bound(n,q,d, algorithm=None): sage: codes.bounds.plotkin_upper_bound(10,2,3) 192 - sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 192 """ _check_n_q_d(n, q, d, field_based=False) @@ -430,7 +430,7 @@ def griesmer_upper_bound(n,q,d,algorithm=None): sage: codes.bounds.griesmer_upper_bound(10,2,3) 128 - sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 128 TESTS:: @@ -471,7 +471,7 @@ def elias_upper_bound(n,q,d,algorithm=None): sage: codes.bounds.elias_upper_bound(10,2,3) 232 - sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 232 """ _check_n_q_d(n, q, d, field_based=False) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 4a157e6bdad..2cd68c11a28 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -731,16 +731,15 @@ def ToricCode(P,F): [36, 5] linear code over GF(7) sage: C.minimum_distance() 24 - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) - ... - 24 + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava + ...24 sage: C = codes.ToricCode([[-2,-2],[-1,-2],[-1,-1],[-1,0], ....: [0,-1],[0,0],[0,1],[1,-1],[1,0]], GF(5)) sage: C [16, 9] linear code over GF(5) sage: C.minimum_distance() 6 - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava 6 sage: C = codes.ToricCode([[0,0],[1,1],[1,2],[1,3],[1,4],[2,1], ....: [2,2],[2,3],[3,1],[3,2],[4,1]], GF(8,"a")) diff --git a/src/sage/coding/databases.py b/src/sage/coding/databases.py index 9fd3b43485b..e0c8b6e4068 100644 --- a/src/sage/coding/databases.py +++ b/src/sage/coding/databases.py @@ -35,11 +35,11 @@ def best_linear_code_in_guava(n, k, F): EXAMPLES:: - sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_packages (Guava package) + sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_package_guava [10, 5] linear code over GF(2) - sage: libgap.LoadPackage('guava') # long time; optional - gap_packages (Guava package) + sage: libgap.LoadPackage('guava') # long time; optional - gap_package_guava ... - sage: libgap.BestKnownLinearCode(10,5,libgap.GF(2)) # long time; optional - gap_packages (Guava package) + sage: libgap.BestKnownLinearCode(10,5,libgap.GF(2)) # long time; optional - gap_package_guava a linear [10,5,4]2..4 shortened code This means that the best possible binary linear code of length 10 and @@ -86,8 +86,8 @@ def bounds_on_minimum_distance_in_guava(n, k, F): EXAMPLES:: - sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) - sage: gap_rec.Display() # optional - gap_packages (Guava package) + sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_package_guava + sage: gap_rec.Display() # optional - gap_package_guava rec( construction := [ , [ [ , diff --git a/src/sage/coding/guava.py b/src/sage/coding/guava.py index 4a529fe762d..e9f0404b458 100644 --- a/src/sage/coding/guava.py +++ b/src/sage/coding/guava.py @@ -60,7 +60,7 @@ def QuasiQuadraticResidueCode(p): EXAMPLES:: - sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) + sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_package_guava [22, 11] linear code over GF(2) These are self-orthogonal in general and self-dual when `p \equiv 3 \pmod 4`. @@ -93,9 +93,9 @@ def RandomLinearCodeGuava(n, k, F): EXAMPLES:: - sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) + sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_package_guava [30, 15] linear code over GF(2) - sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) + sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_package_guava [10, 5] linear code over GF(4) AUTHOR: David Joyner (11-2005) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index ae80ec10894..ac1581f2691 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -410,7 +410,7 @@ def __init__(self, base_field, length, default_encoder_name, default_decoder_nam 1 sage: C.is_self_orthogonal() False - sage: print(C.divisor()) #long time + sage: print(C.divisor()) #long time 1 """ from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder @@ -910,12 +910,11 @@ def covering_radius(self): EXAMPLES:: sage: C = codes.HammingCode(GF(2), 5) - sage: C.covering_radius() # optional - gap_packages (Guava package) - ... - 1 + sage: C.covering_radius() # optional - gap_package_guava + ...1 sage: C = codes.random_linear_code(GF(263), 5, 1) - sage: C.covering_radius() # optional - gap_packages (Guava package) + sage: C.covering_radius() # optional - gap_package_guava Traceback (most recent call last): ... NotImplementedError: the GAP algorithm that Sage is using @@ -1374,9 +1373,8 @@ def minimum_distance(self, algorithm=None): sage: C.minimum_distance(algorithm="gap") # optional - sage.libs.gap 3 sage: libgap.SetAllInfoLevels(0) # to suppress extra info messages # optional - sage.libs.gap - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) - ... - 3 + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava + ...3 TESTS:: @@ -1612,13 +1610,13 @@ def permutation_automorphism_group(self, algorithm="partition"): [5, 3] Hamming Code over GF(4) sage: G = C.permutation_automorphism_group(algorithm="partition"); G # optional - sage.groups Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)] - sage: GG = C.permutation_automorphism_group(algorithm="codecan") # long time, optional - sage.groups - sage: GG == G # long time, optional - sage.groups + sage: GG = C.permutation_automorphism_group(algorithm="codecan") # long time, optional - sage.groups + sage: GG == G # long time, optional - sage.groups True - sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package) sage.groups + sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_package_guava sage.groups Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)] sage: C = codes.GolayCode(GF(3), True) - sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package) sage.groups + sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_package_guava sage.groups Permutation Group with generators [(5,7)(6,11)(8,9)(10,12), (4,6,11)(5,8,12)(7,10,9), (3,4)(6,8)(9,11)(10,12), (2,3)(6,11)(8,12)(9,10), (1,2)(5,10)(7,12)(8,9)] @@ -1839,23 +1837,25 @@ def weight_distribution(self, algorithm=None): [1, 0, 0, 30, 15, 18] sage: C = codes.HammingCode(GF(2), 3); C [7, 4] Hamming Code over GF(2) - sage: C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution(algorithm="leon") # optional - gap_package_guava [1, 0, 0, 7, 7, 0, 0, 1] sage: C.weight_distribution(algorithm="gap") # optional - sage.libs.gap [1, 0, 0, 7, 7, 0, 0, 1] sage: C.weight_distribution(algorithm="binary") [1, 0, 0, 7, 7, 0, 0, 1] + + sage: # optional - gap_package_guava sage: C = codes.HammingCode(GF(3), 3); C [13, 10] Hamming Code over GF(3) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True sage: C = codes.HammingCode(GF(5), 2); C [6, 4] Hamming Code over GF(5) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True sage: C = codes.HammingCode(GF(7), 2); C [8, 6] Hamming Code over GF(7) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True """ @@ -2001,14 +2001,17 @@ def zeta_polynomial(self, name="T"): sage: C = codes.HammingCode(GF(2), 3) sage: C.zeta_polynomial() 2/5*T^2 + 2/5*T + 1/5 - sage: C = codes.databases.best_linear_code_in_guava(6,3,GF(2)) # optional - gap_packages (Guava package) - sage: C.minimum_distance() # optional - gap_packages (Guava package) + + sage: C = codes.databases.best_linear_code_in_guava(6, 3, GF(2)) # optional - gap_package_guava + sage: C.minimum_distance() # optional - gap_package_guava 3 - sage: C.zeta_polynomial() # optional - gap_packages (Guava package) + sage: C.zeta_polynomial() # optional - gap_package_guava 2/5*T^2 + 2/5*T + 1/5 + sage: C = codes.HammingCode(GF(2), 4) sage: C.zeta_polynomial() 16/429*T^6 + 16/143*T^5 + 80/429*T^4 + 32/143*T^3 + 30/143*T^2 + 2/13*T + 1/13 + sage: F. = GF(4,"z") sage: MS = MatrixSpace(F, 3, 6) sage: G = MS([[1,0,0,1,z,z],[0,1,0,z,1,z],[0,0,1,z,z,1]]) @@ -2601,7 +2604,7 @@ class LinearCodeSyndromeDecoder(Decoder): We build a first syndrome decoder, and pick a ``maximum_error_weight`` smaller than both the covering radius and half the minimum distance:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 1) + sage: D = C.decoder("Syndrome", maximum_error_weight=1) sage: D.decoder_type() {'always-succeed', 'bounded_distance', 'hard-decision'} sage: D.decoding_radius() @@ -2614,7 +2617,7 @@ class LinearCodeSyndromeDecoder(Decoder): ``maximum_error_weight`` is chosen to be bigger than half the minimum distance, but lower than the covering radius:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 3) + sage: D = C.decoder("Syndrome", maximum_error_weight=3) sage: D.decoder_type() {'bounded_distance', 'hard-decision', 'might-error'} sage: D.decoding_radius() @@ -2628,10 +2631,10 @@ class LinearCodeSyndromeDecoder(Decoder): And now, we build a third syndrome decoder, whose ``maximum_error_weight`` is bigger than both the covering radius and half the minimum distance:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 5) # long time - sage: D.decoder_type() # long time + sage: D = C.decoder("Syndrome", maximum_error_weight=5) # long time + sage: D.decoder_type() # long time {'complete', 'hard-decision', 'might-error'} - sage: D.decoding_radius() # long time + sage: D.decoding_radius() # long time 4 In that case, the decoder might still return an unexpected codeword, but diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index ce848a94f10..2ae0879fa74 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -1004,8 +1004,8 @@ def is_self_orthogonal(self): sage: C = codes.HammingCode(GF(2), 3) sage: C.is_self_orthogonal() False - sage: C = codes.QuasiQuadraticResidueCode(11) # optional - gap_packages (Guava package) - sage: C.is_self_orthogonal() # optional - gap_packages (Guava package) + sage: C = codes.QuasiQuadraticResidueCode(11) # optional - gap_package_guava + sage: C.is_self_orthogonal() # optional - gap_package_guava True """ return self.is_subcode(self.dual_code()) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 0f43e6bbcfe..79690ff7305 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -277,7 +277,7 @@ lazy_import('sage.combinat.binary_recurrence_sequences', 'BinaryRecurrenceSequence') lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace') -lazy_import('sage.combinat.k_regular_sequence', 'kRegularSequenceSpace') +lazy_import('sage.combinat.regular_sequence', 'RegularSequenceRing') # Six Vertex Model lazy_import('sage.combinat.six_vertex_model', 'SixVertexModel') diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index 98774d77a42..057af5c969c 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -245,8 +245,8 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch Check that the constructor using gap also works:: - sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) - sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) + sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_package_design + sage: BD.is_t_design(return_parameters=True) # optional - gap_package_design (True, (2, 7, 3, 1)) """ try: @@ -934,12 +934,12 @@ def WittDesign(n): EXAMPLES:: - sage: BD = designs.WittDesign(9) # optional - gap_packages (design package) - sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) + sage: BD = designs.WittDesign(9) # optional - gap_package_design + sage: BD.is_t_design(return_parameters=True) # optional - gap_package_design (True, (2, 9, 3, 1)) - sage: BD # optional - gap_packages (design package) + sage: BD # optional - gap_package_design Incidence structure with 9 points and 12 blocks - sage: print(BD) # optional - gap_packages (design package) + sage: print(BD) # optional - gap_package_design Incidence structure with 9 points and 12 blocks """ libgap.load_package("design") diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 3e095e619ee..ebefb6bc669 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -4464,9 +4464,9 @@ def HigmanSimsDesign(): EXAMPLES:: - sage: H = designs.HigmanSimsDesign(); H # optional - gap_packages + sage: H = designs.HigmanSimsDesign(); H # optional - gap_package_design Incidence structure with 176 points and 176 blocks - sage: H.is_t_design(return_parameters=1) # optional - gap_packages + sage: H.is_t_design(return_parameters=1) # optional - gap_package_design (True, (2, 176, 50, 14)) Make sure that the automorphism group of this designs is isomorphic to the @@ -4475,9 +4475,9 @@ def HigmanSimsDesign(): first of those permutation groups acts on 176 points, while the second acts on 100:: - sage: gH = H.automorphism_group() # optional - gap_packages - sage: gG = graphs.HigmanSimsGraph().automorphism_group() # optional - gap_packages - sage: gG.is_isomorphic(gG) # long time # optional - gap_packages + sage: gH = H.automorphism_group() # optional - gap_package_design + sage: gG = graphs.HigmanSimsGraph().automorphism_group() # optional - gap_package_design + sage: gG.is_isomorphic(gG) # long time, optional - gap_package_design True REFERENCE: diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index a9572e119c0..8bf7f14fd0b 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -4,7 +4,7 @@ This module gathers all designs that can be reached through ``designs.``. Example with the Witt design on 24 points:: - sage: designs.WittDesign(24) # optional - gap_packages + sage: designs.WittDesign(24) # optional - gap_package_design Incidence structure with 24 points and 759 blocks Or a Steiner Triple System on 19 points:: diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 83927348b05..5252b3be769 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1075,7 +1075,7 @@ def _libgap_(self): EXAMPLES:: sage: D = IncidenceStructure(4, [[0,2],[1,2,3],[2,3]]) - sage: D._libgap_() # optional - gap_packages + sage: D._libgap_() # optional - gap_package_design rec( blocks := [ [ 1, 3 ], [ 2, 3, 4 ], [ 3, 4 ] ], isBlockDesign := true, v := 4 ) """ @@ -1538,13 +1538,13 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): Some examples of Witt designs that need the gap database:: - sage: BD = designs.WittDesign(9) # optional - gap_packages - sage: BD.is_t_design(2,9,3,1) # optional - gap_packages + sage: BD = designs.WittDesign(9) # optional - gap_package_design + sage: BD.is_t_design(2,9,3,1) # optional - gap_package_design True - sage: W12 = designs.WittDesign(12) # optional - gap_packages - sage: W12.is_t_design(5,12,6,1) # optional - gap_packages + sage: W12 = designs.WittDesign(12) # optional - gap_package_design + sage: W12.is_t_design(5,12,6,1) # optional - gap_package_design True - sage: W12.is_t_design(4) # optional - gap_packages + sage: W12.is_t_design(4) # optional - gap_package_design True Further examples:: @@ -1797,12 +1797,12 @@ def dual(self, algorithm=None): Incidence structure with 4 points and 3 blocks sage: D.dual() # needs sage.modules Incidence structure with 3 points and 4 blocks - sage: print(D.dual(algorithm="gap")) # optional - gap_packages + sage: print(D.dual(algorithm="gap")) # optional - gap_package_design Incidence structure with 3 points and 4 blocks sage: blocks = [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]] sage: BD = IncidenceStructure(7, blocks, name="FanoPlane"); BD Incidence structure with 7 points and 7 blocks - sage: print(BD.dual(algorithm="gap")) # optional - gap_packages + sage: print(BD.dual(algorithm="gap")) # optional - gap_package_design Incidence structure with 7 points and 7 blocks sage: BD.dual() # needs sage.modules Incidence structure with 7 points and 7 blocks diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index b36d23f0162..5c9a90afbcd 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -278,8 +278,8 @@ def twograph_descendant(G, v, name=None): one of s.r.g.'s from the :mod:`database `:: sage: from sage.combinat.designs.twographs import twograph_descendant - sage: A = graphs.strongly_regular_graph(280,135,70) # optional - gap_packages internet - sage: twograph_descendant(A, 0).is_strongly_regular(parameters=True) # optional - gap_packages internet + sage: A = graphs.strongly_regular_graph(280,135,70) # optional - gap_package_design internet + sage: twograph_descendant(A, 0).is_strongly_regular(parameters=True) # optional - gap_package_design internet (279, 150, 85, 75) TESTS:: diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 202bcbb0974..cf8d18c1764 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -1128,7 +1128,7 @@ def __eq__(self, other): sage: G1 == G2 False """ - return (type(self) == type(other) and + return (type(self) is type(other) and self.rule == other.rule and self._lambda == other._lambda and self._mu == other._mu and diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 3822d94f2a4..969aedb770c 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -574,7 +574,7 @@ def dual(self): sage: H.is_isomorphic( H.dual() ) # optional - sage.combinat False """ - H = self.reverse() + H = self.reverse(immutable=False) H.relabel(perm=list(range(H.num_verts() - 1, -1, -1)), inplace=True) return HasseDiagram(H) @@ -1068,28 +1068,27 @@ def moebius_function_matrix(self, algorithm='cython'): TESTS:: - sage: H.moebius_function_matrix().is_immutable() # optional - sage.libs.flint sage.modules + sage: # needs sage.modules sage.libs.flint + sage: H.moebius_function_matrix().is_immutable() True - sage: hasattr(H,'_moebius_function_matrix') # optional - sage.libs.flint sage.modules + sage: hasattr(H,'_moebius_function_matrix') True - - sage: H.moebius_function == H._moebius_function_from_matrix # optional - sage.libs.flint sage.modules + sage: H.moebius_function == H._moebius_function_from_matrix True - sage: H = posets.TamariLattice(3)._hasse_diagram - sage: M = H.moebius_function_matrix('matrix'); M # optional - sage.modules + sage: M = H.moebius_function_matrix('matrix'); M [ 1 -1 -1 0 1] [ 0 1 0 0 -1] [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 1] - sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.modules - sage: H.moebius_function_matrix('cython') == M # optional - sage.libs.flint sage.modules + sage: _ = H.__dict__.pop('_moebius_function_matrix') + sage: H.moebius_function_matrix('cython') == M True - sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.libs.flint sage.modules - sage: H.moebius_function_matrix('recursive') == M # optional - sage.modules + sage: _ = H.__dict__.pop('_moebius_function_matrix') + sage: H.moebius_function_matrix('recursive') == M True - sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.modules + sage: _ = H.__dict__.pop('_moebius_function_matrix') sage: H.moebius_function_matrix('banana') Traceback (most recent call last): ... @@ -1160,25 +1159,27 @@ def coxeter_transformation(self, algorithm='cython'): EXAMPLES:: - sage: P = posets.PentagonPoset()._hasse_diagram # optional - sage.modules - sage: M = P.coxeter_transformation(); M # optional - sage.libs.flint sage.modules + sage: # needs sage.libs.flint sage.modules + sage: P = posets.PentagonPoset()._hasse_diagram + sage: M = P.coxeter_transformation(); M [ 0 0 0 0 -1] [ 0 0 0 1 -1] [ 0 1 0 0 -1] [-1 1 1 0 -1] [-1 1 0 1 -1] - sage: P.__dict__['coxeter_transformation'].clear_cache() # optional - sage.libs.flint sage.modules - sage: P.coxeter_transformation(algorithm="matrix") == M # optional - sage.libs.flint sage.modules + sage: P.__dict__['coxeter_transformation'].clear_cache() + sage: P.coxeter_transformation(algorithm="matrix") == M True TESTS:: - sage: P = posets.PentagonPoset()._hasse_diagram # optional - sage.modules - sage: M = P.coxeter_transformation() # optional - sage.libs.flint sage.modules - sage: M**8 == 1 # optional - sage.libs.flint sage.modules + sage: # needs sage.libs.flint sage.modules + sage: P = posets.PentagonPoset()._hasse_diagram + sage: M = P.coxeter_transformation() + sage: M**8 == 1 True - sage: P.__dict__['coxeter_transformation'].clear_cache() # optional - sage.libs.flint sage.modules - sage: P.coxeter_transformation(algorithm="banana") # optional - sage.libs.flint sage.modules + sage: P.__dict__['coxeter_transformation'].clear_cache() + sage: P.coxeter_transformation(algorithm="banana") Traceback (most recent call last): ... ValueError: unknown algorithm @@ -2222,24 +2223,22 @@ def antichains_iterator(self): EXAMPLES:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H.antichains_iterator() # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H.antichains_iterator() - sage: list(H.antichains_iterator()) # optional - sage.modules + sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[4],2:[3],3:[4]}) - sage: list(H.antichains_iterator()) # optional - sage.modules + sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - sage: H = HasseDiagram({0:[],1:[],2:[]}) - sage: list(H.antichains_iterator()) # optional - sage.modules + sage: list(H.antichains_iterator()) [[], [2], [1], [1, 2], [0], [0, 2], [0, 1], [0, 1, 2]] - sage: H = HasseDiagram({0:[1],1:[2],2:[3],3:[4]}) - sage: list(H.antichains_iterator()) # optional - sage.modules + sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [0]] TESTS:: @@ -2279,12 +2278,13 @@ def are_incomparable(self, i, j): EXAMPLES:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H.are_incomparable(1,2) # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H.are_incomparable(1,2) True - sage: V = H.vertices(sort=True) # optional - sage.modules - sage: [ (i,j) for i in V for j in V if H.are_incomparable(i,j)] # optional - sage.modules + sage: V = H.vertices(sort=True) + sage: [ (i,j) for i in V for j in V if H.are_incomparable(i,j)] [(1, 2), (1, 3), (2, 1), (3, 1)] """ if i == j: @@ -2304,12 +2304,13 @@ def are_comparable(self, i, j): EXAMPLES:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H.are_comparable(1,2) # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H.are_comparable(1,2) False - sage: V = H.vertices(sort=True) # optional - sage.modules - sage: [ (i,j) for i in V for j in V if H.are_comparable(i,j)] # optional - sage.modules + sage: V = H.vertices(sort=True) + sage: [ (i,j) for i in V for j in V if H.are_comparable(i,j)] [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 4), (2, 0), (2, 2), (2, 3), (2, 4), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] @@ -2331,26 +2332,27 @@ def antichains(self, element_class=list): EXAMPLES:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: A = H.antichains() # optional - sage.modules - sage: list(A) # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: A = H.antichains() + sage: list(A) [[], [0], [1], [1, 2], [1, 3], [2], [3], [4]] - sage: A.cardinality() # optional - sage.modules + sage: A.cardinality() 8 - sage: [1,3] in A # optional - sage.modules + sage: [1,3] in A True - sage: [1,4] in A # optional - sage.modules + sage: [1,4] in A False TESTS:: - sage: TestSuite(A).run() # optional - sage.modules - - sage: A = Poset()._hasse_diagram.antichains() # optional - sage.modules - sage: list(A) # optional - sage.modules + sage: # needs sage.modules + sage: TestSuite(A).run() + sage: A = Poset()._hasse_diagram.antichains() + sage: list(A) [[]] - sage: TestSuite(A).run() # optional - sage.modules + sage: TestSuite(A).run() """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets return PairwiseCompatibleSubsets(self.vertices(sort=True), @@ -2382,23 +2384,25 @@ def chains(self, element_class=list, exclude=None, conversion=None): EXAMPLES:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: A = H.chains() # optional - sage.modules - sage: list(A) # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: A = H.chains() + sage: list(A) [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] - sage: A.cardinality() # optional - sage.modules + sage: A.cardinality() 20 - sage: [1,3] in A # optional - sage.modules + sage: [1,3] in A False - sage: [1,4] in A # optional - sage.modules + sage: [1,4] in A True One can exclude some vertices:: - sage: list(H.chains(exclude=[4, 3])) # optional - sage.modules + sage: # needs sage.modules + sage: list(H.chains(exclude=[4, 3])) [[], [0], [0, 1], [0, 2], [1], [2]] The ``element_class`` keyword determines how the chains are @@ -2426,16 +2430,16 @@ def is_linear_interval(self, t_min, t_max) -> bool: This means that this interval is a total order. EXAMPLES:: - - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H.is_linear_interval(0, 4) # optional - sage.modules + sage: # needs sage.modules + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H.is_linear_interval(0, 4) False - sage: H.is_linear_interval(0, 3) # optional - sage.modules + sage: H.is_linear_interval(0, 3) True - sage: H.is_linear_interval(1, 3) # optional - sage.modules + sage: H.is_linear_interval(1, 3) False - sage: H.is_linear_interval(1, 1) # optional - sage.modules + sage: H.is_linear_interval(1, 1) True TESTS:: diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index d37e9676d7c..c21bcc899e1 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -877,7 +877,7 @@ class FinitePoset(UniqueRepresentation, Parent): Conversion to some other software is possible:: sage: P = posets.TamariLattice(3) - sage: libgap(P) # optional - gap_packages + sage: libgap(P) # optional - gap_package_qpa sage: P = Poset({1:[2],2:[]}) @@ -8828,11 +8828,11 @@ def _libgap_(self): EXAMPLES:: sage: P = posets.TamariLattice(3) - sage: libgap(P) # optional - gap_packages + sage: libgap(P) # optional - gap_package_qpa - sage: A = libgap(GF(2)).PosetAlgebra(P); A # optional - gap_packages + sage: A = libgap(GF(2)).PosetAlgebra(P); A # optional - gap_package_qpa ]/]>, (1 generator)>> - sage: A.Dimension() # optional - gap_packages + sage: A.Dimension() # optional - gap_package_qpa 13 """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index e5856aacef9..ca2f11bd6ff 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -27,27 +27,13 @@ In particular, minimization is called before checking if a series is nonzero. -.. WARNING:: - - As this code is experimental, warnings are thrown when a - recognizable series space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - Various ======= .. SEEALSO:: - :mod:`k-regular sequence `, + :mod:`k-regular sequence `, :mod:`sage.rings.cfinite_sequence`, :mod:`sage.combinat.binary_recurrence_sequences`. @@ -79,7 +65,6 @@ from functools import wraps from sage.misc.cachefunc import cached_method -from sage.misc.superseded import experimental from sage.structure.element import ModuleElement from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -1140,6 +1125,12 @@ def minimized(self): sage: all(c == d and v == w ....: for (c, v), (d, w) in islice(zip(iter(S), iter(M)), 20)) True + + TESTS:: + + sage: Rec((Matrix([[0]]), Matrix([[0]])), + ....: vector([1]), vector([0])).minimized().linear_representation() + ((), Finite family {0: [], 1: []}, ()) """ return self._minimized_right_()._minimized_left_() @@ -1291,7 +1282,7 @@ def _add_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: E @@ -1314,7 +1305,7 @@ def _add_(self, other): result = P.element_class( P, - dict((a, self.mu[a].block_sum(other.mu[a])) for a in P.alphabet()), + {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()}, vector(tuple(self.left) + tuple(other.left)), vector(tuple(self.right) + tuple(other.right))) @@ -1330,7 +1321,7 @@ def _neg_(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: -E @@ -1357,7 +1348,7 @@ def _rmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = 2 * E # indirect doctest @@ -1376,6 +1367,11 @@ def _rmul_(self, other): sage: 1 * E is E True + :: + + sage: 0 * E is Seq2.zero() + True + We test that ``_rmul_`` and ``_lmul_`` are actually called:: sage: def print_name(f): @@ -1394,9 +1390,11 @@ def _rmul_(self, other): _lmul_ 2-regular sequence 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, ... """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() return P.element_class(P, self.mu, other * self.left, self.right) def _lmul_(self, other): @@ -1414,7 +1412,7 @@ def _lmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = E * 2 # indirect doctest @@ -1433,6 +1431,11 @@ def _lmul_(self, other): sage: E * 1 is E True + :: + + sage: E * 0 is Seq2.zero() + True + The following is not tested, as `MS^i` for integers `i` does not work, thus ``vector([m])`` fails. (See :trac:`21317` for details.) @@ -1449,9 +1452,11 @@ def _lmul_(self, other): sage: M # not tested sage: M.linear_representation() # not tested """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() return P.element_class(P, self.mu, self.left, self.right * other) @minimize_result @@ -1477,7 +1482,7 @@ def hadamard_product(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) @@ -1557,8 +1562,7 @@ def tensor_product(left, right): return T result = P.element_class( P, - dict((a, tensor_product(self.mu[a], other.mu[a])) - for a in P.alphabet()), + {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()}, vector(tensor_product(Matrix(self.left), Matrix(other.left))), vector(tensor_product(Matrix(self.right), Matrix(other.right)))) @@ -1722,7 +1726,6 @@ def __normalize__(cls, return (coefficient_ring, indices, category, minimize_results) - @experimental(issue_number=21202) def __init__(self, coefficient_ring, indices, category, minimize_results): r""" See :class:`RecognizableSeriesSpace` for details. @@ -1952,6 +1955,59 @@ def some_elements(self, **kwds): break yield self(mu, *LR, **kwds) + @cached_method + def _zero_(self): + r""" + Return the zero element of this :class:`RecognizableSeriesSpace`, + i.e. the unique neutral element for `+`. + + TESTS:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: Z = Rec._zero_(); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + from sage.sets.family import Family + + return self.element_class( + self, Family(self.alphabet(), lambda a: Matrix()), + vector([]), vector([])) + + @cached_method + def one(self): + r""" + Return the one element of this :class:`RecognizableSeriesSpace`, + i.e. the embedding of the one of the coefficient ring into + this :class:`RecognizableSeriesSpace`. + + EXAMPLES:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: O = Rec.one(); O + [] + ... + sage: O.linear_representation() + ((1), Finite family {0: [0], 1: [0]}, (1)) + + TESTS:: + + sage: Rec.one() is Rec.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + len(self.alphabet())*[Matrix([[zero]])], + vector([one]), + vector([one])) + @cached_method def one_hadamard(self): r""" @@ -1979,7 +2035,7 @@ def one_hadamard(self): from sage.modules.free_module_element import vector one = self.coefficient_ring()(1) - return self(dict((a, Matrix([[one]])) for a in self.alphabet()), + return self({a: Matrix([[one]]) for a in self.alphabet()}, vector([one]), vector([one])) def _element_constructor_(self, data, @@ -2006,6 +2062,19 @@ def _element_constructor_(self, data, sage: Rec(S) is S True + :: + + sage: A = Rec(42); A + 42*[] + ... + sage: A.linear_representation() + ((42), Finite family {0: [0], 1: [0]}, (1)) + sage: Z = Rec(0); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + + :: + sage: Rec((M0, M1)) Traceback (most recent call last): ... @@ -2024,20 +2093,18 @@ def _element_constructor_(self, data, ValueError: left or right vector is None """ if isinstance(data, int) and data == 0: - from sage.matrix.constructor import Matrix - from sage.modules.free_module_element import vector - from sage.sets.family import Family - - return self.element_class( - self, Family(self.alphabet(), lambda a: Matrix()), - vector([]), vector([])) + return self._zero_() - if type(data) == self.element_class and data.parent() == self: + if isinstance(data, self.element_class) and data.parent() == self: element = data elif isinstance(data, RecognizableSeries): element = self.element_class(self, data.mu, data.left, data.right) + elif data in self.coefficient_ring(): + c = self.coefficient_ring()(data) + return c * self.one() + else: mu = data if left is None or right is None: diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/regular_sequence.py similarity index 91% rename from src/sage/combinat/k_regular_sequence.py rename to src/sage/combinat/regular_sequence.py index 6a1a2dabf71..afb83bed6f7 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -1,26 +1,11 @@ # sage.doctest: optional - sage.combinat sage.modules sage.symbolic r""" -`k`-regular Sequences +`k`-regular sequences An introduction and formal definition of `k`-regular sequences can be found, for example, on the :wikipedia:`k-regular_sequence` or in [AS2003]_. - -.. WARNING:: - - As this code is experimental, warnings are thrown when a - `k`-regular sequence space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - :: sage: import logging @@ -35,7 +20,7 @@ The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies `S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S @@ -125,7 +110,7 @@ def pad_right(T, length, zero=0): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import pad_right + sage: from sage.combinat.regular_sequence import pad_right sage: pad_right((1, 2, 3), 10) (1, 2, 3, 0, 0, 0, 0, 0, 0, 0) sage: pad_right((1, 2, 3), 2) @@ -162,7 +147,7 @@ def value(D, k): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import value + sage: from sage.combinat.regular_sequence import value sage: value(42.digits(7), 7) 42 """ @@ -172,11 +157,11 @@ def value(D, k): class DegeneratedSequenceError(RuntimeError): r""" Exception raised if a degenerated sequence - (see :meth:`~kRegularSequence.is_degenerated`) is detected. + (see :meth:`~RegularSequence.is_degenerated`) is detected. EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) Traceback (most recent call last): ... @@ -188,14 +173,14 @@ class DegeneratedSequenceError(RuntimeError): pass -class kRegularSequence(RecognizableSeries): +class RegularSequence(RecognizableSeries): def __init__(self, parent, mu, left=None, right=None): r""" A `k`-regular sequence. INPUT: - - ``parent`` -- an instance of :class:`kRegularSequenceSpace` + - ``parent`` -- an instance of :class:`RegularSequenceRing` - ``mu`` -- a family of square matrices, all of which have the same dimension. The indices of this family are `0,...,k-1`. @@ -213,7 +198,7 @@ def __init__(self, parent, mu, left=None, right=None): from the right to the matrix product. If ``None``, then this multiplication is skipped. - When created via the parent :class:`kRegularSequenceSpace`, then + When created via the parent :class:`RegularSequenceRing`, then the following option is available. - ``allow_degenerated_sequence`` -- (default: ``False``) a boolean. If set, then @@ -224,7 +209,7 @@ def __init__(self, parent, mu, left=None, right=None): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), ....: vector([1, 0]), vector([0, 1])); S 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... @@ -244,8 +229,8 @@ def __init__(self, parent, mu, left=None, right=None): .. SEEALSO:: - :doc:`k-regular sequence `, - :class:`kRegularSequenceSpace`. + :doc:`k-regular sequence `, + :class:`RegularSequenceRing`. TESTS:: @@ -262,7 +247,7 @@ def _repr_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: s = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), ....: vector([1, 0]), vector([0, 1])) sage: repr(s) # indirect doctest @@ -288,7 +273,7 @@ def coefficient_of_n(self, n, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S[7] @@ -308,7 +293,7 @@ def coefficient_of_n(self, n, **kwds): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: W = Seq2.indices() sage: M0 = Matrix([[1, 0], [0, 1]]) sage: M1 = Matrix([[0, -1], [1, 2]]) @@ -330,7 +315,7 @@ def __iter__(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: from itertools import islice @@ -357,7 +342,7 @@ def is_degenerated(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) # indirect doctest Traceback (most recent call last): ... @@ -390,7 +375,7 @@ def _error_if_degenerated_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), # indirect doctest ....: left=vector([0, 1]), right=vector([1, 0])) Traceback (most recent call last): @@ -425,7 +410,7 @@ def regenerated(self): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` ALGORITHM: @@ -433,7 +418,7 @@ def regenerated(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) The following linear representation of `S` is chosen badly (is degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on @@ -517,14 +502,14 @@ def transposed(self, allow_degenerated_sequence=False): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` Each of the matrices in :meth:`mu ` is transposed. Additionally the vectors :meth:`left ` and :meth:`right ` are switched. EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), ....: left=vector([0, 1]), right=vector([1, 0]), ....: allow_degenerated_sequence=True) @@ -568,7 +553,7 @@ def _minimized_right_(self): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. SEEALSO:: @@ -576,7 +561,7 @@ def _minimized_right_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), # indirect doctest ....: left=vector([1, 0]), right=vector([0, 1])).minimized() 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... @@ -606,7 +591,7 @@ def subsequence(self, a, b): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -615,7 +600,7 @@ def subsequence(self, a, b): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) We consider the sequence `C` with `C(n) = n` and the following linear representation @@ -879,7 +864,7 @@ def shift_left(self, b=1, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -888,7 +873,7 @@ def shift_left(self, b=1, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), ....: vector([1, 0]), vector([0, 1])); C 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... @@ -925,7 +910,7 @@ def shift_right(self, b=1, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -934,7 +919,7 @@ def shift_right(self, b=1, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), ....: vector([1, 0]), vector([0, 1])); C 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... @@ -973,7 +958,7 @@ def backward_differences(self, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -981,7 +966,7 @@ def backward_differences(self, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), ....: vector([1, 0]), vector([0, 1])) sage: C @@ -1014,11 +999,11 @@ def forward_differences(self, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), ....: vector([1, 0]), vector([0, 1])) sage: C @@ -1037,6 +1022,115 @@ def forward_differences(self, **kwds): """ return self.subsequence(1, {1: 1, 0: -1}, **kwds) + @minimize_result + def _mul_(self, other): + r""" + Return the product of this `k`-regular sequence with ``other``, + where the multiplication is convolution of power series. + + The operator `*` is mapped to :meth:`convolution`. + + INPUT: + + - ``other`` -- a :class:`RegularSequence` + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + ALGORITHM: + + See pdf attached to + `github pull request #35894 `_ + which contains a draft describing the details of the used algorithm. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + + We can build the convolution (in the sense of power-series) of `E` by + itself via:: + + sage: E.convolution(E) + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + This is the same as using multiplication operator:: + + sage: E * E + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + Building :meth:`partial_sums` can also be seen as a convolution:: + + sage: o = Seq2.one_hadamard() + sage: E * o + 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... + sage: E * o == E.partial_sums(include_n=True) + True + + TESTS:: + + sage: E * o == o * E + True + """ + from sage.arith.srange import srange + from sage.matrix.constructor import Matrix + from sage.matrix.special import zero_matrix + from sage.modules.free_module_element import vector + + P = self.parent() + k = P.k + + def tensor_product(left, right): + T = left.tensor_product(right) + T.subdivide() + return T + + matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s]) + for s in srange(0, r+1)) + for r in P.alphabet()} + matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s]) + for s in srange(r+1, k)) + for r in P.alphabet()} + left = vector(tensor_product(Matrix(self.left), Matrix(other.left))) + right = vector(tensor_product(Matrix(self.right), Matrix(other.right))) + + def linear_representation_morphism_recurrence_order_1(C, D): + r""" + Return the morphism of a linear representation + for the sequence `z_n` satisfying + `z_{kn+r} = C_r z_n + D_r z_{n-1}`. + """ + Z = zero_matrix(C[0].dimensions()[0]) + + def blocks(r): + upper = list([C[s], D[s], Z] + for s in reversed(srange(max(0, r-2), r+1))) + lower = list([Z, C[s], D[s]] + for s in reversed(srange(k-3+len(upper), k))) + return upper + lower + + return {r: Matrix.block(blocks(r)) for r in P.alphabet()} + + result = P.element_class( + P, + linear_representation_morphism_recurrence_order_1(matrices_0, + matrices_1), + vector(list(left) + (2*len(list(left)))*[0]), + vector(list(right) + (2*len(list(right)))*[0])) + + return result + + convolution = _mul_ + @minimize_result def partial_sums(self, include_n=False): r""" @@ -1057,11 +1151,11 @@ def partial_sums(self, include_n=False): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) @@ -1101,7 +1195,7 @@ def partial_sums(self, include_n=False): sage: H 2-regular sequence 0, 2, 10, 16, 50, 62, 80, 98, 250, 274, ... - We can :meth:`~kRegularSequenceSpace.guess` the correct representation:: + We can :meth:`~RegularSequenceRing.guess` the correct representation:: sage: from itertools import islice sage: L = []; ps = 0 @@ -1141,20 +1235,36 @@ def partial_sums(self, include_n=False): 1: [0 0] [0 1]}, (1, 1)) + sage: P = E.partial_sums(minimize=False) sage: P.linear_representation() - ((1, 0, -1, 0), - Finite family {0: [ 0 1| 0 0] - [ 0 2| 0 -1] - [-----+-----] - [ 0 0| 0 1] - [ 0 0| 0 1], - 1: [0 1|0 0] + ((1, 0, 0, 0), + Finite family {0: [0 1|0 0] + [0 2|0 0] + [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] + [0 0|0 0] + [0 0|0 1]}, + (0, 0, 1, 1)) + + sage: P = E.partial_sums(include_n=True, minimize=False) + sage: P.linear_representation() + ((1, 0, 1, 0), + Finite family {0: [0 1|0 0] [0 2|0 0] [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] [0 0|0 0] [0 0|0 1]}, - (1, 1, 1, 1)) + (0, 0, 1, 1)) """ from itertools import chain from sage.matrix.constructor import Matrix @@ -1165,37 +1275,41 @@ def partial_sums(self, include_n=False): A = P.alphabet() k = P.k dim = self.dimension() - - B = {r: sum(self.mu[a] for a in A[r:]) for r in A} Z = zero_matrix(dim) - B[k] = Z + + z = A[0] + assert z == 0 + B = {z: Z} + for r in A: + B[r+1] = B[r] + self.mu[r] + C = B[k] result = P.element_class( P, - {r: Matrix.block([[B[0], -B[r + 1]], [Z, self.mu[r]]]) for r in A}, + {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A}, vector(chain(self.left, - (dim * (0,) if include_n else -self.left))), - vector(chain(self.right, self.right))) + (dim * (0,) if not include_n else self.left))), + vector(chain(dim * (0,), self.right))) return result -def _pickle_kRegularSequenceSpace(k, coefficients, category): +def _pickle_RegularSequenceRing(k, coefficients, category): r""" Pickle helper. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: from sage.combinat.k_regular_sequence import _pickle_kRegularSequenceSpace - sage: _pickle_kRegularSequenceSpace( + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: from sage.combinat.regular_sequence import _pickle_RegularSequenceRing + sage: _pickle_RegularSequenceRing( ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category()) Space of 2-regular sequences over Integer Ring """ - return kRegularSequenceSpace(k, coefficients, category=category) + return RegularSequenceRing(k, coefficients, category=category) -class kRegularSequenceSpace(RecognizableSeriesSpace): +class RegularSequenceRing(RecognizableSeriesSpace): r""" The space of `k`-regular Sequences over the given ``coefficient_ring``. @@ -1210,42 +1324,49 @@ class kRegularSequenceSpace(RecognizableSeriesSpace): EXAMPLES:: - sage: kRegularSequenceSpace(2, ZZ) + sage: RegularSequenceRing(2, ZZ) Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) + sage: RegularSequenceRing(3, ZZ) Space of 3-regular sequences over Integer Ring .. SEEALSO:: - :doc:`k-regular sequence `, - :class:`kRegularSequence`. + :doc:`k-regular sequence `, + :class:`RegularSequence`. """ - Element = kRegularSequence + Element = RegularSequence @classmethod - def __normalize__(cls, k, coefficient_ring, **kwds): + def __normalize__(cls, k, + coefficient_ring, + category=None, + **kwds): r""" Normalizes the input in order to ensure a unique representation. - For more information see :class:`kRegularSequenceSpace`. + For more information see :class:`RegularSequenceRing`. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2.category() - Category of modules over Integer Ring + Category of algebras over Integer Ring sage: Seq2.alphabet() {0, 1} """ from sage.arith.srange import srange + from sage.categories.algebras import Algebras + category = category or Algebras(coefficient_ring) nargs = super().__normalize__(coefficient_ring, - alphabet=srange(k), **kwds) + alphabet=srange(k), + category=category, + **kwds) return (k,) + nargs def __init__(self, k, *args, **kwds): r""" - See :class:`kRegularSequenceSpace` for details. + See :class:`RegularSequenceRing` for details. INPUT: @@ -1256,22 +1377,22 @@ def __init__(self, k, *args, **kwds): TESTS:: - sage: kRegularSequenceSpace(2, ZZ) + sage: RegularSequenceRing(2, ZZ) Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) + sage: RegularSequenceRing(3, ZZ) Space of 3-regular sequences over Integer Ring :: sage: from itertools import islice - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: TestSuite(Seq2).run( # long time ....: elements=tuple(islice(Seq2.some_elements(), 4))) .. SEEALSO:: - :doc:`k-regular sequence `, - :class:`kRegularSequence`. + :doc:`k-regular sequence `, + :class:`RegularSequence`. """ self.k = k super().__init__(*args, **kwds) @@ -1282,11 +1403,11 @@ def __reduce__(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: loads(dumps(Seq2)) # indirect doctest Space of 2-regular sequences over Integer Ring """ - return _pickle_kRegularSequenceSpace, \ + return _pickle_RegularSequenceRing, \ (self.k, self.coefficient_ring(), self.category()) def _repr_(self): @@ -1297,7 +1418,7 @@ def _repr_(self): TESTS:: - sage: repr(kRegularSequenceSpace(2, ZZ)) # indirect doctest + sage: repr(RegularSequenceRing(2, ZZ)) # indirect doctest 'Space of 2-regular sequences over Integer Ring' """ return 'Space of {}-regular sequences over {}'.format(self.k, self.base()) @@ -1315,7 +1436,7 @@ def _n_to_index_(self, n): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2._n_to_index_(6) word: 011 sage: Seq2._n_to_index_(-1) @@ -1331,6 +1452,39 @@ def _n_to_index_(self, n): except OverflowError: raise ValueError('value {} of index is negative'.format(n)) from None + @cached_method + def one(self): + r""" + Return the one element of this :class:`RegularSequenceRing`, + i.e. the unique neutral element for `*` and also + the embedding of the one of the coefficient ring into + this :class:`RegularSequenceRing`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: O = Seq2.one(); O + 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + sage: O.linear_representation() + ((1), Finite family {0: [1], 1: [0]}, (1)) + + TESTS:: + + sage: Seq2.one() is Seq2.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + [Matrix([[one]])] + + (self.k-1)*[Matrix([[zero]])], + vector([one]), + vector([one])) + def some_elements(self): r""" Return some elements of this `k`-regular sequence. @@ -1343,7 +1497,7 @@ def some_elements(self): EXAMPLES:: - sage: tuple(kRegularSequenceSpace(2, ZZ).some_elements()) + sage: tuple(RegularSequenceRing(2, ZZ).some_elements()) (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 2-regular sequence 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, ..., 2-regular sequence 1, 1, 0, 1, -1, 0, 0, 1, -2, -1, ..., @@ -1356,18 +1510,18 @@ def some_elements(self): """ return iter(element.regenerated() for element - in super(kRegularSequenceSpace, self).some_elements( + in super(RegularSequenceRing, self).some_elements( allow_degenerated_sequence=True)) def _element_constructor_(self, *args, **kwds): r""" Return a `k`-regular sequence. - See :class:`kRegularSequenceSpace` for details. + See :class:`RegularSequenceRing` for details. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) Traceback (most recent call last): ... @@ -1383,7 +1537,7 @@ def _element_constructor_(self, *args, **kwds): 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... """ allow_degenerated_sequence = kwds.pop('allow_degenerated_sequence', False) - element = super(kRegularSequenceSpace, self)._element_constructor_(*args, **kwds) + element = super(RegularSequenceRing, self)._element_constructor_(*args, **kwds) if not allow_degenerated_sequence: element._error_if_degenerated_() return element @@ -1412,7 +1566,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` ALGORITHM: @@ -1449,7 +1603,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): Let us guess a `2`-linear representation for `s(n)`:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: import logging sage: logging.getLogger().setLevel(logging.INFO) sage: S1 = Seq2.guess(s); S1 @@ -1539,7 +1693,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): sage: S.is_degenerated() True - However, we can :meth:`~kRegularSequenceSpace.guess` a `2`-regular sequence of dimension `2`:: + However, we can :meth:`~RegularSequenceRing.guess` a `2`-regular sequence of dimension `2`:: sage: G = Seq2.guess(lambda n: S[n]) sage: G @@ -1582,7 +1736,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): 1: [1]}, (1)) - We :meth:`~kRegularSequenceSpace.guess` some partial sums sequences:: + We :meth:`~RegularSequenceRing.guess` some partial sums sequences:: sage: S = Seq2((Matrix([1]), Matrix([2])), vector([1]), vector([1])) sage: S @@ -1607,7 +1761,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): :: - sage: Seq3 = kRegularSequenceSpace(3, QQ) + sage: Seq3 = RegularSequenceRing(3, QQ) sage: S = Seq3((Matrix([1]), Matrix([3]), Matrix([2])), vector([1]), vector([1])) sage: S 3-regular sequence 1, 3, 2, 3, 9, 6, 2, 6, 4, 3, ... @@ -1640,7 +1794,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): :: - sage: R = kRegularSequenceSpace(2, QQ) + sage: R = RegularSequenceRing(2, QQ) sage: one = R.one_hadamard() sage: S = R.guess(lambda n: sum(n.bits()), sequence=one) + one sage: T = R.guess(lambda n: n*n, sequence=S, n_verify=4); T @@ -1844,7 +1998,7 @@ def from_recurrence(self, *args, **kwds): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -1876,7 +2030,7 @@ def from_recurrence(self, *args, **kwds): + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some coefficients `c_{r,j}` from the (semi)ring ``coefficients`` - of the corresponding :class:`kRegularSequenceSpace`, valid + of the corresponding :class:`RegularSequenceRing`, valid for all integers `n \geq \text{offset}` for some integer `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and there is an equation of this form (with the same @@ -1926,13 +2080,13 @@ def from_recurrence(self, *args, **kwds): in [HKL2022]_, Corollary D. All inhomogeneities have to be regular sequences from ``self`` or elements of ``coefficient_ring``. - OUTPUT: a :class:`kRegularSequence` + OUTPUT: a :class:`RegularSequence` EXAMPLES: Stern--Brocot Sequence:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -2006,7 +2160,7 @@ def from_recurrence(self, *args, **kwds): Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: - sage: Seq2 = kRegularSequenceSpace(2, QQ) + sage: Seq2 = RegularSequenceRing(2, QQ) sage: P = Seq2.from_recurrence([ ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), @@ -2189,8 +2343,8 @@ class RecurrenceParser(): the construction of a `k`-linear representation for the sequence satisfying these recurrence relations. - This is used by :meth:`kRegularSequenceSpace.from_recurrence` - to construct a :class:`kRegularSequence`. + This is used by :meth:`RegularSequenceRing.from_recurrence` + to construct a :class:`RegularSequence`. """ def __init__(self, k, coefficient_ring): @@ -2204,37 +2358,37 @@ def __init__(self, k, coefficient_ring): - ``coefficient_ring`` -- a ring. These are the same parameters used when creating - a :class:`kRegularSequenceSpace`. + a :class:`RegularSequenceRing`. TESTS:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RecurrenceParser(2, ZZ) - + """ self.k = k self.coefficient_ring = coefficient_ring def parse_recurrence(self, equations, function, var): r""" - Parse recurrence relations as admissible in :meth:`kRegularSequenceSpace.from_recurrence`. + Parse recurrence relations as admissible in :meth:`RegularSequenceRing.from_recurrence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a tuple consisting of - - ``M``, ``m`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``M``, ``m`` -- see :meth:`RegularSequenceRing.from_recurrence` - - ``coeffs`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``coeffs`` -- see :meth:`RegularSequenceRing.from_recurrence` - - ``initial_values`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``initial_values`` -- see :meth:`RegularSequenceRing.from_recurrence` EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -2259,7 +2413,7 @@ def parse_recurrence(self, equations, function, var): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -2604,7 +2758,7 @@ def parse_recurrence(self, equations, function, var): This results in giving the correct (see :trac:`33158`) minimization in:: - sage: Seq2 = kRegularSequenceSpace(2, QQ) + sage: Seq2 = RegularSequenceRing(2, QQ) sage: P = Seq2.from_recurrence(equations, f, n) sage: P 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... @@ -2804,18 +2958,18 @@ def parse_one_summand(summand, eq): def parse_direct_arguments(self, M, m, coeffs, initial_values): r""" Check whether the direct arguments as admissible in - :meth:`kRegularSequenceSpace.from_recurrence` are valid. + :meth:`RegularSequenceRing.from_recurrence` are valid. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a tuple consisting of the input parameters EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.parse_direct_arguments(2, 1, ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, @@ -2838,7 +2992,7 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -2981,12 +3135,12 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}): r""" Determine parameters from recurrence relations as admissible in - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a namedtuple ``recurrence_rules`` consisting of @@ -3009,7 +3163,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.parameters(2, 1, ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, @@ -3026,7 +3180,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS:: @@ -3050,7 +3204,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) :: - sage: Seq3 = kRegularSequenceSpace(3, ZZ) + sage: Seq3 = RegularSequenceRing(3, ZZ) sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, ....: {0: Seq3.zero()}) Traceback (most recent call last): @@ -3128,12 +3282,12 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " f"integers between 0 and {k**M - 1}.") - Seq = kRegularSequenceSpace(k, coefficient_ring) + Seq = RegularSequenceRing(k, coefficient_ring) inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() for i in inhomogeneities if inhomogeneities[i] in coefficient_ring}) invalid = {i: inhomogeneities[i] for i in inhomogeneities - if not (isinstance(inhomogeneities[i].parent(), kRegularSequenceSpace) and + if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and inhomogeneities[i].parent().k == k)} if invalid: raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " @@ -3177,7 +3331,7 @@ def values(self, *, M, m, l, u, ll, coeffs, initial_values, last_value_needed, offset, inhomogeneities): r""" Determine enough values of the corresponding recursive sequence by - applying the recurrence relations given in :meth:`kRegularSequenceSpace.from_recurrence` + applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence` to the values given in ``initial_values``. INPUT: @@ -3189,7 +3343,7 @@ def values(self, *, M, m, l, u, ll, coeffs, see [HKL2022]_, Theorem A - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the - coefficient `c_{r,j}` as given in :meth:`kRegularSequenceSpace.from_recurrence`. + coefficient `c_{r,j}` as given in :meth:`RegularSequenceRing.from_recurrence`. If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, then it is assumed to be zero. @@ -3211,7 +3365,7 @@ def values(self, *, M, m, l, u, ll, coeffs, Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, @@ -3222,7 +3376,7 @@ def values(self, *, M, m, l, u, ll, coeffs, .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -3303,7 +3457,7 @@ def values(self, *, M, m, l, u, ll, coeffs, :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: RP.values(M=1, m=0, l=0, u=0, ll=0, ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, ....: last_value_needed=10, offset=0, @@ -3397,7 +3551,7 @@ def ind(self, M, m, ll, uu): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.ind(3, 1, -3, 3) {(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1, @@ -3410,7 +3564,7 @@ def ind(self, M, m, ll, uu): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.arith.srange import srange @@ -3460,9 +3614,9 @@ def shifted_inhomogeneities(self, recurrence_rules): EXAMPLES:: sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S @@ -3495,7 +3649,7 @@ def shifted_inhomogeneities(self, recurrence_rules): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -3528,7 +3682,7 @@ def shifted_inhomogeneities(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.arith.srange import srange from sage.functions.other import floor @@ -3564,7 +3718,7 @@ def v_eval_n(self, recurrence_rules, n): Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: SB_rules = RP.parameters( ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, @@ -3574,7 +3728,7 @@ def v_eval_n(self, recurrence_rules, n): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from itertools import chain @@ -3628,7 +3782,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): right-hand sides of the recurrence relations correspond to the entries of the matrices. :: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -3753,7 +3907,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from itertools import chain @@ -3871,7 +4025,7 @@ def left(self, recurrence_rules): EXAMPLES:: sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RRD = namedtuple('recurrence_rules_dim', ....: ['dim', 'inhomogeneities']) @@ -3881,7 +4035,7 @@ def left(self, recurrence_rules): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: RRD = namedtuple('recurrence_rules_dim', ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities']) sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5, @@ -3891,7 +4045,7 @@ def left(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.modules.free_module_element import vector @@ -3919,13 +4073,13 @@ def right(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -3974,22 +4128,22 @@ def __call__(self, *args, **kwds): given in ``equations``. This is the main method of :class:`RecurrenceParser` and - is called by :meth:`kRegularSequenceSpace.from_recurrence` - to construct a :class:`kRegularSequence`. + is called by :meth:`RegularSequenceRing.from_recurrence` + to construct a :class:`RegularSequence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a linear representation ``(left, mu, right)`` Many examples can be found in - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. TESTS:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 19bef31c3c5..9789faae487 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -455,7 +455,7 @@ def __eq__(self, other): sage: W1 == W3 False """ - return self is other or (type(self) == type(other) and + return self is other or (type(self) is type(other) and self.alphabet() == other.alphabet() and self.vector_space() == other.vector_space() and self.letters_to_steps() == other.letters_to_steps()) diff --git a/src/sage/crypto/boolean_function.pxd b/src/sage/crypto/boolean_function.pxd index 2821fb0d1b0..8a97eb875aa 100644 --- a/src/sage/crypto/boolean_function.pxd +++ b/src/sage/crypto/boolean_function.pxd @@ -1,8 +1,8 @@ cdef inline unsigned int hamming_weight(unsigned int x): # valid for 32bits - x -= (x>>1) & 0x55555555UL # 0-2 in 2 bits - x = ((x>>2) & 0x33333333UL) + (x & 0x33333333UL) # 0-4 in 4 bits - x = ((x>>4) + x) & 0x0f0f0f0fUL # 0-8 in 8 bits + x -= (x>>1) & 0x55555555UL # 0-2 in 2 bits + x = ((x>>2) & 0x33333333UL) + (x & 0x33333333UL) # 0-4 in 4 bits + x = ((x>>4) + x) & 0x0f0f0f0fUL # 0-8 in 8 bits x *= 0x01010101UL return x>>24 diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index 05ec9cfc065..13d0a043ff8 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -67,7 +67,7 @@ cdef walsh_hadamard(long *f, int ldn): cdef long n, ldm, m, mh, t1, t2, r, j, u, v n = 1 << ldn for ldm in range(1, ldn+1): - m = (1 << ldm) + m = (1 << ldm) mh = m // 2 # If this is ``for r in range(0, n, m):``, then Cython generates horrible C code for 0 <= r < n by m: @@ -101,7 +101,7 @@ cdef long yellow_code(unsigned long a): cdef unsigned long r = a while(s): sig_check() - r ^= ( (r&m) << s ) + r ^= (r&m) << s s >>= 1 m ^= (m< L) for i in range(L): - bitset_set_to(self._truth_table, i, x[i])#int(x[i])&1) + bitset_set_to(self._truth_table, i, x[i]) # int(x[i])&1) elif isinstance(x, BooleanPolynomial): - # initialisation from a Boolean polynomial + # initialisation from a Boolean polynomial self._nvariables = ZZ(x.parent().ngens()) bitset_init(self._truth_table, (1< (1< (1<>k)&1: m *= G[k] - P+=m + P += m bitset_free(anf) return P @@ -710,7 +712,7 @@ cdef class BooleanFunction(SageObject): cdef mp_bitcnt_t i,n if self._walsh_hadamard_transform is None: - n = self._truth_table.size + n = self._truth_table.size temp = sig_malloc(sizeof(long)*n) for i in range(n): @@ -748,7 +750,7 @@ cdef class BooleanFunction(SageObject): def is_balanced(self): """ - Return True if the function takes the value True half of the time. + Return ``True`` if the function takes the value ``True`` half of the time. EXAMPLES:: @@ -764,8 +766,10 @@ cdef class BooleanFunction(SageObject): def is_symmetric(self): """ - Return True if the function is symmetric, i.e. invariant under - permutation of its input bits. Another way to see it is that the + Return ``True`` if the function is symmetric, i.e. invariant under + permutation of its input bits. + + Another way to see it is that the output depends only on the Hamming weight of the input. EXAMPLES:: @@ -781,18 +785,19 @@ cdef class BooleanFunction(SageObject): True """ cdef mp_bitcnt_t i - cdef list T = [ self(2**i-1) for i in range(self._nvariables+1) ] + cdef list T = [self(2**i-1) for i in range(self._nvariables+1)] for i in range(1 << self._nvariables): sig_check() - if T[ hamming_weight(i) ] != bitset_in(self._truth_table, i): + if T[hamming_weight(i)] != bitset_in(self._truth_table, i): return False return True def nonlinearity(self): """ - Return the nonlinearity of the function. This is the distance - to the linear functions, or the number of output ones need to - change to obtain a linear function. + Return the nonlinearity of the function. + + This is the distance to the linear functions, or the number of + output ones need to change to obtain a linear function. EXAMPLES:: @@ -808,12 +813,12 @@ cdef class BooleanFunction(SageObject): cdef long w if self._nonlinearity is None: self._nonlinearity = \ - ( (1<> 1 + ((1<> 1 return self._nonlinearity def is_bent(self): """ - Return True if the function is bent. + Return ``True`` if the function is bent. EXAMPLES:: @@ -832,7 +837,7 @@ cdef class BooleanFunction(SageObject): correlation immune of order `m`. A Boolean function is said to be correlation immune of order - `m` , if the output of the function is statistically + `m`, if the output of the function is statistically independent of the combination of any m of its inputs. EXAMPLES:: @@ -849,7 +854,7 @@ cdef class BooleanFunction(SageObject): for i in range(len(W)): sig_check() if W[i]: - c = min( c , hamming_weight(i) ) + c = min(c, hamming_weight(i)) self._correlation_immunity = ZZ(c-1) return self._correlation_immunity @@ -891,7 +896,7 @@ cdef class BooleanFunction(SageObject): cdef long i if self._autocorrelation is None: - n = self._truth_table.size + n = self._truth_table.size temp = sig_malloc(sizeof(long)*n) W = self.walsh_hadamard_transform() @@ -952,7 +957,7 @@ cdef class BooleanFunction(SageObject): cdef long a if self._absolute_indicator is None: D = self.autocorrelation() - self._absolute_indicator = max([ abs(a) for a in D[1:] ]) + self._absolute_indicator = max([abs(a) for a in D[1:]]) return self._absolute_indicator absolut_indicator = deprecated_function_alias(28001, absolute_indicator) @@ -1315,9 +1320,9 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B=BooleanFunction([0,0,1,1]) - sage: B[0]=1 - sage: B[2]=(3**17 == 9) + sage: B = BooleanFunction([0,0,1,1]) + sage: B[0] = 1 + sage: B[2] = (3**17 == 9) sage: [b for b in B] [True, False, False, True] @@ -1338,7 +1343,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B=BooleanFunction([0,1,1,1]) + sage: B = BooleanFunction([0,1,1,1]) sage: [ int(B[i]) for i in range(len(B)) ] [0, 1, 1, 1] """ @@ -1377,6 +1382,7 @@ cdef class BooleanFunction(SageObject): """ return unpickle_BooleanFunction, (self.truth_table(format='hex'),) + def unpickle_BooleanFunction(bool_list): """ Specific function to unpickle Boolean functions. @@ -1390,6 +1396,7 @@ def unpickle_BooleanFunction(bool_list): """ return BooleanFunction(bool_list) + cdef class BooleanFunctionIterator: cdef long index, last cdef BooleanFunction f diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 8f830240844..453ac488a88 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -435,7 +435,7 @@ cdef class SBox(SageObject): return self._S_list[ X] # Handle non-integer inputs: vectors, finite field elements to-integer-coercible elements - #cdef int i + # cdef int i if isinstance(X, Element): K = X.parent() if K.base_ring().characteristic() != 2: @@ -948,8 +948,6 @@ cdef class SBox(SageObject): cdef Py_ssize_t m = self.m cdef Py_ssize_t n = self.n - F = GF(2) - if X is None and Y is None: P = self.ring() X = P.gens()[:m] @@ -1056,7 +1054,7 @@ cdef class SBox(SageObject): cdef int i for i in range(2**m): x = k(vector(self.to_bits(i, m))) - l.append( (x, self(x)) ) + l.append((x, self(x))) P = PolynomialRing(k, 'x') return P.lagrange_polynomial(l) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 4844662073d..9261c69dd4b 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -281,6 +281,10 @@ def skipfile(filename, tested_optional_tags=False, *, if log: log(f"Skipping '{filename}' because it does not have one of the recognized file name extensions") return True + if if_installed and ext not in ('.py', '.pyx'): + if log: + log(f"Skipping '{filename}' because it is not the source file of a Python module") + return True if "jupyter_execute" in filename: if log: log(f"Skipping '{filename}' because it is created by the jupyter-sphinx extension for internal use and should not be tested") diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 86d7aa71174..5b4dc56c7d1 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -1071,6 +1071,28 @@ def parse(self, string, *args): '', (None, '5 # optional guava\n', 'Integer(5) # optional guava\n'), ''] + + TESTS:: + + sage: parse("::\n\n sage: # needs sage.combinat\n sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n ....: import incidence_matrix_to_bit_rep_of_Vrep\n sage: P = polytopes.associahedron(['A',3])\n\n") + ['::\n\n', + '', + (None, + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n', + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'), + '', + (None, + "P = polytopes.associahedron(['A',3])\n", + "P = polytopes.associahedron(['A',Integer(3)])\n"), + '\n'] + + sage: example4 = '::\n\n sage: C.minimum_distance(algorithm="guava") # optional - guava\n ...\n 24\n\n' + sage: parsed4 = DTP.parse(example4) + sage: dte = parsed4[1] + sage: dte.sage_source + 'C.minimum_distance(algorithm="guava") # optional - guava\n' + sage: dte.want + '...\n24\n' """ # Regular expressions find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M) @@ -1078,7 +1100,7 @@ def parse(self, string, *args): find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M) python_prompt = re.compile(r"^(\s*)>>>", re.M) backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ * -\ *(((\.){4}:)|((\.){3}))?\ *""") +\ *((\.){4}:)?\ *""") # The following are used to allow ... at the beginning of output ellipsis_tag = "" @@ -1087,13 +1109,8 @@ def parse(self, string, *args): # doctest system. m = backslash_replacer.search(string) while m is not None: - next_prompt = find_sage_prompt.search(string, m.end()) g = m.groups() - if next_prompt: - future = string[m.end():next_prompt.start()] + '\n' + string[next_prompt.start():] - else: - future = string[m.end():] - string = string[:m.start()] + g[0] + "sage:" + g[1] + future + string = string[:m.start()] + g[0] + "sage:" + g[1] + string[m.end():] m = backslash_replacer.search(string, m.start()) replace_ellipsis = not python_prompt.search(string) diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index 466ccf12181..d5dc83f0e1a 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -159,7 +159,7 @@ def __eq__(self, other): sage: FDS == FDS2 True """ - if type(self) != type(other): + if type(self) is not type(other): return False return self.__dict__ == other.__dict__ diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index dde3194df5d..cc4078c017a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -474,7 +474,7 @@ def Qxa(self, a): sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + 5*x0*x2*y0*y2 \ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 \ + - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 7e41c0fca68..f387c84ccec 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -396,7 +396,7 @@ def external_ray(theta, **kwds): pixel[i, j] = old_pixel[i, j] # Make sure that theta is a list so loop below works - if type(theta) != list: + if not isinstance(theta, list): theta = [theta] # Check if theta is in the interval [0,1] diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 62788943b09..9ee71e4f4bf 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -739,7 +739,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, # Take the given base color and create a list of evenly spaced # colors between the given base color and white. The number of # colors in the list depends on the variable color_num. - if type(base_color) == Color: + if isinstance(base_color, Color): # Convert Color to RGB list base_color = [int(k*255) for k in base_color] color_list = [] @@ -973,7 +973,7 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, # Take the given base color and create a list of evenly spaced # colors between the given base color and white. The number of # colors in the list depends on the variable color_num. - if type(base_color) == Color: + if isinstance(base_color, Color): # Convert Color to RGB list base_color = [int(k*255) for k in base_color] color_list = [] diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 6634b027ef5..97a16b9452a 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -493,7 +493,7 @@ def _builder_and_stream(vars, domain): sage: _builder_and_stream(["x", "y"], ZZ) (, ) - sage: _builder_and_stream(["x", "y"], RR) # optional - sage.rings.real_mpfr + sage: _builder_and_stream(["x", "y"], RR) # needs sage.rings.real_mpfr (, ) @@ -503,7 +503,7 @@ def _builder_and_stream(vars, domain): interpreter:: sage: domain = RDF - sage: from sage.structure.element import Element as domain # optional - sage.modules + sage: from sage.structure.element import Element as domain # needs sage.modules sage: _builder_and_stream(["x", "y"], domain) (, ) @@ -1622,7 +1622,7 @@ class IntegerPowerFunction(): sage: cube = IntegerPowerFunction(3) sage: cube (^3) - sage: cube(AA(7)^(1/3)) + sage: cube(AA(7)^(1/3)) # needs sage.rings.number_field 7.000000000000000? sage: cube.exponent 3 @@ -1820,18 +1820,18 @@ cpdef generate_code(Expression expr, InstructionStream stream): 25 sage: fc.op_list() [('load_arg', 0), ('load_arg', 1), ('py_call', , 2), 'return'] - sage: fc = fast_callable(expr) # optional - sage.symbolic - sage: fc(3.0r) # optional - sage.symbolic + sage: fc = fast_callable(expr) # needs sage.symbolic + sage: fc(3.0r) # needs sage.symbolic 4.0*pi + 12.0 - sage: fc = fast_callable(x+3, domain=ZZ) # optional - sage.symbolic - sage: fc(4) # optional - sage.symbolic + sage: fc = fast_callable(x+3, domain=ZZ) # needs sage.symbolic + sage: fc(4) # needs sage.symbolic 7 - sage: fc = fast_callable(x/3, domain=ZZ) # optional - sage.symbolic - sage: fc(4) # optional - sage.symbolic + sage: fc = fast_callable(x/3, domain=ZZ) # needs sage.symbolic + sage: fc(4) # needs sage.symbolic Traceback (most recent call last): ... TypeError: no conversion of this rational to integer - sage: fc(6) # optional - sage.symbolic + sage: fc(6) # needs sage.symbolic 2 sage: fc = fast_callable(etb.call(sin, x), domain=ZZ) sage: fc(0) diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 17aabcdca54..a989dcfc1fb 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -68,4 +68,11 @@ def _is_present(self): def all_features(): - return [] + return [GapPackage("atlasrep", spkg="gap_packages"), + GapPackage("design", spkg="gap_packages"), + GapPackage("grape", spkg="gap_packages"), + GapPackage("guava", spkg="gap_packages"), + GapPackage("hap", spkg="gap_packages"), + GapPackage("polycyclic", spkg="gap_packages"), + GapPackage("qpa", spkg="gap_packages"), + GapPackage("quagroup", spkg="gap_packages")] diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 234a4f82aa9..bafa3283990 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -17,6 +17,7 @@ # **************************************************************************** import sys +from sage.misc.misc import increase_recursion_limit from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.rings.real_double import RDF @@ -551,9 +552,8 @@ def _eval_(self, x): max = x.parent()(1.1)*x + 10 abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil() self._f = {} - if sys.getrecursionlimit() < max + 10: - sys.setrecursionlimit(int(max) + 10) - self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) + with increase_recursion_limit(int(max)): + self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) return self._f[n](2*(x-n-x.parent()(0.5))) def power_series(self, n, abs_prec): diff --git a/src/sage/geometry/abc.pyx b/src/sage/geometry/abc.pyx index 4db85b7ace8..f3aee46d324 100644 --- a/src/sage/geometry/abc.pyx +++ b/src/sage/geometry/abc.pyx @@ -13,13 +13,13 @@ class LatticePolytope: EXAMPLES:: sage: import sage.geometry.abc - sage: P = LatticePolytope([(1,2,3), (4,5,6)]) # optional - sage.geometry.polyhedron - sage: isinstance(P, sage.geometry.abc.LatticePolytope) # optional - sage.geometry.polyhedron + sage: P = LatticePolytope([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.LatticePolytope) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.LatticePolytope.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.LatticePolytope.__subclasses__() # needs sage.geometry.polyhedron [] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 @@ -39,13 +39,13 @@ class ConvexRationalPolyhedralCone: EXAMPLES:: sage: import sage.geometry.abc - sage: C = cones.nonnegative_orthant(2) # optional - sage.geometry.polyhedron - sage: isinstance(C, sage.geometry.abc.ConvexRationalPolyhedralCone) # optional - sage.geometry.polyhedron + sage: C = cones.nonnegative_orthant(2) # needs sage.geometry.polyhedron + sage: isinstance(C, sage.geometry.abc.ConvexRationalPolyhedralCone) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.ConvexRationalPolyhedralCone.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.ConvexRationalPolyhedralCone.__subclasses__() # needs sage.geometry.polyhedron [] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 @@ -65,13 +65,13 @@ class Polyhedron: EXAMPLES:: sage: import sage.geometry.abc - sage: P = polytopes.cube() # optional - sage.geometry.polyhedron - sage: isinstance(P, sage.geometry.abc.Polyhedron) # optional - sage.geometry.polyhedron + sage: P = polytopes.cube() # needs sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.Polyhedron) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.Polyhedron.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.Polyhedron.__subclasses__() # needs sage.geometry.polyhedron [] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d37a444a564..f0a8620011a 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -129,31 +129,33 @@ You can work with subcones that form faces of other cones:: - sage: face = four_rays.faces(dim=2)[0] # optional - sage.graphs - sage: face # optional - sage.graphs + sage: # needs sage.graphs + sage: face = four_rays.faces(dim=2)[0] + sage: face 2-d face of 3-d cone in 3-d lattice N - sage: face.rays() # optional - sage.graphs + sage: face.rays() N(-1, -1, 1), N(-1, 1, 1) in 3-d lattice N - sage: face.ambient_ray_indices() # optional - sage.graphs + sage: face.ambient_ray_indices() (2, 3) - sage: four_rays.rays(face.ambient_ray_indices()) # optional - sage.graphs + sage: four_rays.rays(face.ambient_ray_indices()) N(-1, -1, 1), N(-1, 1, 1) in 3-d lattice N If you need to know inclusion relations between faces, you can use :: - sage: L = four_rays.face_lattice() # optional - sage.graphs - sage: [len(s) for s in L.level_sets()] # optional - sage.graphs + sage: # needs sage.graphs + sage: L = four_rays.face_lattice() + sage: [len(s) for s in L.level_sets()] [1, 4, 4, 1] - sage: face = L.level_sets()[2][0] # optional - sage.graphs - sage: face.rays() # optional - sage.graphs + sage: face = L.level_sets()[2][0] + sage: face.rays() N(1, 1, 1), N(1, -1, 1) in 3-d lattice N - sage: L.hasse_diagram().neighbors_in(face) # optional - sage.graphs + sage: L.hasse_diagram().neighbors_in(face) [1-d face of 3-d cone in 3-d lattice N, 1-d face of 3-d cone in 3-d lattice N] @@ -572,9 +574,9 @@ def _ambient_space_point(body, data): (1, 1/3) sage: _ambient_space_point(c, vector(QQ,[1,1/3])) (1, 1/3) - sage: _ambient_space_point(c, [1/2, 1/sqrt(3)]) # optional - sage.symbolic sage.rings.number_field + sage: _ambient_space_point(c, [1/2, 1/sqrt(3)]) # needs sage.rings.number_field sage.symbolic (1/2, 0.5773502691896258?) - sage: _ambient_space_point(c, vector(AA, [1/2, 1/sqrt(3)])) # optional - sage.symbolic sage.rings.number_field + sage: _ambient_space_point(c, vector(AA, [1/2, 1/sqrt(3)])) # needs sage.rings.number_field sage.symbolic (1/2, 0.5773502691896258?) sage: _ambient_space_point(c, [1,1,3]) Traceback (most recent call last): @@ -592,9 +594,9 @@ def _ambient_space_point(body, data): sage: from sage.geometry.cone import _ambient_space_point sage: c = Cone([(1,0), (0,1)]) - sage: _ambient_space_point(c, [1, pi]) # optional - sage.symbolic sage.rings.number_field + sage: _ambient_space_point(c, [1, pi]) # needs sage.rings.number_field sage.symbolic (1.00000000000000, 3.14159265358979) - sage: _ambient_space_point(c, vector(SR,[1, pi])) # optional - sage.symbolic sage.rings.number_field + sage: _ambient_space_point(c, vector(SR,[1, pi])) # needs sage.rings.number_field sage.symbolic (1.00000000000000, 3.14159265358979) """ @@ -844,7 +846,7 @@ def __richcmp__(self, right, op): sage: c2 is c3 False """ - if type(self) != type(right): + if type(self) is not type(right): return NotImplemented # We probably do need to have explicit comparison of lattices here @@ -1005,7 +1007,7 @@ def ambient_vector_space(self, base_field=None): sage: c = Cone([(1,0)]) sage: c.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: c.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: c.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.lattice().vector_space(base_field=base_field) @@ -1098,7 +1100,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() # optional - sage.plot + sage: quadrant.plot() # needs sage.plot Graphics object consisting of 9 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) @@ -1601,7 +1603,7 @@ def __getstate__(self): TESTS:: sage: C = Cone([(1,0)]) - sage: C.face_lattice() # optional - sage.graphs sage.combinat + sage: C.face_lattice() # needs sage.combinat sage.graphs Finite lattice containing 2 elements with distinguished linear extension sage: C._test_pickling() sage: C2 = loads(dumps(C)); C2 @@ -1674,17 +1676,17 @@ def _contains(self, point, region='whole cone'): We can test vectors with irrational components:: sage: c = Cone([(1,0), (0,1)]) - sage: c._contains((1, sqrt(2))) # optional - sage.symbolic + sage: c._contains((1, sqrt(2))) # needs sage.symbolic True - sage: c._contains(vector(SR, [1, pi])) # optional - sage.symbolic + sage: c._contains(vector(SR, [1, pi])) # needs sage.symbolic True Ensure that complex vectors are not contained in a real cone:: sage: c = Cone([(1,0), (0,1)]) - sage: c._contains((1,I)) # optional - sage.symbolic + sage: c._contains((1,I)) # needs sage.symbolic False - sage: c._contains(vector(QQbar, [1,I])) # optional - sage.rings.number_field sage.symbolic + sage: c._contains(vector(QQbar, [1,I])) # needs sage.rings.number_field sage.symbolic False And we refuse to coerce elements of another lattice into ours:: @@ -1971,7 +1973,7 @@ def _latex_(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant._latex_() '\\sigma^{2}' - sage: quadrant.facets()[0]._latex_() # optional - sage.graphs + sage: quadrant.facets()[0]._latex_() # needs sage.graphs '\\sigma^{1} \\subset \\sigma^{2}' """ if self.ambient() is self: @@ -1995,7 +1997,7 @@ def _repr_(self): '2-d cone in 2-d lattice N' sage: quadrant 2-d cone in 2-d lattice N - sage: quadrant.facets()[0] # optional - sage.graphs + sage: quadrant.facets()[0] # needs sage.graphs 1-d face of 2-d cone in 2-d lattice N """ result = "%d-d" % self.dim() @@ -2051,7 +2053,7 @@ def _sort_faces(self, faces): sage: octant = Cone(identity_matrix(3).columns()) sage: # indirect doctest - sage: for i, face in enumerate(octant.faces(1)): # optional - sage.graphs + sage: for i, face in enumerate(octant.faces(1)): # needs sage.graphs ....: if face.ray(0) != octant.ray(i): ....: print("Wrong order!") """ @@ -2095,13 +2097,14 @@ def adjacent(self): EXAMPLES:: + sage: # needs sage.graphs sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) - sage: octant.adjacent() # optional - sage.graphs + sage: octant.adjacent() () - sage: one_face = octant.faces(1)[0] # optional - sage.graphs - sage: len(one_face.adjacent()) # optional - sage.graphs + sage: one_face = octant.faces(1)[0] + sage: len(one_face.adjacent()) 2 - sage: one_face.adjacent()[1] # optional - sage.graphs + sage: one_face.adjacent()[1] 1-d face of 3-d cone in 3-d lattice N Things are a little bit subtle with fans, as we illustrate below. @@ -2111,7 +2114,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2)], ....: rays=[(1,0), (0,1), (-1,0)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) # optional - sage.graphs + sage: len(cone.adjacent()) # needs sage.graphs 1 The second generating cone is adjacent to this one. Now we create the @@ -2120,7 +2123,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2)], ....: rays=[(1,0,0), (0,1,0), (-1,0,0)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) # optional - sage.graphs + sage: len(cone.adjacent()) # needs sage.graphs 1 The result is as before, since we still have:: @@ -2133,7 +2136,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2), (3,)], ....: rays=[(1,0,0), (0,1,0), (-1,0,0), (0,0,1)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) # optional - sage.graphs + sage: len(cone.adjacent()) # needs sage.graphs 0 Since now ``cone`` has smaller dimension than ``fan``, it and its @@ -2176,12 +2179,14 @@ def ambient(self): 3-d cone in 3-d lattice N sage: cone.ambient() is cone True - sage: face = cone.faces(1)[0] # optional - sage.graphs - sage: face # optional - sage.graphs + + sage: # needs sage.graphs + sage: face = cone.faces(1)[0] + sage: face 1-d face of 3-d cone in 3-d lattice N - sage: face.ambient() # optional - sage.graphs + sage: face.ambient() 3-d cone in 3-d lattice N - sage: face.ambient() is cone # optional - sage.graphs + sage: face.ambient() is cone True """ return self._ambient @@ -2199,7 +2204,7 @@ def ambient_ray_indices(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.ambient_ray_indices() (0, 1) - sage: quadrant.facets()[1].ambient_ray_indices() # optional - sage.graphs + sage: quadrant.facets()[1].ambient_ray_indices() # needs sage.graphs (1,) """ return self._ambient_ray_indices @@ -2238,9 +2243,9 @@ def contains(self, *args): False sage: c.contains(1) False - sage: c.contains(1/2, sqrt(3)) # optional - sage.symbolic + sage: c.contains(1/2, sqrt(3)) # needs sage.symbolic True - sage: c.contains(-1/2, sqrt(3)) # optional - sage.symbolic + sage: c.contains(-1/2, sqrt(3)) # needs sage.symbolic False """ point = flatten(args) @@ -2369,7 +2374,7 @@ def embed(self, cone): 1-d cone in 3-d lattice N sage: ray.ambient_ray_indices() (0,) - sage: ray.adjacent() # optional - sage.graphs + sage: ray.adjacent() # needs sage.graphs () sage: ray.ambient() 1-d cone in 3-d lattice N @@ -2377,22 +2382,23 @@ def embed(self, cone): If we want to operate with this ray as a face of the cone, we need to embed it first:: - sage: e_ray = c.embed(ray) # optional - sage.graphs - sage: e_ray # optional - sage.graphs + sage: # needs sage.graphs + sage: e_ray = c.embed(ray) + sage: e_ray 1-d face of 3-d cone in 3-d lattice N - sage: e_ray.rays() # optional - sage.graphs + sage: e_ray.rays() N(0, -1, 1) in 3-d lattice N - sage: e_ray is ray # optional - sage.graphs + sage: e_ray is ray False - sage: e_ray.is_equivalent(ray) # optional - sage.graphs + sage: e_ray.is_equivalent(ray) True - sage: e_ray.ambient_ray_indices() # optional - sage.graphs + sage: e_ray.ambient_ray_indices() (3,) - sage: e_ray.adjacent() # optional - sage.graphs + sage: e_ray.adjacent() (1-d face of 3-d cone in 3-d lattice N, 1-d face of 3-d cone in 3-d lattice N) - sage: e_ray.ambient() # optional - sage.graphs + sage: e_ray.ambient() 3-d cone in 3-d lattice N Not every cone can be embedded into a fixed ambient cone:: @@ -2402,7 +2408,7 @@ def embed(self, cone): ... ValueError: 1-d cone in 3-d lattice N is not a face of 3-d cone in 3-d lattice N! - sage: c.embed(Cone([(1,0,1), (-1,0,1)])) # optional - sage.graphs + sage: c.embed(Cone([(1,0,1), (-1,0,1)])) # needs sage.graphs Traceback (most recent call last): ... ValueError: 2-d cone in 3-d lattice N is not a face @@ -2447,13 +2453,13 @@ def face_lattice(self): Let's take a look at the face lattice of the first quadrant:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: L = quadrant.face_lattice() # optional - sage.graphs sage.combinat - sage: L # optional - sage.graphs sage.combinat + sage: L = quadrant.face_lattice() # needs sage.combinat sage.graphs + sage: L # needs sage.combinat sage.graphs Finite lattice containing 4 elements with distinguished linear extension To see all faces arranged by dimension, you can do this:: - sage: for level in L.level_sets(): print(level) # optional - sage.graphs sage.combinat + sage: for level in L.level_sets(): print(level) # needs sage.combinat sage.graphs [0-d face of 2-d cone in 2-d lattice N] [1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N] @@ -2461,15 +2467,15 @@ def face_lattice(self): For a particular face you can look at its actual rays... :: - sage: face = L.level_sets()[1][0] # optional - sage.graphs sage.combinat - sage: face.rays() # optional - sage.graphs sage.combinat + sage: face = L.level_sets()[1][0] # needs sage.combinat sage.graphs + sage: face.rays() # needs sage.combinat sage.graphs N(1, 0) in 2-d lattice N ... or you can see the index of the ray of the original cone that corresponds to the above one:: - sage: face.ambient_ray_indices() # optional - sage.graphs sage.combinat + sage: face.ambient_ray_indices() # needs sage.combinat sage.graphs (0,) sage: quadrant.ray(0) N(1, 0) @@ -2477,56 +2483,58 @@ def face_lattice(self): An alternative to extracting faces from the face lattice is to use :meth:`faces` method:: - sage: face is quadrant.faces(dim=1)[0] # optional - sage.graphs sage.combinat + sage: face is quadrant.faces(dim=1)[0] # needs sage.combinat sage.graphs True The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:: - sage: face = L.level_sets()[1][0] # optional - sage.graphs sage.combinat - sage: D = L.hasse_diagram() # optional - sage.graphs sage.combinat - sage: sorted(D.neighbors(face)) # optional - sage.graphs sage.combinat + sage: face = L.level_sets()[1][0] # needs sage.combinat sage.graphs + sage: D = L.hasse_diagram() # needs sage.combinat sage.graphs + sage: sorted(D.neighbors(face)) # needs sage.combinat sage.graphs [0-d face of 2-d cone in 2-d lattice N, 2-d cone in 2-d lattice N] However, you can achieve some of this functionality using :meth:`facets`, :meth:`facet_of`, and :meth:`adjacent` methods:: - sage: face = quadrant.faces(1)[0] # optional - sage.graphs - sage: face # optional - sage.graphs + sage: # needs sage.graphs + sage: face = quadrant.faces(1)[0] + sage: face 1-d face of 2-d cone in 2-d lattice N - sage: face.rays() # optional - sage.graphs + sage: face.rays() N(1, 0) in 2-d lattice N - sage: face.facets() # optional - sage.graphs + sage: face.facets() (0-d face of 2-d cone in 2-d lattice N,) - sage: face.facet_of() # optional - sage.graphs + sage: face.facet_of() (2-d cone in 2-d lattice N,) - sage: face.adjacent() # optional - sage.graphs + sage: face.adjacent() (1-d face of 2-d cone in 2-d lattice N,) - sage: face.adjacent()[0].rays() # optional - sage.graphs + sage: face.adjacent()[0].rays() N(0, 1) in 2-d lattice N Note that if ``cone`` is a face of ``supercone``, then the face lattice of ``cone`` consists of (appropriate) faces of ``supercone``:: + sage: # needs sage.combinat sage.graphs sage: supercone = Cone([(1,2,3,4), (5,6,7,8), ....: (1,2,4,8), (1,3,9,7)]) - sage: supercone.face_lattice() # optional - sage.graphs sage.combinat + sage: supercone.face_lattice() Finite lattice containing 16 elements with distinguished linear extension - sage: supercone.face_lattice().top() # optional - sage.graphs sage.combinat + sage: supercone.face_lattice().top() 4-d cone in 4-d lattice N - sage: cone = supercone.facets()[0] # optional - sage.graphs sage.combinat - sage: cone # optional - sage.graphs sage.combinat + sage: cone = supercone.facets()[0] + sage: cone 3-d face of 4-d cone in 4-d lattice N - sage: cone.face_lattice() # optional - sage.graphs sage.combinat + sage: cone.face_lattice() Finite poset containing 8 elements with distinguished linear extension - sage: cone.face_lattice().bottom() # optional - sage.graphs sage.combinat + sage: cone.face_lattice().bottom() 0-d face of 4-d cone in 4-d lattice N - sage: cone.face_lattice().top() # optional - sage.graphs sage.combinat + sage: cone.face_lattice().top() 3-d face of 4-d cone in 4-d lattice N - sage: cone.face_lattice().top() == cone # optional - sage.graphs sage.combinat + sage: cone.face_lattice().top() == cone True TESTS:: @@ -2542,19 +2550,19 @@ def face_lattice(self): to have non identical face lattices, even if the faces themselves are equal (see :trac:`10998`):: - sage: C1.face_lattice() is C2.face_lattice() # optional - sage.graphs sage.combinat + sage: C1.face_lattice() is C2.face_lattice() # needs sage.combinat sage.graphs False - sage: C1.facets()[0] # optional - sage.graphs + sage: C1.facets()[0] # needs sage.graphs 0-d face of 1-d cone in 2-d lattice N - sage: C2.facets()[0] # optional - sage.graphs + sage: C2.facets()[0] # needs sage.graphs 0-d face of 1-d cone in 2-d lattice N - sage: C1.facets()[0].ambient() is C1 # optional - sage.graphs + sage: C1.facets()[0].ambient() is C1 # needs sage.graphs True - sage: C2.facets()[0].ambient() is C1 # optional - sage.graphs + sage: C2.facets()[0].ambient() is C1 # needs sage.graphs False - sage: C2.facets()[0].ambient() is C2 # optional - sage.graphs + sage: C2.facets()[0].ambient() is C2 # needs sage.graphs True """ if "_face_lattice" not in self.__dict__: @@ -2680,50 +2688,51 @@ def faces(self, dim=None, codim=None): Let's take a look at the faces of the first quadrant:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.faces() # optional - sage.graphs + sage: quadrant.faces() # needs sage.graphs ((0-d face of 2-d cone in 2-d lattice N,), (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N), (2-d cone in 2-d lattice N,)) - sage: quadrant.faces(dim=1) # optional - sage.graphs + sage: quadrant.faces(dim=1) # needs sage.graphs (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N) - sage: face = quadrant.faces(dim=1)[0] # optional - sage.graphs + sage: face = quadrant.faces(dim=1)[0] # needs sage.graphs Now you can look at the actual rays of this face... :: - sage: face.rays() # optional - sage.graphs + sage: face.rays() # needs sage.graphs N(1, 0) in 2-d lattice N ... or you can see indices of the rays of the original cone that correspond to the above ray:: - sage: face.ambient_ray_indices() # optional - sage.graphs + sage: face.ambient_ray_indices() # needs sage.graphs (0,) sage: quadrant.ray(0) N(1, 0) Note that it is OK to ask for faces of too small or high dimension:: - sage: quadrant.faces(-1) # optional - sage.graphs + sage: quadrant.faces(-1) # needs sage.graphs () - sage: quadrant.faces(3) # optional - sage.graphs + sage: quadrant.faces(3) # needs sage.graphs () In the case of non-strictly convex cones even faces of small non-negative dimension may be missing:: + sage: # needs sage.graphs sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) - sage: halfplane.faces(0) # optional - sage.graphs + sage: halfplane.faces(0) () - sage: halfplane.faces() # optional - sage.graphs + sage: halfplane.faces() ((1-d face of 2-d cone in 2-d lattice N,), (2-d cone in 2-d lattice N,)) - sage: plane = Cone([(1,0), (0,1), (-1,-1)]) # optional - sage.graphs - sage: plane.faces(1) # optional - sage.graphs + sage: plane = Cone([(1,0), (0,1), (-1,-1)]) + sage: plane.faces(1) () - sage: plane.faces() # optional - sage.graphs + sage: plane.faces() ((2-d cone in 2-d lattice N,),) TESTS: @@ -2732,7 +2741,7 @@ def faces(self, dim=None, codim=None): dimension of the ambient space work as expected (see :trac:`9188`):: sage: c = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3)]) - sage: c.faces() # optional - sage.graphs + sage: c.faces() # needs sage.graphs ((0-d face of 3-d cone in 4-d lattice N,), (1-d face of 3-d cone in 4-d lattice N, 1-d face of 3-d cone in 4-d lattice N, @@ -2745,16 +2754,17 @@ def faces(self, dim=None, codim=None): We also ensure that a call to this function does not break :meth:`facets` method (see :trac:`9780`):: - sage: cone = toric_varieties.dP8().fan().generating_cone(0); cone # optional - palp + sage: # needs palp sage.graphs + sage: cone = toric_varieties.dP8().fan().generating_cone(0); cone 2-d cone of Rational polyhedral fan in 2-d lattice N - sage: for f in cone.facets(): print(f.rays()) # optional - palp sage.graphs + sage: for f in cone.facets(): print(f.rays()) N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N - sage: len(cone.faces()) # optional - palp sage.graphs + sage: len(cone.faces()) 3 - sage: for f in cone.facets(): print(f.rays()) # optional - palp sage.graphs + sage: for f in cone.facets(): print(f.rays()) N(1, 1) in 2-d lattice N N(0, 1) @@ -2900,26 +2910,27 @@ def facet_of(self): EXAMPLES:: + sage: # needs sage.graphs sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) - sage: octant.facet_of() # optional - sage.graphs + sage: octant.facet_of() () - sage: one_face = octant.faces(1)[0] # optional - sage.graphs - sage: len(one_face.facet_of()) # optional - sage.graphs + sage: one_face = octant.faces(1)[0] + sage: len(one_face.facet_of()) 2 - sage: one_face.facet_of()[1] # optional - sage.graphs + sage: one_face.facet_of()[1] 2-d face of 3-d cone in 3-d lattice N While fan is the top element of its own cone lattice, which is a variant of a face lattice, we do not refer to cones as its facets:: - sage: fan = Fan([octant]) - sage: fan.generating_cone(0).facet_of() # optional - sage.graphs + sage: fan = Fan([octant]) # needs sage.graphs + sage: fan.generating_cone(0).facet_of() # needs sage.graphs () Subcones of generating cones work as before:: - sage: one_cone = fan(1)[0] # optional - sage.graphs - sage: len(one_cone.facet_of()) # optional - sage.graphs + sage: one_cone = fan(1)[0] # needs sage.graphs + sage: len(one_cone.facet_of()) # needs sage.graphs 2 """ L = self._ambient._face_lattice_function() @@ -2938,7 +2949,7 @@ def facets(self): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.facets() # optional - sage.graphs + sage: quadrant.facets() # needs sage.graphs (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N) """ @@ -3257,19 +3268,19 @@ def is_isomorphic(self, other): We check that :trac:`18613` is fixed:: sage: K = cones.trivial(0) - sage: K.is_isomorphic(K) # optional - sage.graphs + sage: K.is_isomorphic(K) # needs sage.graphs True sage: K = cones.trivial(1) - sage: K.is_isomorphic(K) # optional - sage.graphs + sage: K.is_isomorphic(K) # needs sage.graphs True sage: K = cones.trivial(2) - sage: K.is_isomorphic(K) # optional - sage.graphs + sage: K.is_isomorphic(K) True A random (strictly convex) cone is isomorphic to itself:: sage: K = random_cone(max_ambient_dim=6, strictly_convex=True) - sage: K.is_isomorphic(K) # optional - sage.graphs + sage: K.is_isomorphic(K) # needs sage.graphs True """ if self.is_strictly_convex() and other.is_strictly_convex(): @@ -3484,7 +3495,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() # optional - sage.plot + sage: quadrant.plot() # needs sage.plot Graphics object consisting of 9 graphics primitives """ # What to do with 3-d cones in 5-d? Use some projection method? @@ -3754,7 +3765,7 @@ def solid_restriction(self): the original:: sage: K = random_cone(max_ambient_dim=6) - sage: len(K.solid_restriction().facets()) == len(K.facets()) # optional - sage.graphs + sage: len(K.solid_restriction().facets()) == len(K.facets()) # needs sage.graphs True """ if self.is_solid(): @@ -3915,17 +3926,18 @@ def sublattice_quotient(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.graphs sage: C2_Z2 = Cone([(1,0), (1,2)]) # C^2/Z_2 - sage: c1, c2 = C2_Z2.facets() # optional - sage.graphs - sage: c2.sublattice_quotient() # optional - sage.graphs + sage: c1, c2 = C2_Z2.facets() + sage: c2.sublattice_quotient() 1-d lattice, quotient of 2-d lattice N by Sublattice sage: N = C2_Z2.lattice() sage: n = N(1,1) - sage: n_bar = c2.sublattice_quotient(n); n_bar # optional - sage.graphs + sage: n_bar = c2.sublattice_quotient(n); n_bar N[1, 1] - sage: n_bar.lift() # optional - sage.graphs + sage: n_bar.lift() N(1, 1) - sage: vector(n_bar) # optional - sage.graphs + sage: vector(n_bar) (-1) """ if "_sublattice_quotient" not in self.__dict__: @@ -3968,10 +3980,10 @@ def sublattice_complement(self, *args, **kwds): EXAMPLES:: sage: C2_Z2 = Cone([(1,0), (1,2)]) # C^2/Z_2 - sage: c1, c2 = C2_Z2.facets() # optional - sage.graphs - sage: c2.sublattice() # optional - sage.graphs + sage: c1, c2 = C2_Z2.facets() # needs sage.graphs + sage: c2.sublattice() # needs sage.graphs Sublattice - sage: c2.sublattice_complement() # optional - sage.graphs + sage: c2.sublattice_complement() # needs sage.graphs Sublattice A more complicated example:: @@ -4197,30 +4209,32 @@ def relative_orthogonal_quotient(self, supercone): EXAMPLES:: + sage: # needs sage.graphs sage: rho = Cone([(1,1,1,3), (1,-1,1,3), (-1,-1,1,3), (-1,1,1,3)]) sage: rho.orthogonal_sublattice() Sublattice - sage: sigma = rho.facets()[1] # optional - sage.graphs - sage: sigma.orthogonal_sublattice() # optional - sage.graphs + sage: sigma = rho.facets()[1] + sage: sigma.orthogonal_sublattice() Sublattice - sage: sigma.is_face_of(rho) # optional - sage.graphs + sage: sigma.is_face_of(rho) True - sage: Q = sigma.relative_orthogonal_quotient(rho); Q # optional - sage.graphs + sage: Q = sigma.relative_orthogonal_quotient(rho); Q 1-d lattice, quotient of Sublattice by Sublattice - sage: Q.gens() # optional - sage.graphs + sage: Q.gens() (M[0, 1, 1, 0],) Different codimension:: + sage: # needs sage.graphs sage: rho = Cone([[1,-1,1,3],[-1,-1,1,3]]) - sage: sigma = rho.facets()[0] # optional - sage.graphs - sage: sigma.orthogonal_sublattice() # optional - sage.graphs + sage: sigma = rho.facets()[0] + sage: sigma.orthogonal_sublattice() Sublattice - sage: rho.orthogonal_sublattice() # optional - sage.graphs + sage: rho.orthogonal_sublattice() Sublattice - sage: sigma.relative_orthogonal_quotient(rho).gens() # optional - sage.graphs + sage: sigma.relative_orthogonal_quotient(rho).gens() (M[-1, 0, -2, 1],) Sign choice in the codimension one case:: @@ -5733,19 +5747,20 @@ def positive_operators_gens(self, K2=None): The positive operators on a permuted cone can be obtained by conjugation:: + sage: # needs sage.groups sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) - sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() # optional - sage.groups - sage: pK = Cone((p*k for k in K), K.lattice(), check=False) # optional - sage.groups - sage: pi_gens = pK.positive_operators_gens() # optional - sage.groups - sage: actual = Cone((g.list() for g in pi_gens), # optional - sage.groups + sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() + sage: pK = Cone((p*k for k in K), K.lattice(), check=False) + sage: pi_gens = pK.positive_operators_gens() + sage: actual = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_gens = K.positive_operators_gens() - sage: expected = Cone(((p*g*p.inverse()).list() for g in pi_gens), # optional - sage.groups + sage: expected = Cone(((p*g*p.inverse()).list() for g in pi_gens), ....: lattice=L, ....: check=False) - sage: actual.is_equivalent(expected) # optional - sage.groups + sage: actual.is_equivalent(expected) True An operator is positive from one cone to another if and only if @@ -6056,19 +6071,20 @@ def cross_positive_operators_gens(self): The cross-positive operators of a permuted cone can be obtained by conjugation:: + sage: # needs sage.groups sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) - sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() # optional - sage.groups - sage: pK = Cone((p*k for k in K), K.lattice(), check=False) # optional - sage.groups - sage: cp_gens = pK.cross_positive_operators_gens() # optional - sage.groups - sage: actual = Cone((g.list() for g in cp_gens), # optional - sage.groups + sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() + sage: pK = Cone((p*k for k in K), K.lattice(), check=False) + sage: cp_gens = pK.cross_positive_operators_gens() + sage: actual = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: cp_gens = K.cross_positive_operators_gens() - sage: expected = Cone(((p*g*p.inverse()).list() for g in cp_gens), # optional - sage.groups + sage: expected = Cone(((p*g*p.inverse()).list() for g in cp_gens), ....: lattice=L, ....: check=False) - sage: actual.is_equivalent(expected) # optional - sage.groups + sage: actual.is_equivalent(expected) True An operator is cross-positive on a cone if and only if its diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index 185391d261a..d6898d40087 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -374,8 +374,8 @@ def rearrangement(p, ambient_dim=None, lattice=None): sage: ambient_dim = ZZ.random_element(2,10).abs() sage: p = ZZ.random_element(1, ambient_dim) sage: K = cones.rearrangement(p, ambient_dim) - sage: P = SymmetricGroup(ambient_dim).random_element().matrix() # optional - sage.groups - sage: all(K.contains(P*r) for r in K) # optional - sage.groups + sage: P = SymmetricGroup(ambient_dim).random_element().matrix() # needs sage.groups + sage: all(K.contains(P*r) for r in K) # needs sage.groups True The smallest ``p`` components of every element of the rearrangement @@ -527,13 +527,14 @@ def schur(ambient_dim=None, lattice=None): generators of the Schur cone and the nonnegative orthant in dimension five is `\left(3/4\right)\pi`:: + sage: # needs sage.rings.number_fields sage: P = cones.schur(5) sage: Q = cones.nonnegative_orthant(5) - sage: G = ( g.change_ring(QQbar).normalized() for g in P ) # optional - sage.rings.number_fields - sage: H = ( h.change_ring(QQbar).normalized() for h in Q ) # optional - sage.rings.number_fields - sage: actual = max(arccos(u.inner_product(v)) for u in G for v in H) # optional - sage.rings.number_fields - sage: expected = 3*pi/4 # optional - sage.rings.number_fields - sage: abs(actual - expected).n() < 1e-12 # optional - sage.rings.number_fields + sage: G = ( g.change_ring(QQbar).normalized() for g in P ) + sage: H = ( h.change_ring(QQbar).normalized() for h in Q ) + sage: actual = max(arccos(u.inner_product(v)) for u in G for v in H) + sage: expected = 3*pi/4 + sage: abs(actual - expected).n() < 1e-12 True The dual of the Schur cone is the "downward monotonic cone" @@ -566,7 +567,7 @@ def schur(ambient_dim=None, lattice=None): True sage: x = V.random_element() sage: y = V.random_element() - sage: majorized_by(x,y) == ( (y-x) in S ) # optional - sage.rings.number_fields + sage: majorized_by(x,y) == ( (y-x) in S ) True If a ``lattice`` was given, it is actually used:: diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 3f04faf2e4d..258544012fe 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -196,11 +196,12 @@ We can also make ``fan3`` smooth, but it will take a bit more work:: + sage: # needs palp sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: sk = cube.skeleton_points(2) # optional - palp - sage: rays = [cube.point(p) for p in sk] # optional - palp - sage: fan4 = fan3.subdivide(new_rays=rays) # optional - palp - sage: fan4.is_smooth() # optional - palp + sage: sk = cube.skeleton_points(2) + sage: rays = [cube.point(p) for p in sk] + sage: fan4 = fan3.subdivide(new_rays=rays) + sage: fan4.is_smooth() True Let's see how "different" are ``fan2`` and ``fan4``:: @@ -209,9 +210,9 @@ 6 sage: fan2.nrays() 8 - sage: fan4.ngenerating_cones() # optional - palp + sage: fan4.ngenerating_cones() # needs palp 48 - sage: fan4.nrays() # optional - palp + sage: fan4.nrays() # needs palp 26 Smoothness does not come for free! @@ -278,9 +279,9 @@ def is_Fan(x) -> bool: sage: from sage.geometry.fan import is_Fan sage: is_Fan(1) False - sage: fan = toric_varieties.P2().fan(); fan # optional - palp + sage: fan = toric_varieties.P2().fan(); fan # needs palp Rational polyhedral fan in 2-d lattice N - sage: is_Fan(fan) # optional - palp + sage: is_Fan(fan) # needs palp True """ return isinstance(x, RationalPolyhedralFan) @@ -503,7 +504,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: fan = Fan([c1, c2], allow_arrangement=True) sage: fan.ngenerating_cones() 7 - sage: fan.plot() # optional - sage.plot + sage: fan.plot() # needs sage.plot Graphics3d Object Cones of different dimension:: @@ -523,7 +524,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: c3 = Cone([[0, 1, 1], [1, 0, 1], [0, -1, 1], [-1, 0, 1]]) sage: c1 = Cone([[0, 0, 1]]) sage: fan1 = Fan([c1, c3], allow_arrangement=True) - sage: fan1.plot() # optional - sage.plot + sage: fan1.plot() # needs sage.plot Graphics3d Object A 3-d cone and two 2-d cones:: @@ -1027,12 +1028,13 @@ class Cone_of_fan(ConvexRationalPolyhedralCone): The intended way to get objects of this class is the following:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: cone = fan.generating_cone(0); cone # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P1xP1().fan() + sage: cone = fan.generating_cone(0); cone 2-d cone of Rational polyhedral fan in 2-d lattice N - sage: cone.ambient_ray_indices() # optional - palp + sage: cone.ambient_ray_indices() (0, 2) - sage: cone.star_generator_indices() # optional - palp + sage: cone.star_generator_indices() (0,) """ @@ -1045,10 +1047,10 @@ def __init__(self, ambient, ambient_ray_indices): The following code is likely to construct an invalid object, we just test that creation of cones of fans is working:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: cone = sage.geometry.fan.Cone_of_fan(fan, (0,)); cone # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: cone = sage.geometry.fan.Cone_of_fan(fan, (0,)); cone # needs palp 1-d cone of Rational polyhedral fan in 2-d lattice N - sage: TestSuite(cone).run() # optional - palp + sage: TestSuite(cone).run() # needs palp """ super().__init__(ambient=ambient, ambient_ray_indices=ambient_ray_indices) @@ -1065,11 +1067,12 @@ def _repr_(self) -> str: TESTS:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone._repr_() # optional - palp + sage: # needs palp + sage: P1xP1 = toric_varieties.P1xP1() + sage: cone = P1xP1.fan().generating_cone(0) + sage: cone._repr_() '2-d cone of Rational polyhedral fan in 2-d lattice N' - sage: cone.facets()[0]._repr_() # optional - palp + sage: cone.facets()[0]._repr_() '1-d cone of Rational polyhedral fan in 2-d lattice N' """ # The base class would print "face of" instead of "cone of" @@ -1086,9 +1089,9 @@ def star_generator_indices(self): EXAMPLES:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone.star_generator_indices() # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() # needs palp + sage: cone = P1xP1.fan().generating_cone(0) # needs palp + sage: cone.star_generator_indices() # needs palp (0,) TESTS: @@ -1138,9 +1141,9 @@ def star_generators(self): EXAMPLES:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone.star_generators() # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() # needs palp + sage: cone = P1xP1.fan().generating_cone(0) # needs palp + sage: cone.star_generators() # needs palp (2-d cone of Rational polyhedral fan in 2-d lattice N,) """ if "_star_generators" not in self.__dict__: @@ -1394,8 +1397,8 @@ def _compute_cone_lattice(self): the common cases is a fan which is KNOWN to be complete, i.e. we do not even need to check if it is complete:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.cone_lattice() # indirect doctest # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.cone_lattice() # indirect doctest # needs palp Finite lattice containing 10 elements with distinguished linear extension These 10 elements are: 1 origin, 4 rays, 4 generating cones, 1 fan. @@ -1625,9 +1628,9 @@ def support_contains(self, *args): False sage: f.support_contains(0) # 0 converts to the origin in the lattice True - sage: f.support_contains(1/2, sqrt(3)) # optional - sage.symbolic + sage: f.support_contains(1/2, sqrt(3)) # needs sage.symbolic True - sage: f.support_contains(-1/2, sqrt(3)) # optional - sage.symbolic + sage: f.support_contains(-1/2, sqrt(3)) # needs sage.symbolic False """ if len(args) == 1: @@ -1811,10 +1814,10 @@ def _ray_to_cones(self, i=None): EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan._ray_to_cones(0) # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan._ray_to_cones(0) # needs palp frozenset({0, 3}) - sage: fan._ray_to_cones() # optional - palp + sage: fan._ray_to_cones() # needs palp (frozenset({0, 3}), frozenset({1, 2}), frozenset({0, 1}), frozenset({2, 3})) """ # This function is close to self(1)[i].star_generator_indices(), but @@ -2123,9 +2126,9 @@ def cone_lattice(self): can (and will!) be computed in a much more efficient way, but the interface is exactly the same:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: L = fan.cone_lattice() # optional - palp - sage: for l in L.level_sets()[:-1]: # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: L = fan.cone_lattice() # needs palp + sage: for l in L.level_sets()[:-1]: # needs palp ....: print([f.ambient_ray_indices() for f in l]) [()] [(0,), (1,), (2,), (3,)] @@ -2452,11 +2455,11 @@ def Gale_transform(self): EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.Gale_transform() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.Gale_transform() # needs palp [ 1 1 0 0 -2] [ 0 0 1 1 -2] - sage: _.base_ring() # optional - palp + sage: _.base_ring() # needs palp Integer Ring """ m = self.rays().matrix().stack(matrix(ZZ, 1, self.lattice_dim())) @@ -2477,8 +2480,8 @@ def generating_cone(self, n): EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.generating_cone(0) # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.generating_cone(0) # needs palp 2-d cone of Rational polyhedral fan in 2-d lattice N """ return self._generating_cones[n] @@ -2493,8 +2496,8 @@ def generating_cones(self): EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.generating_cones() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.generating_cones() # needs palp (2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, @@ -2525,18 +2528,19 @@ def vertex_graph(self): EXAMPLES:: - sage: dP8 = toric_varieties.dP8() # optional - palp sage.graphs - sage: g = dP8.fan().vertex_graph(); g # optional - palp sage.graphs + sage: # needs palp + sage: dP8 = toric_varieties.dP8() + sage: g = dP8.fan().vertex_graph(); g Graph on 4 vertices - sage: set(dP8.fan(1)) == set(g.vertices(sort=False)) # optional - palp sage.graphs + sage: set(dP8.fan(1)) == set(g.vertices(sort=False)) True - sage: g.edge_labels() # all edge labels the same since every cone is smooth # optional - palp sage.graphs + sage: g.edge_labels() # all edge labels the same since every cone is smooth [(1, 0), (1, 0), (1, 0), (1, 0)] - sage: g = toric_varieties.Cube_deformation(10).fan().vertex_graph() # optional - sage.graphs - sage: g.automorphism_group().order() # optional - sage.graphs sage.groups + sage: g = toric_varieties.Cube_deformation(10).fan().vertex_graph() + sage: g.automorphism_group().order() # needs sage.groups 48 - sage: g.automorphism_group(edge_labels=True).order() # optional - sage.graphs sage.groups + sage: g.automorphism_group(edge_labels=True).order() # needs sage.groups 4 """ from sage.geometry.cone import classify_cone_2d @@ -2567,8 +2571,8 @@ def is_complete(self) -> bool: EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_complete() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_complete() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2750,8 +2754,8 @@ def _2d_echelon_forms(self): EXAMPLES:: - sage: fan = toric_varieties.dP8().fan() # optional - palp - sage: fan._2d_echelon_forms() # optional - palp + sage: fan = toric_varieties.dP8().fan() # needs palp + sage: fan._2d_echelon_forms() # needs palp frozenset({[ 1 0 -1 -1] [ 0 1 0 -1], [ 1 0 -1 0] [ 0 1 -1 -1], [ 1 0 -1 0] @@ -2772,8 +2776,8 @@ def _2d_echelon_form(self): EXAMPLES:: - sage: fan = toric_varieties.dP8().fan() # optional - palp - sage: fan._2d_echelon_form() # optional - palp + sage: fan = toric_varieties.dP8().fan() # needs palp + sage: fan._2d_echelon_form() # needs palp [ 1 0 -1 -1] [ 0 1 0 -1] """ @@ -2816,7 +2820,7 @@ def isomorphism(self, other): Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N - sage: fan1.isomorphism(toric_varieties.P2().fan()) # optional - palp + sage: fan1.isomorphism(toric_varieties.P2().fan()) # needs palp Traceback (most recent call last): ... FanNotIsomorphicError @@ -2838,8 +2842,8 @@ def is_simplicial(self) -> bool: EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_simplicial() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_simplicial() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2888,8 +2892,8 @@ def is_smooth(self, codim=None) -> bool: EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_smooth() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_smooth() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2957,8 +2961,8 @@ def ngenerating_cones(self): EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.ngenerating_cones() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.ngenerating_cones() # needs palp 4 sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2983,8 +2987,8 @@ def plot(self, **options): EXAMPLES:: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - palp sage.plot + sage: fan = toric_varieties.dP6().fan() # needs palp + sage: fan.plot() # needs palp sage.plot Graphics object consisting of 31 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) @@ -3042,8 +3046,8 @@ def subdivide(self, new_rays=None, make_simplicial=False, We check that :trac:`11902` is fixed:: - sage: fan = toric_varieties.P2().fan() # optional - palp - sage: fan.subdivide(new_rays=[(0,0)]) # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp + sage: fan.subdivide(new_rays=[(0,0)]) # needs palp Traceback (most recent call last): ... ValueError: the origin cannot be used for fan subdivision! @@ -3319,18 +3323,19 @@ def oriented_boundary(self, cone): EXAMPLES:: - sage: fan = toric_varieties.P(3).fan() # optional - palp - sage: cone = fan(2)[0] # optional - palp - sage: bdry = fan.oriented_boundary(cone); bdry # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P(3).fan() + sage: cone = fan(2)[0] + sage: bdry = fan.oriented_boundary(cone); bdry -1-d cone of Rational polyhedral fan in 3-d lattice N + 1-d cone of Rational polyhedral fan in 3-d lattice N - sage: bdry[0] # optional - palp + sage: bdry[0] (-1, 1-d cone of Rational polyhedral fan in 3-d lattice N) - sage: bdry[1] # optional - palp + sage: bdry[1] (1, 1-d cone of Rational polyhedral fan in 3-d lattice N) - sage: fan.oriented_boundary(bdry[0][1]) # optional - palp + sage: fan.oriented_boundary(bdry[0][1]) -0-d cone of Rational polyhedral fan in 3-d lattice N - sage: fan.oriented_boundary(bdry[1][1]) # optional - palp + sage: fan.oriented_boundary(bdry[1][1]) -0-d cone of Rational polyhedral fan in 3-d lattice N If you pass the fan itself, this method returns the @@ -3338,12 +3343,12 @@ def oriented_boundary(self, cone): order of the rays in :meth:`cone.ray_basis() ` :: - sage: fan.oriented_boundary(fan) # optional - palp + sage: fan.oriented_boundary(fan) # needs palp -3-d cone of Rational polyhedral fan in 3-d lattice N + 3-d cone of Rational polyhedral fan in 3-d lattice N - 3-d cone of Rational polyhedral fan in 3-d lattice N + 3-d cone of Rational polyhedral fan in 3-d lattice N - sage: [cone.rays().basis().matrix().det() # optional - palp + sage: [cone.rays().basis().matrix().det() # needs palp ....: for cone in fan.generating_cones()] [-1, 1, -1, 1] @@ -3358,9 +3363,9 @@ def oriented_boundary(self, cone): TESTS:: - sage: fan = toric_varieties.P2().fan() # optional - palp - sage: trivial_cone = fan(0)[0] # optional - palp - sage: fan.oriented_boundary(trivial_cone) # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp + sage: trivial_cone = fan(0)[0] # needs palp + sage: fan.oriented_boundary(trivial_cone) # needs palp 0 """ if cone is not self: @@ -3505,23 +3510,24 @@ def complex(self, base_ring=ZZ, extended=False): EXAMPLES:: - sage: fan = toric_varieties.P(3).fan() # optional - palp - sage: K_normal = fan.complex(); K_normal # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P(3).fan() + sage: K_normal = fan.complex(); K_normal Chain complex with at most 4 nonzero terms over Integer Ring - sage: K_normal.homology() # optional - palp + sage: K_normal.homology() {0: Z, 1: 0, 2: 0, 3: 0} - sage: K_extended = fan.complex(extended=True); K_extended # optional - palp + sage: K_extended = fan.complex(extended=True); K_extended Chain complex with at most 5 nonzero terms over Integer Ring - sage: K_extended.homology() # optional - palp + sage: K_extended.homology() {-1: 0, 0: 0, 1: 0, 2: 0, 3: 0} Homology computations are much faster over `\QQ` if you do not care about the torsion coefficients:: - sage: toric_varieties.P2_123().fan().complex(extended=True, # optional - palp + sage: toric_varieties.P2_123().fan().complex(extended=True, # needs palp ....: base_ring=QQ) Chain complex with at most 4 nonzero terms over Rational Field - sage: _.homology() # optional - palp + sage: _.homology() # needs palp {-1: Vector space of dimension 0 over Rational Field, 0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 0 over Rational Field, @@ -3606,17 +3612,17 @@ def discard_faces(cones): Consider all cones of a fan:: - sage: Sigma = toric_varieties.P2().fan() # optional - palp - sage: cones = flatten(Sigma.cones()) # optional - palp - sage: len(cones) # optional - palp + sage: Sigma = toric_varieties.P2().fan() # needs palp + sage: cones = flatten(Sigma.cones()) # needs palp + sage: len(cones) # needs palp 7 Most of them are not necessary to generate this fan:: sage: from sage.geometry.fan import discard_faces - sage: len(discard_faces(cones)) # optional - palp + sage: len(discard_faces(cones)) # needs palp 3 - sage: Sigma.ngenerating_cones() # optional - palp + sage: Sigma.ngenerating_cones() # needs palp 3 """ # Convert to a list or make a copy, so that the input is unchanged. diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index 0eb3b13d21c..2c69f06a71f 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -38,10 +38,10 @@ def fan_isomorphic_necessary_conditions(fan1, fan2): EXAMPLES:: - sage: fan1 = toric_varieties.P2().fan() # optional - palp - sage: fan2 = toric_varieties.dP8().fan() # optional - palp + sage: fan1 = toric_varieties.P2().fan() # needs palp sage.graphs + sage: fan2 = toric_varieties.dP8().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_isomorphic_necessary_conditions - sage: fan_isomorphic_necessary_conditions(fan1, fan2) # optional - palp + sage: fan_isomorphic_necessary_conditions(fan1, fan2) # needs palp sage.graphs False """ if fan1.lattice_dim() != fan2.lattice_dim(): @@ -78,9 +78,9 @@ def fan_isomorphism_generator(fan1, fan2): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_isomorphism_generator - sage: sorted(fan_isomorphism_generator(fan, fan)) # optional - palp + sage: sorted(fan_isomorphism_generator(fan, fan)) # needs palp sage.graphs [ [-1 -1] [-1 -1] [ 0 1] [0 1] [ 1 0] [1 0] [ 0 1], [ 1 0], [-1 -1], [1 0], [-1 -1], [0 1] @@ -93,7 +93,7 @@ def fan_isomorphism_generator(fan1, fan2): ....: Cone([m1*vector([-1,-14]), m1*vector([-100, -5])])]) sage: fan2 = Fan([Cone([m2*vector([23, 14]), m2*vector([ 3,100])]), ....: Cone([m2*vector([-1,-14]), m2*vector([-100, -5])])]) - sage: sorted(fan_isomorphism_generator(fan1, fan2)) + sage: sorted(fan_isomorphism_generator(fan1, fan2)) # needs sage.graphs [ [-12 1 -5] [ -4 0 -1] @@ -111,24 +111,24 @@ def fan_isomorphism_generator(fan1, fan2): ....: Cone([m1*vector([1,1]), m1*vector([0,1])])]) sage: fan2 = Fan([Cone([m2*vector([1,0]), m2*vector([1,1])]), ....: Cone([m2*vector([1,1]), m2*vector([0,1])])]) - sage: sorted(fan_isomorphism_generator(fan0, fan0)) + sage: sorted(fan_isomorphism_generator(fan0, fan0)) # needs sage.graphs [ [0 1] [1 0] [1 0], [0 1] ] - sage: sorted(fan_isomorphism_generator(fan1, fan1)) + sage: sorted(fan_isomorphism_generator(fan1, fan1)) # needs sage.graphs [ [ -3 -20 28] [1 0 0] [ -1 -4 7] [0 1 0] [ -1 -5 8], [0 0 1] ] - sage: sorted(fan_isomorphism_generator(fan1, fan2)) + sage: sorted(fan_isomorphism_generator(fan1, fan2)) # needs sage.graphs [ [-24 -3 7] [-12 1 -5] [ -7 -1 2] [ -4 0 -1] [ -8 -1 2], [ -5 0 -1] ] - sage: sorted(fan_isomorphism_generator(fan2, fan1)) + sage: sorted(fan_isomorphism_generator(fan2, fan1)) # needs sage.graphs [ [ 0 1 -1] [ 0 1 -1] [ 1 -13 8] [ 2 -8 1] @@ -216,14 +216,14 @@ def find_isomorphism(fan1, fan2, check=False): sage: fan2 = Fan(cones, [vector(r)*m for r in rays]) sage: from sage.geometry.fan_isomorphism import find_isomorphism - sage: find_isomorphism(fan1, fan2, check=True) # optional - sage.graphs + sage: find_isomorphism(fan1, fan2, check=True) # needs sage.graphs Fan morphism defined by the matrix [-2 3] [ 1 -1] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N - sage: find_isomorphism(fan1, toric_varieties.P2().fan()) # optional - palp + sage: find_isomorphism(fan1, toric_varieties.P2().fan()) # needs palp sage.graphs Traceback (most recent call last): ... FanNotIsomorphicError @@ -232,7 +232,7 @@ def find_isomorphism(fan1, fan2, check=False): ....: rays=[(-1,-1,0),(-1,-1,3),(-1,1,-1),(-1,3,-1),(0,2,-1),(1,-1,1)]) sage: fan2 = Fan(cones=[[0,2,3,5],[0,1,4,5],[0,1,2],[3,4,5]], ....: rays=[(-1,-1,-1),(-1,-1,0),(-1,1,-1),(0,2,-1),(1,-1,1),(3,-1,-1)]) - sage: fan1.is_isomorphic(fan2) + sage: fan1.is_isomorphic(fan2) # needs sage.graphs True """ generator = fan_isomorphism_generator(fan1, fan2) @@ -311,14 +311,14 @@ def fan_2d_echelon_forms(fan): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_forms - sage: fan_2d_echelon_forms(fan) # optional - palp + sage: fan_2d_echelon_forms(fan) # needs palp sage.graphs frozenset({[ 1 0 -1] [ 0 1 -1]}) - sage: fan = toric_varieties.dP7().fan() # optional - palp - sage: sorted(fan_2d_echelon_forms(fan)) # optional - palp + sage: fan = toric_varieties.dP7().fan() # needs palp sage.graphs + sage: sorted(fan_2d_echelon_forms(fan)) # needs palp sage.graphs [ [ 1 0 -1 -1 0] [ 1 0 -1 -1 0] [ 1 0 -1 -1 1] [ 1 0 -1 0 1] [ 0 1 0 -1 -1], [ 0 1 1 0 -1], [ 0 1 1 0 -1], [ 0 1 0 -1 -1], @@ -334,10 +334,10 @@ def fan_2d_echelon_forms(fan): sage: fan1 = Fan(cones, rays) sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_form, fan_2d_echelon_forms sage: echelon_forms = fan_2d_echelon_forms(fan1) - sage: S4 = CyclicPermutationGroup(4) + sage: S4 = CyclicPermutationGroup(4) # needs sage.groups sage: rays.reverse() sage: cones = [(3,1), (1,2), (2,0), (0,3)] - sage: for i in range(100): + sage: for i in range(100): # needs sage.groups ....: m = random_matrix(ZZ,2,2) ....: if abs(det(m)) != 1: continue ....: perm = S4.random_element() @@ -382,9 +382,9 @@ def fan_2d_echelon_form(fan): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_form - sage: fan_2d_echelon_form(fan) # optional - palp + sage: fan_2d_echelon_form(fan) # needs palp sage.graphs [ 1 0 -1] [ 0 1 -1] """ diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index 2302c7551ee..1d3cd1db886 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -319,15 +319,15 @@ def __mul__(self, right): EXAMPLES:: sage: A2 = toric_varieties.A2() - sage: P3 = toric_varieties.P(3) # optional - palp + sage: P3 = toric_varieties.P(3) # needs palp sage: m = matrix([(2,0,0), (1,1,0)]) - sage: phi = A2.hom(m, P3).fan_morphism(); phi # optional - palp + sage: phi = A2.hom(m, P3).fan_morphism(); phi # needs palp Fan morphism defined by the matrix [2 0 0] [1 1 0] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: prod(phi.factor()) # indirect test # optional - palp + sage: prod(phi.factor()) # indirect test # needs palp Fan morphism defined by the matrix [2 0 0] [1 1 0] @@ -529,13 +529,14 @@ def _ray_index_map(self): TESTS:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: phi._ray_index_map() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: phi._ray_index_map() (-1, 1, -1, 0) - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: xi._ray_index_map() # optional - palp + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: xi._ray_index_map() Traceback (most recent call last): ... ValueError: ray #1 is mapped into a 2-d cone! @@ -1040,32 +1041,33 @@ def index(self, cone=None): EXAMPLES:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: phi.index() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: phi.index() 1 - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: psi.index() # optional - palp + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: psi.index() 2 - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: xi.index() # optional - palp + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: xi.index() +Infinity Infinite index in the last example indicates that the image has positive codimension in the codomain. Let's look at the rays of our fans:: - sage: Sigma_p.rays() + sage: Sigma_p.rays() # needs palp N( 1), N(-1) in 1-d lattice N - sage: Sigma.rays() # optional - palp + sage: Sigma.rays() # needs palp N( 1, 1), N( 0, 1), N(-1, -1), N( 1, 0) in 2-d lattice N - sage: xi.factor()[0].domain_fan().rays() # optional - palp + sage: xi.factor()[0].domain_fan().rays() # needs palp N(-1, 0), N( 1, 0) in Sublattice @@ -1081,25 +1083,26 @@ def index(self, cone=None): 1-d cones are ``None``, except for one which is infinite, and all indices over 2-d cones are ``None``, except for one which is 1:: - sage: [xi.index(cone) for cone in Sigma(1)] # optional - palp + sage: [xi.index(cone) for cone in Sigma(1)] # needs palp [None, None, None, +Infinity] - sage: [xi.index(cone) for cone in Sigma(2)] # optional - palp + sage: [xi.index(cone) for cone in Sigma(2)] # needs palp [None, 1, None, None] TESTS:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.Cube_nonpolyhedral().fan() sage: m = matrix([[2,6,10], [7,11,13]]) - sage: zeta = FanMorphism(m, Sigma, Sigma_p, subdivide=True) # optional - palp - sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] # optional - palp + sage: zeta = FanMorphism(m, Sigma, Sigma_p, subdivide=True) + sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] [+Infinity, None, None, None, None, None, None, None, None, None, 4, 4, None, 4, None, None, 2, None, 4, None, 4, 1, 1, 1, 1, 1, 1] - sage: zeta = prod(zeta.factor()[1:]) # optional - palp - sage: Sigma_p = zeta.codomain_fan() # optional - palp - sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] # optional - palp + sage: zeta = prod(zeta.factor()[1:]) + sage: Sigma_p = zeta.codomain_fan() + sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] [4, 4, 4, 1, 4, 4, 4, 1, 1, 1, 1, 1, 1] - sage: zeta.index() == zeta.index(Sigma_p(0)[0]) # optional - palp + sage: zeta.index() == zeta.index(Sigma_p(0)[0]) True """ if cone is None: @@ -1130,14 +1133,15 @@ def is_birational(self): EXAMPLES:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.index(), psi.index(), xi.index() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.index(), psi.index(), xi.index() (1, 2, +Infinity) - sage: phi.is_birational(), psi.is_birational(), xi.is_birational() # optional - palp + sage: phi.is_birational(), psi.is_birational(), xi.is_birational() (True, False, False) """ return self.index() == 1 @@ -1178,26 +1182,27 @@ def is_bundle(self): We consider several maps between fans of a del Pezzo surface and the projective line:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.is_bundle() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.is_bundle() True - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() True - sage: phi.index() # optional - palp + sage: phi.index() 1 - sage: psi.is_bundle() # optional - palp + sage: psi.is_bundle() False - sage: psi.is_fibration() # optional - palp + sage: psi.is_fibration() True - sage: psi.index() # optional - palp + sage: psi.index() 2 - sage: xi.is_fibration() # optional - palp + sage: xi.is_fibration() False - sage: xi.index() # optional - palp + sage: xi.index() +Infinity The first of these maps induces not only a fibration, but a fiber @@ -1270,26 +1275,27 @@ def is_fibration(self): We consider several maps between fans of a del Pezzo surface and the projective line:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.is_bundle() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.is_bundle() True - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() True - sage: phi.index() # optional - palp + sage: phi.index() 1 - sage: psi.is_bundle() # optional - palp + sage: psi.is_bundle() False - sage: psi.is_fibration() # optional - palp + sage: psi.is_fibration() True - sage: psi.index() # optional - palp + sage: psi.index() 2 - sage: xi.is_fibration() # optional - palp + sage: xi.is_fibration() False - sage: xi.index() # optional - palp + sage: xi.index() +Infinity The first of these maps induces not only a fibration, but a fiber @@ -1384,9 +1390,9 @@ def is_injective(self): We also embed the affine plane into the projective one:: - sage: P2 = toric_varieties.P(2).fan() # optional - palp + sage: P2 = toric_varieties.P(2).fan() # needs palp sage: m = identity_matrix(2) - sage: FanMorphism(m, A2, P2).is_injective() # optional - palp + sage: FanMorphism(m, A2, P2).is_injective() # needs palp True """ if self.matrix().index_in_saturation() != 1: @@ -1564,15 +1570,16 @@ def preimage_cones(self, cone): We check that reviewer's example from :trac:`9972` is handled correctly:: + sage: # needs palp sage: N1 = ToricLattice(1) sage: N2 = ToricLattice(2) sage: Hom21 = Hom(N2, N1) sage: pr = Hom21([N1.0,0]) - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: f = FanMorphism(pr, P1xP1.fan()) # optional - palp - sage: c = f.image_cone(Cone([(1,0), (0,1)])); c # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() + sage: f = FanMorphism(pr, P1xP1.fan()) + sage: c = f.image_cone(Cone([(1,0), (0,1)])); c 1-d cone of Rational polyhedral fan in 1-d lattice N - sage: f.preimage_cones(c) # optional - palp + sage: f.preimage_cones(c) (1-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N) @@ -1678,8 +1685,8 @@ def primitive_preimage_cones(self, cone): Consider a projection of a del Pezzo surface onto the projective line:: - sage: Sigma = toric_varieties.dP6().fan() # optional - palp - sage: Sigma.rays() # optional - palp + sage: Sigma = toric_varieties.dP6().fan() # needs palp + sage: Sigma.rays() # needs palp N( 0, 1), N(-1, 0), N(-1, -1), @@ -1688,7 +1695,7 @@ def primitive_preimage_cones(self, cone): N( 1, 1) in 2-d lattice N sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # needs palp Under this map, one pair of rays is mapped to the origin, one in the positive direction, and one in the negative one. Also three @@ -1696,28 +1703,28 @@ def primitive_preimage_cones(self, cone): the negative one, so there are 5 preimage cones corresponding to either of the rays of the codomain fan ``Sigma_p``:: - sage: len(phi.preimage_cones(Cone([(1,)]))) # optional - palp + sage: len(phi.preimage_cones(Cone([(1,)]))) # needs palp 5 Yet only rays are primitive:: - sage: phi.primitive_preimage_cones(Cone([(1,)])) # optional - palp + sage: phi.primitive_preimage_cones(Cone([(1,)])) # needs palp (1-d cone of Rational polyhedral fan in 2-d lattice N, 1-d cone of Rational polyhedral fan in 2-d lattice N) Since all primitive cones are mapped onto their images bijectively, we get a fibration:: - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() # needs palp True But since there are several primitive cones corresponding to the same cone of the codomain fan, this map is not a bundle, even though its index is 1:: - sage: phi.is_bundle() # optional - palp + sage: phi.is_bundle() # needs palp False - sage: phi.index() # optional - palp + sage: phi.index() # needs palp 1 """ sigma_p = self._codomain_fan.embed(cone) # Necessary if used as a key @@ -1771,10 +1778,10 @@ def factor(self): coordinate planes":: sage: A2 = toric_varieties.A2() - sage: P3 = toric_varieties.P(3) # optional - palp + sage: P3 = toric_varieties.P(3) # needs palp sage: m = matrix([(2,0,0), (1,1,0)]) - sage: phi = A2.hom(m, P3) # optional - palp - sage: phi.as_polynomial_map() # optional - palp + sage: phi = A2.hom(m, P3) # needs palp + sage: phi.as_polynomial_map() # needs palp Scheme morphism: From: 2-d affine toric variety To: 3-d CPR-Fano toric variety covered by 4 affine patches @@ -1783,18 +1790,19 @@ def factor(self): Now we will work with the underlying fan morphism:: - sage: phi = phi.fan_morphism(); phi # optional - palp + sage: # needs palp + sage: phi = phi.fan_morphism(); phi Fan morphism defined by the matrix [2 0 0] [1 1 0] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: phi.is_surjective(), phi.is_birational(), phi.is_injective() # optional - palp + sage: phi.is_surjective(), phi.is_birational(), phi.is_injective() (False, False, False) - sage: phi_i, phi_b, phi_s = phi.factor() # optional - palp - sage: phi_s.is_surjective(), phi_b.is_birational(), phi_i.is_injective() # optional - palp + sage: phi_i, phi_b, phi_s = phi.factor() + sage: phi_s.is_surjective(), phi_b.is_birational(), phi_i.is_injective() (True, True, True) - sage: prod(phi.factor()) == phi # optional - palp + sage: prod(phi.factor()) == phi True Double cover (surjective):: @@ -1803,26 +1811,26 @@ def factor(self): N(1, 0), N(0, 1) in 2-d lattice N - sage: phi_s # optional - palp + sage: phi_s # needs palp Fan morphism defined by the matrix [2 0] [1 1] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in Sublattice - sage: phi_s.codomain_fan().rays() # optional - palp + sage: phi_s.codomain_fan().rays() # needs palp N(1, 0, 0), N(1, 1, 0) in Sublattice Blowup chart (birational):: - sage: phi_b # optional - palp + sage: phi_b # needs palp Fan morphism defined by the matrix [1 0] [0 1] Domain fan: Rational polyhedral fan in Sublattice Codomain fan: Rational polyhedral fan in Sublattice - sage: phi_b.codomain_fan().rays() # optional - palp + sage: phi_b.codomain_fan().rays() # needs palp N(-1, -1, 0), N( 0, 1, 0), N( 1, 0, 0) @@ -1830,13 +1838,13 @@ def factor(self): Coordinate plane inclusion (injective):: - sage: phi_i # optional - palp + sage: phi_i # needs palp Fan morphism defined by the matrix [1 0 0] [0 1 0] Domain fan: Rational polyhedral fan in Sublattice Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: phi.codomain_fan().rays() # optional - palp + sage: phi.codomain_fan().rays() # needs palp N( 1, 0, 0), N( 0, 1, 0), N( 0, 0, 1), @@ -1845,16 +1853,17 @@ def factor(self): TESTS:: - sage: phi_s.matrix() * phi_b.matrix() * phi_i.matrix() == m # optional - palp + sage: phi_s.matrix() * phi_b.matrix() * phi_i.matrix() == m # needs palp True - sage: phi.domain_fan() is phi_s.domain_fan() # optional - palp + sage: # needs palp + sage: phi.domain_fan() is phi_s.domain_fan() True - sage: phi_s.codomain_fan() is phi_b.domain_fan() # optional - palp + sage: phi_s.codomain_fan() is phi_b.domain_fan() True - sage: phi_b.codomain_fan() is phi_i.domain_fan() # optional - palp + sage: phi_b.codomain_fan() is phi_i.domain_fan() True - sage: phi_i.codomain_fan() is phi.codomain_fan() # optional - palp + sage: phi_i.codomain_fan() is phi.codomain_fan() True sage: trivialfan2 = Fan([], [], lattice=ToricLattice(2)) diff --git a/src/sage/geometry/hasse_diagram.py b/src/sage/geometry/hasse_diagram.py index f40560f30fe..d30f08ac8d5 100644 --- a/src/sage/geometry/hasse_diagram.py +++ b/src/sage/geometry/hasse_diagram.py @@ -104,9 +104,9 @@ def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, and we can compute the lattice as :: sage: from sage.geometry.cone import lattice_from_incidences - sage: L = lattice_from_incidences(atom_to_coatoms, coatom_to_atoms); L # optional - sage.graphs + sage: L = lattice_from_incidences(atom_to_coatoms, coatom_to_atoms); L # needs sage.graphs Finite lattice containing 8 elements with distinguished linear extension - sage: for level in L.level_sets(): print(level) # optional - sage.graphs + sage: for level in L.level_sets(): print(level) # needs sage.graphs [((), (0, 1, 2))] [((0,), (0, 1)), ((1,), (0, 2)), ((2,), (1, 2))] [((0, 1), (0,)), ((0, 2), (1,)), ((1, 2), (2,))] diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 45c8efb11ed..9f6d5725f68 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -24,7 +24,7 @@ :: - sage: g.plot(axes=True) # optional - sage.plot + sage: g.plot(axes=True) # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -37,7 +37,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3 + I) sage: g.length() arccosh(11/2) - sage: g.plot(axes=True) # optional - sage.plot + sage: g.plot(axes=True) # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -49,7 +49,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I) sage: g Geodesic in UHP from I to 3*I - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1126,7 +1126,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() - sage: UHP.get_geodesic(0, 1).plot() # optional - sage.plot + sage: UHP.get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1137,7 +1137,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") # optional - sage.plot + sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1148,7 +1148,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(1, infinity).plot(color='orange') # optional - sage.plot + sage: UHP.get_geodesic(1, infinity).plot(color='orange') # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1162,25 +1162,25 @@ def plot(self, boundary=True, **options): Plotting a line with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives Plotting a line with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot(boundary=False) # optional - sage.plot + sage: g.plot(boundary=False) # needs sage.plot Graphics object consisting of 1 graphics primitive Plotting a circle with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(-3, 19) - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives Plotting a circle with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(3, 4) - sage: g.plot(boundary=False) # optional - sage.plot + sage: g.plot(boundary=False) # needs sage.plot Graphics object consisting of 1 graphics primitive """ @@ -2202,7 +2202,7 @@ def plot(self, boundary=True, **options): First some lines:: sage: PD = HyperbolicPlane().PD() - sage: PD.get_geodesic(0, 1).plot() # optional - sage.plot + sage: PD.get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2211,7 +2211,7 @@ def plot(self, boundary=True, **options): :: - sage: PD.get_geodesic(0, 0.3+0.8*I).plot() # optional - sage.plot + sage: PD.get_geodesic(0, 0.3+0.8*I).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2221,15 +2221,15 @@ def plot(self, boundary=True, **options): Then some generic geodesics:: - sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() # optional - sage.plot + sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives sage: g = PD.get_geodesic(-1, exp(3*I*pi/7)) - sage: G = g.plot(linestyle="dashed",color="red"); G # optional - sage.plot + sage: G = g.plot(linestyle="dashed",color="red"); G # needs sage.plot Graphics object consisting of 2 graphics primitives sage: h = PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)) - sage: H = h.plot(thickness=6, color="orange"); H # optional - sage.plot + sage: H = h.plot(thickness=6, color="orange"); H # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: show(G+H) # optional - sage.plot + sage: show(G+H) # needs sage.plot .. PLOT:: @@ -2293,7 +2293,7 @@ class HyperbolicGeodesicKM(HyperbolicGeodesic): sage: KM = HyperbolicPlane().KM() sage: g = KM.get_geodesic((0.1,0.9),(-0.1,-0.9)) sage: h = KM.get_geodesic((-0.707106781,-0.707106781),(0.707106781,-0.707106781)) - sage: P = g.plot(color='orange')+h.plot(); P # optional - sage.plot + sage: P = g.plot(color='orange')+h.plot(); P # needs sage.plot Graphics object consisting of 4 graphics primitives .. PLOT:: @@ -2313,7 +2313,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: - sage: HyperbolicPlane().KM().get_geodesic(0, 1).plot() # optional - sage.plot + sage: HyperbolicPlane().KM().get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2424,7 +2424,7 @@ def plot(self, show_hyperboloid=True, **graphics_options): sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic \ ....: import * sage: g = HyperbolicPlane().HM().random_geodesic() - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics3d Object .. PLOT:: diff --git a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py index 3b024b6f419..7c1065553c4 100644 --- a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py +++ b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py @@ -33,8 +33,8 @@ True sage: c < b False - sage: A = AffineSubspace([8,38,21,250], VectorSpace(GF(19),4)) # optional - sage.libs.pari - sage: A # optional - sage.libs.pari + sage: A = AffineSubspace([8,38,21,250], VectorSpace(GF(19),4)) + sage: A Affine space p + W where: p = (8, 0, 2, 3) W = Vector space of dimension 4 over Finite Field of size 19 @@ -384,9 +384,9 @@ def intersection(self, other): [] sage: A.intersection(C).intersection(B) - sage: D = AffineSubspace([1,2,3], VectorSpace(GF(5),3)) # optional - sage.libs.pari - sage: E = AffineSubspace([3,4,5], VectorSpace(GF(5),3)) # optional - sage.libs.pari - sage: D.intersection(E) # optional - sage.libs.pari + sage: D = AffineSubspace([1,2,3], VectorSpace(GF(5),3)) + sage: E = AffineSubspace([3,4,5], VectorSpace(GF(5),3)) + sage: D.intersection(E) Affine space p + W where: p = (3, 4, 0) W = Vector space of dimension 3 over Finite Field of size 5 diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 7cc2b479573..ee8962019ae 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -60,42 +60,43 @@ The default base field is `\QQ`, the rational numbers. Finite fields are also supported:: - sage: H. = HyperplaneArrangements(GF(5)) # optional - sage.rings.finite_rings - sage: a = H([(1,2,3), 4], [(5,6,7), 8]); a # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(5)) + sage: a = H([(1,2,3), 4], [(5,6,7), 8]); a Arrangement Number fields are also possible:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') - sage: NF. = NumberField(x**4 - 5*x**2 + 5, embedding=1.90) # optional - sage.rings.number_field - sage: H. = HyperplaneArrangements(NF) # optional - sage.rings.number_field - sage: A = H([[(-a**3 + 3*a, -a**2 + 4), 1], [(a**3 - 4*a, -1), 1], # optional - sage.rings.number_field + sage: NF. = NumberField(x**4 - 5*x**2 + 5, embedding=1.90) + sage: H. = HyperplaneArrangements(NF) + sage: A = H([[(-a**3 + 3*a, -a**2 + 4), 1], [(a**3 - 4*a, -1), 1], ....: [(0, 2*a**2 - 6), 1], [(-a**3 + 4*a, -1), 1], ....: [(a**3 - 3*a, -a**2 + 4), 1]]) - sage: A # optional - sage.rings.number_field + sage: A Arrangement of 5 hyperplanes of dimension 2 and rank 2 - sage: A.base_ring() # optional - sage.rings.number_field + sage: A.base_ring() Number Field in a with defining polynomial x^4 - 5*x^2 + 5 with a = 1.902113032590308? Notation (iii): a list or tuple of hyperplanes:: - sage: H. = HyperplaneArrangements(GF(5)) # optional - sage.rings.finite_rings - sage: k = [x+i for i in range(4)]; k # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(5)) + sage: k = [x+i for i in range(4)]; k [Hyperplane x + 0*y + 0*z + 0, Hyperplane x + 0*y + 0*z + 1, Hyperplane x + 0*y + 0*z + 2, Hyperplane x + 0*y + 0*z + 3] - sage: H(k) # optional - sage.rings.finite_rings + sage: H(k) Arrangement Notation (iv): using the library of arrangements:: - sage: hyperplane_arrangements.braid(4) # optional - sage.graphs + sage: hyperplane_arrangements.braid(4) # needs sage.graphs Arrangement of 6 hyperplanes of dimension 4 and rank 3 - sage: hyperplane_arrangements.semiorder(3) # optional - sage.combinat + sage: hyperplane_arrangements.semiorder(3) Arrangement of 6 hyperplanes of dimension 3 and rank 2 - sage: hyperplane_arrangements.graphical(graphs.PetersenGraph()) # optional - sage.graphs + sage: hyperplane_arrangements.graphical(graphs.PetersenGraph()) # needs sage.graphs Arrangement of 15 hyperplanes of dimension 10 and rank 9 - sage: hyperplane_arrangements.Ish(5) # optional - sage.combinat + sage: hyperplane_arrangements.Ish(5) Arrangement of 20 hyperplanes of dimension 5 and rank 4 Notation (v): from the bounding hyperplanes of a polyhedron:: @@ -107,21 +108,23 @@ New arrangements from old:: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: b = a.add_hyperplane([4, 1, 2, 3]) # optional - sage.graphs - sage: b # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: b = a.add_hyperplane([4, 1, 2, 3]) + sage: b Arrangement - sage: c = b.deletion([4, 1, 2, 3]) # optional - sage.graphs - sage: a == c # optional - sage.graphs + sage: c = b.deletion([4, 1, 2, 3]) + sage: a == c True - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs sage.combinat - sage: b = a.union(hyperplane_arrangements.semiorder(3)) # optional - sage.graphs sage.combinat - sage: b == a | hyperplane_arrangements.semiorder(3) # alternate syntax # optional - sage.graphs sage.combinat + sage: # needs sage.combinat sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: b = a.union(hyperplane_arrangements.semiorder(3)) + sage: b == a | hyperplane_arrangements.semiorder(3) # alternate syntax True - sage: b == hyperplane_arrangements.Catalan(3) # optional - sage.graphs sage.combinat + sage: b == hyperplane_arrangements.Catalan(3) True - sage: a # optional - sage.graphs sage.combinat + sage: a Arrangement sage: a = hyperplane_arrangements.coordinate(4) @@ -139,24 +142,25 @@ normal space (actually, it is a bit more complicated over finite fields):: - sage: a = hyperplane_arrangements.braid(4); a # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(4); a Arrangement of 6 hyperplanes of dimension 4 and rank 3 - sage: a.is_essential() # optional - sage.graphs + sage: a.is_essential() False - sage: a.rank() < a.dimension() # double-check # optional - sage.graphs + sage: a.rank() < a.dimension() # double-check True - sage: a.essentialization() # optional - sage.graphs + sage: a.essentialization() Arrangement of 6 hyperplanes of dimension 3 and rank 3 The connected components of the complement of the hyperplanes of an arrangement in `\RR^n` are called the *regions* of the arrangement:: - sage: a = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: b = a.essentialization(); b # optional - sage.combinat + sage: a = hyperplane_arrangements.semiorder(3) + sage: b = a.essentialization(); b Arrangement of 6 hyperplanes of dimension 2 and rank 2 - sage: b.n_regions() # optional - sage.combinat + sage: b.n_regions() 19 - sage: b.regions() # optional - sage.combinat + sage: b.regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 6 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, @@ -184,9 +188,9 @@ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices) - sage: b.n_bounded_regions() # optional - sage.combinat + sage: b.n_bounded_regions() 7 - sage: a.unbounded_regions() # optional - sage.combinat + sage: a.unbounded_regions() (A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, @@ -203,13 +207,14 @@ The distance between regions is defined as the number of hyperplanes separating them. For example:: - sage: r1 = b.regions()[0] # optional - sage.combinat - sage: r2 = b.regions()[1] # optional - sage.combinat - sage: b.distance_between_regions(r1, r2) # optional - sage.combinat + sage: # needs sage.combinat + sage: r1 = b.regions()[0] + sage: r2 = b.regions()[1] + sage: b.distance_between_regions(r1, r2) 1 - sage: [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)] # optional - sage.combinat + sage: [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)] [Hyperplane 2*t1 + t2 + 1] - sage: b.distance_enumerator(r1) # generating function for distances from r1 # optional - sage.combinat + sage: b.distance_enumerator(r1) # generating function for distances from r1 6*x^3 + 6*x^2 + 6*x + 1 .. NOTE:: @@ -223,11 +228,12 @@ ordered by reverse inclusion. It includes the ambient space of the arrangement (as the intersection over the empty set):: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: p = a.intersection_poset() # optional - sage.graphs - sage: p.is_ranked() # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: p = a.intersection_poset() + sage: p.is_ranked() True - sage: p.order_polytope() # optional - sage.graphs + sage: p.order_polytope() A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 10 vertices The characteristic polynomial is a basic invariant of a hyperplane @@ -241,19 +247,20 @@ :meth:`~HyperplaneArrangementElement.intersection_poset` of the arrangement and `\mu` is the Möbius function of `P`:: + sage: # long time sage: a = hyperplane_arrangements.semiorder(5) - sage: a.characteristic_polynomial() # long time (about a second on Core i7) + sage: a.characteristic_polynomial() # about a second on Core i7 x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x - sage: a.poincare_polynomial() # long time + sage: a.poincare_polynomial() 1380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1 - sage: a.n_regions() # long time + sage: a.n_regions() 2371 - sage: charpoly = a.characteristic_polynomial() # long time - sage: charpoly(-1) # long time + sage: charpoly = a.characteristic_polynomial() + sage: charpoly(-1) -2371 - sage: a.n_bounded_regions() # long time + sage: a.n_bounded_regions() 751 - sage: charpoly(1) # long time + sage: charpoly(1) 751 For finer invariants derived from the intersection poset, see @@ -263,16 +270,16 @@ Miscellaneous methods (see documentation for an explanation):: sage: a = hyperplane_arrangements.semiorder(3) - sage: a.has_good_reduction(5) # optional - sage.rings.finite_rings + sage: a.has_good_reduction(5) # needs sage.rings.finite_rings True - sage: b = a.change_ring(GF(5)) # optional - sage.rings.finite_rings - sage: pa = a.intersection_poset() - sage: pb = b.intersection_poset() # optional - sage.rings.finite_rings - sage: pa.is_isomorphic(pb) # optional - sage.rings.finite_rings + sage: b = a.change_ring(GF(5)) + sage: pa = a.intersection_poset() # needs sage.graphs + sage: pb = b.intersection_poset() # needs sage.rings.finite_rings + sage: pa.is_isomorphic(pb) # needs sage.graphs sage.rings.finite_rings True - sage: a.face_vector() + sage: a.face_vector() # needs sage.graphs (0, 12, 30, 19) - sage: a.face_vector() + sage: a.face_vector() # needs sage.graphs (0, 12, 30, 19) sage: a.is_central() False @@ -394,13 +401,14 @@ def __init__(self, parent, hyperplanes, check=True, backend=None): It is possible to specify a backend for polyhedral computations:: - sage: R. = QuadraticField(5) # optional - sage.rings.number_field - sage: H = HyperplaneArrangements(R, names='xyz') # optional - sage.rings.number_field - sage: x, y, z = H.gens() # optional - sage.rings.number_field - sage: A = H(sqrt5*x + 2*y + 3*z, backend='normaliz') # optional - sage.rings.number_field - sage: A.backend() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QuadraticField(5) + sage: H = HyperplaneArrangements(R, names='xyz') + sage: x, y, z = H.gens() + sage: A = H(sqrt5*x + 2*y + 3*z, backend='normaliz') + sage: A.backend() 'normaliz' - sage: A.regions()[0].backend() # optional - pynormaliz sage.rings.number_field + sage: A.regions()[0].backend() # optional - pynormaliz 'normaliz' """ super().__init__(parent) @@ -424,8 +432,8 @@ def _first_ngens(self, n): EXAMPLES:: - sage: a. = hyperplane_arrangements.braid(3) # indirect doctest # optional - sage.graphs - sage: (x, y) == a._first_ngens(2) # optional - sage.graphs + sage: a. = hyperplane_arrangements.braid(3) # indirect doctest # needs sage.graphs + sage: (x, y) == a._first_ngens(2) # needs sage.graphs True """ return self.parent()._first_ngens(n) @@ -570,14 +578,15 @@ def rank(self): sage: A.rank() 2 - sage: B = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: B.hyperplanes() # optional - sage.graphs + sage: # needs sage.graphs + sage: B = hyperplane_arrangements.braid(3) + sage: B.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) - sage: B.dimension() # optional - sage.graphs + sage: B.dimension() 3 - sage: B.rank() # optional - sage.graphs + sage: B.rank() 2 sage: p = polytopes.simplex(5, project=True) @@ -689,7 +698,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L. = HyperplaneArrangements(QQ) - sage: L(x, y, x+y-2).plot() # optional - sage.plot + sage: L(x, y, x+y-2).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot @@ -720,20 +729,21 @@ def cone(self, variable='t'): EXAMPLES:: - sage: a. = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: b = a.cone() # optional - sage.combinat - sage: a.characteristic_polynomial().factor() # optional - sage.combinat + sage: # needs sage.combinat + sage: a. = hyperplane_arrangements.semiorder(3) + sage: b = a.cone() + sage: a.characteristic_polynomial().factor() x * (x^2 - 6*x + 12) - sage: b.characteristic_polynomial().factor() # optional - sage.combinat + sage: b.characteristic_polynomial().factor() (x - 1) * x * (x^2 - 6*x + 12) - sage: a.hyperplanes() # optional - sage.combinat + sage: a.hyperplanes() (Hyperplane 0*x + y - z - 1, Hyperplane 0*x + y - z + 1, Hyperplane x - y + 0*z - 1, Hyperplane x - y + 0*z + 1, Hyperplane x + 0*y - z - 1, Hyperplane x + 0*y - z + 1) - sage: b.hyperplanes() # optional - sage.combinat + sage: b.hyperplanes() (Hyperplane -t + 0*x + y - z + 0, Hyperplane -t + x - y + 0*z + 0, Hyperplane -t + x + 0*y - z + 0, @@ -781,21 +791,22 @@ def intersection_poset(self, element_label="int"): of hyperplanes of the arrangement. :: sage: A = hyperplane_arrangements.coordinate(2) - sage: L = A.intersection_poset(); L # optional - sage.combinat + sage: L = A.intersection_poset(); L # needs sage.combinat Finite poset containing 4 elements - sage: sorted(L) # optional - sage.combinat + sage: sorted(L) # needs sage.combinat [0, 1, 2, 3] - sage: L.level_sets() # optional - sage.combinat + sage: L.level_sets() # needs sage.combinat [[0], [1, 2], [3]] :: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: L = A.intersection_poset(); L # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: L = A.intersection_poset(); L Finite poset containing 19 elements - sage: sorted(L) # optional - sage.combinat + sage: sorted(L) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] - sage: [sorted(level_set) for level_set in L.level_sets()] # optional - sage.combinat + sage: [sorted(level_set) for level_set in L.level_sets()] [[0], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]] By passing the argument ``element_label="subset"``, each element of the @@ -803,9 +814,9 @@ def intersection_poset(self, element_label="int"): whose intersection is said element. The index of a hyperplane is its index in ``self.hyperplanes()``. :: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: L = A.intersection_poset(element_label='subset') # optional - sage.combinat - sage: [sorted(level, key=sorted) for level in L.level_sets()] # optional - sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat + sage: [sorted(level, key=sorted) for level in L.level_sets()] # needs sage.combinat [[{}], [{0}, {1}, {2}, {3}, {4}, {5}], [{0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 5}, {3, 4}, {3, 5}]] @@ -814,17 +825,17 @@ def intersection_poset(self, element_label="int"): sage: H. = HyperplaneArrangements(QQ) sage: A = H((y, y-1, y+1, x-y, x+y)) - sage: L = A.intersection_poset(element_label='subset') # optional - sage.combinat - sage: sorted(L, key=sorted) # optional - sage.combinat + sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat + sage: sorted(L, key=sorted) # needs sage.combinat [{}, {0}, {0, 3}, {0, 4}, {1}, {1, 3, 4}, {2}, {2, 3}, {2, 4}, {3}, {4}] One can instead use affine subspaces as elements, which is what is used to compute the poset in the first place:: sage: A = hyperplane_arrangements.coordinate(2) - sage: L = A.intersection_poset(element_label='subspace'); L # optional - sage.combinat + sage: L = A.intersection_poset(element_label='subspace'); L # needs sage.combinat Finite poset containing 4 elements - sage: sorted(L, key=lambda S: (S.dimension(), # optional - sage.combinat + sage: sorted(L, key=lambda S: (S.dimension(), # needs sage.combinat ....: S.linear_part().basis_matrix())) [Affine space p + W where: p = (0, 0) @@ -905,7 +916,7 @@ def _slow_characteristic_polynomial(self): EXAMPLES:: sage: a = hyperplane_arrangements.coordinate(2) - sage: a._slow_characteristic_polynomial() # optional - sage.combinat + sage: a._slow_characteristic_polynomial() # needs sage.combinat x^2 - 2*x + 1 """ from sage.rings.polynomial.polynomial_ring import polygen @@ -1050,20 +1061,21 @@ def restriction(self, hyperplane): EXAMPLES:: - sage: A. = hyperplane_arrangements.braid(4); A # optional - sage.graphs + sage: # needs sage.graphs + sage: A. = hyperplane_arrangements.braid(4); A Arrangement of 6 hyperplanes of dimension 4 and rank 3 - sage: H = A[0]; H # optional - sage.graphs + sage: H = A[0]; H Hyperplane 0*u + 0*x + y - z + 0 - sage: R = A.restriction(H); R # optional - sage.graphs + sage: R = A.restriction(H); R Arrangement - sage: D = A.deletion(H); D # optional - sage.graphs + sage: D = A.deletion(H); D Arrangement of 5 hyperplanes of dimension 4 and rank 3 - sage: ca = A.characteristic_polynomial() # optional - sage.graphs - sage: cr = R.characteristic_polynomial() # optional - sage.graphs - sage: cd = D.characteristic_polynomial() # optional - sage.graphs - sage: ca # optional - sage.graphs + sage: ca = A.characteristic_polynomial() + sage: cr = R.characteristic_polynomial() + sage: cd = D.characteristic_polynomial() + sage: ca x^4 - 6*x^3 + 11*x^2 - 6*x - sage: cd - cr # optional - sage.graphs + sage: cd - cr x^4 - 6*x^3 + 11*x^2 - 6*x .. SEEALSO:: @@ -1130,7 +1142,7 @@ def change_ring(self, base_ring): sage: H. = HyperplaneArrangements(QQ) sage: A = H([(1,1), 0], [(2,3), -1]) - sage: A.change_ring(FiniteField(2)) # optional - sage.rings.finite_rings + sage: A.change_ring(FiniteField(2)) Arrangement TESTS: @@ -1158,38 +1170,39 @@ def n_regions(self): EXAMPLES:: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: A.n_regions() # optional - sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: A.n_regions() 19 TESTS:: sage: H. = HyperplaneArrangements(QQ) sage: A = H([(1,1), 0], [(2,3), -1], [(4,5), 3]) - sage: B = A.change_ring(FiniteField(7)) # optional - sage.rings.finite_rings - sage: B.n_regions() # optional - sage.rings.finite_rings + sage: B = A.change_ring(FiniteField(7)) + sage: B.n_regions() Traceback (most recent call last): ... TypeError: base field must have characteristic zero Check that :trac:`30749` is fixed:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: v1 = AA.polynomial_root(AA.common_polynomial(y^2 - 3), # optional - sage.rings.number_field + sage: v1 = AA.polynomial_root(AA.common_polynomial(y^2 - 3), ....: RIF(RR(1.7320508075688772), RR(1.7320508075688774))) - sage: v2 = QQbar.polynomial_root(AA.common_polynomial(y^4 - y^2 + 1), # optional - sage.rings.number_field + sage: v2 = QQbar.polynomial_root(AA.common_polynomial(y^4 - y^2 + 1), ....: CIF(RIF(RR(0.8660254037844386), RR(0.86602540378443871)), ....: RIF(-RR(0.50000000000000011), -RR(0.49999999999999994)))) - sage: my_vectors = (vector(AA, [-v1, -1, 1]), vector(AA, [0, 2, 1]), vector(AA, [v1, -1, 1]), # optional - sage.rings.number_field + sage: my_vectors = (vector(AA, [-v1, -1, 1]), vector(AA, [0, 2, 1]), vector(AA, [v1, -1, 1]), ....: vector(AA, [1, 0, 0]), vector(AA, [1/2, AA(-1/2*v2^3 + v2),0]), ....: vector(AA, [-1/2, AA(-1/2*v2^3 + v2), 0])) - sage: H = HyperplaneArrangements(AA, names='xyz') # optional - sage.rings.number_field - sage: x,y,z = H.gens() # optional - sage.rings.number_field - sage: A = H(backend="normaliz") # optional - pynormaliz # optional - sage.rings.number_field - sage: for v in my_vectors: # optional - pynormaliz # optional - sage.rings.number_field + sage: H = HyperplaneArrangements(AA, names='xyz') + sage: x,y,z = H.gens() + sage: A = H(backend="normaliz") # optional - pynormaliz + sage: for v in my_vectors: # optional - pynormaliz ....: a, b, c = v ....: A = A.add_hyperplane(a*x + b*y + c*z) - sage: A.n_regions() # optional - pynormaliz # optional - sage.rings.number_field + sage: A.n_regions() # optional - pynormaliz 24 """ if self.base_ring().characteristic() != 0: @@ -1209,16 +1222,16 @@ def n_bounded_regions(self): EXAMPLES:: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: A.n_bounded_regions() # optional - sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: A.n_bounded_regions() 7 TESTS:: sage: H. = HyperplaneArrangements(QQ) sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3]) - sage: B = A.change_ring(FiniteField(7)) # optional - sage.rings.finite_rings - sage: B.n_bounded_regions() # optional - sage.rings.finite_rings + sage: B = A.change_ring(FiniteField(7)) + sage: B.n_bounded_regions() Traceback (most recent call last): ... TypeError: base field must have characteristic zero @@ -1248,15 +1261,16 @@ def has_good_reduction(self, p): EXAMPLES:: - sage: a = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: a.has_good_reduction(5) # optional - sage.combinat sage.rings.finite_rings + sage: # needs sage.combinat + sage: a = hyperplane_arrangements.semiorder(3) + sage: a.has_good_reduction(5) True - sage: a.has_good_reduction(3) # optional - sage.combinat sage.rings.finite_rings + sage: a.has_good_reduction(3) False - sage: b = a.change_ring(GF(3)) # optional - sage.combinat sage.rings.finite_rings - sage: a.characteristic_polynomial() # optional - sage.combinat sage.rings.finite_rings + sage: b = a.change_ring(GF(3)) + sage: a.characteristic_polynomial() x^3 - 6*x^2 + 12*x - sage: b.characteristic_polynomial() # not equal to that for a # optional - sage.combinat sage.rings.finite_rings + sage: b.characteristic_polynomial() # not equal to that for a x^3 - 6*x^2 + 10*x """ if self.base_ring() != QQ: @@ -1279,11 +1293,11 @@ def is_linear(self): EXAMPLES:: - sage: a = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: a.is_linear() # optional - sage.combinat + sage: a = hyperplane_arrangements.semiorder(3) + sage: a.is_linear() False - sage: b = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: b.is_linear() # optional - sage.graphs + sage: b = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: b.is_linear() # needs sage.graphs True sage: H. = HyperplaneArrangements(QQ) @@ -1345,8 +1359,8 @@ def is_central(self, certificate=False): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(2) # optional - sage.graphs - sage: a.is_central() # optional - sage.graphs + sage: a = hyperplane_arrangements.braid(2) # needs sage.graphs + sage: a.is_central() # needs sage.graphs True The Catalan arrangement in dimension 3 is not central:: @@ -1421,15 +1435,15 @@ def center(self): The Shi arrangement in dimension 3 has an empty center:: - sage: A = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: A.center() # optional - sage.combinat + sage: A = hyperplane_arrangements.Shi(3) + sage: A.center() The empty polyhedron in QQ^3 The Braid arrangement in dimension 3 has a center that is neither empty nor full-dimensional:: - sage: A = hyperplane_arrangements.braid(3) # optional - sage.combinat - sage: A.center() # optional - sage.combinat + sage: A = hyperplane_arrangements.braid(3) # needs sage.combinat + sage: A.center() # needs sage.combinat A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line """ return self.is_central(certificate=True)[1] @@ -1459,7 +1473,7 @@ def is_simplicial(self): sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) sage: A.is_simplicial() False - sage: hyperplane_arrangements.braid(3).is_simplicial() # optional - sage.graphs + sage: hyperplane_arrangements.braid(3).is_simplicial() # needs sage.graphs True """ # if the arr is not essential, grab the essential version and check there. @@ -1485,10 +1499,10 @@ def essentialization(self): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: a.is_essential() # optional - sage.graphs + sage: a = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: a.is_essential() # needs sage.graphs False - sage: a.essentialization() # optional - sage.graphs + sage: a.essentialization() # needs sage.graphs Arrangement sage: H. = HyperplaneArrangements(QQ) @@ -1501,13 +1515,13 @@ def essentialization(self): Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x - sage: H. = HyperplaneArrangements(GF(2)) # optional - sage.rings.finite_rings - sage: C = H([(1,1),1], [(1,1),0]) # optional - sage.rings.finite_rings - sage: C.essentialization() # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(2)) + sage: C = H([(1,1),1], [(1,1),0]) + sage: C.essentialization() Arrangement - sage: h = hyperplane_arrangements.semiorder(4) # optional - sage.combinat - sage: h.essentialization() # optional - sage.combinat + sage: h = hyperplane_arrangements.semiorder(4) + sage: h.essentialization() Arrangement of 12 hyperplanes of dimension 3 and rank 3 TESTS:: @@ -1593,9 +1607,9 @@ def sign_vector(self, p): TESTS:: - sage: H. = HyperplaneArrangements(GF(3)) # optional - sage.rings.finite_rings - sage: A = H(x, y) # optional - sage.rings.finite_rings - sage: A.sign_vector([1, 2]) # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(3)) + sage: A = H(x, y) + sage: A.sign_vector([1, 2]) Traceback (most recent call last): ... ValueError: characteristic must be zero @@ -1622,8 +1636,8 @@ def face_vector(self): EXAMPLES:: - sage: A = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: A.face_vector() # optional - sage.combinat + sage: A = hyperplane_arrangements.Shi(3) + sage: A.face_vector() # needs sage.combinat (0, 6, 21, 16) """ m = self.whitney_data()[0] @@ -1662,7 +1676,7 @@ def _parallel_hyperplanes(self): (Hyperplane x + 2*y + 0, (1, 2), 0), (Hyperplane 2*x + 4*y + 1, (1, 2), 1/2)) - sage: hyperplane_arrangements.Shi(3)._parallel_hyperplanes() # optional - sage.combinat + sage: hyperplane_arrangements.Shi(3)._parallel_hyperplanes() (((Hyperplane 0*t0 + t1 - t2 - 1, (0, 1, -1), -1), (Hyperplane 0*t0 + t1 - t2 + 0, (0, 1, -1), 0)), ((Hyperplane t0 - t1 + 0*t2 - 1, (1, -1, 0), -1), @@ -1705,14 +1719,15 @@ def vertices(self, exclude_sandwiched=False): EXAMPLES:: - sage: A = hyperplane_arrangements.Shi(3).essentialization() # optional - sage.combinat - sage: A.dimension() # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.Shi(3).essentialization() + sage: A.dimension() 2 - sage: A.face_vector() # optional - sage.combinat + sage: A.face_vector() (6, 21, 16) - sage: A.vertices() # optional - sage.combinat + sage: A.vertices() ((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3)) - sage: point2d(A.vertices(), size=20) + A.plot() # optional - sage.combinat sage.plot + sage: point2d(A.vertices(), size=20) + A.plot() # needs sage.plot Graphics object consisting of 7 graphics primitives sage: H. = HyperplaneArrangements(QQ) @@ -1782,7 +1797,7 @@ def _make_region(self, hyperplanes): Checks that it creates the regions with the appropriate backend:: - sage: h = H(x,backend='normaliz') # optional - pynormaliz + sage: h = H(x,backend='normaliz') sage: h._make_region([x, 1-x, y, 1-y]).backend() # optional - pynormaliz 'normaliz' """ @@ -1808,8 +1823,8 @@ def regions(self): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(2) # optional - sage.graphs - sage: a.regions() # optional - sage.graphs + sage: a = hyperplane_arrangements.braid(2) # needs sage.graphs + sage: a.regions() # needs sage.graphs (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, A 2-dimensional polyhedron in QQ^2 defined @@ -1863,21 +1878,22 @@ def regions(self): It is possible to specify the backend:: - sage: K. = CyclotomicField(9) # optional - sage.rings.number_field - sage: L. = NumberField((q + q**(-1)).minpoly(), # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(9) + sage: L. = NumberField((q + q**(-1)).minpoly(), ....: embedding=AA(q + q**-1)) - sage: norms = [[1, 1/3*(-2*r9**2-r9+1), 0], # optional - sage.rings.number_field + sage: norms = [[1, 1/3*(-2*r9**2-r9+1), 0], ....: [1, -r9**2 - r9, 0], ....: [1, -r9**2 + 1, 0], ....: [1, -r9**2, 0], ....: [1, r9**2 - 4, -r9**2+3]] - sage: H. = HyperplaneArrangements(L) # optional - sage.rings.number_field - sage: A = H(backend='normaliz') # optional - sage.rings.number_field - sage: for v in norms: # optional - sage.rings.number_field + sage: H. = HyperplaneArrangements(L) + sage: A = H(backend='normaliz') + sage: for v in norms: ....: a,b,c = v ....: A = A.add_hyperplane(a*x + b*y + c*z) - sage: R = A.regions() # optional - pynormaliz sage.rings.number_field - sage: R[0].backend() # optional - pynormaliz sage.rings.number_field + sage: R = A.regions() # optional - pynormaliz + sage: R[0].backend() # optional - pynormaliz 'normaliz' TESTS:: @@ -1987,23 +2003,24 @@ def poset_of_regions(self, B=None, numbered_labels=True): sage: H. = HyperplaneArrangements(QQ) sage: A = H([[0,1,1,1], [0,1,2,3]]) - sage: A.poset_of_regions() # optional - sage.combinat + sage: A.poset_of_regions() # needs sage.combinat Finite poset containing 4 elements - sage: A = hyperplane_arrangements.braid(3) # optional - sage.combinat sage.graphs - sage: A.poset_of_regions() # optional - sage.combinat sage.graphs + sage: # needs sage.combinat sage.graphs + sage: A = hyperplane_arrangements.braid(3) + sage: A.poset_of_regions() Finite poset containing 6 elements - sage: A.poset_of_regions(numbered_labels=False) # optional - sage.combinat sage.graphs + sage: A.poset_of_regions(numbered_labels=False) Finite poset containing 6 elements - sage: A = hyperplane_arrangements.braid(4) # optional - sage.combinat sage.graphs - sage: A.poset_of_regions() # optional - sage.combinat sage.graphs + sage: A = hyperplane_arrangements.braid(4) + sage: A.poset_of_regions() Finite poset containing 24 elements sage: H. = HyperplaneArrangements(QQ) sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) - sage: R = A.regions() # optional - sage.combinat - sage: base_region = R[3] # optional - sage.combinat - sage: A.poset_of_regions(B=base_region) # optional - sage.combinat + sage: R = A.regions() + sage: base_region = R[3] + sage: A.poset_of_regions(B=base_region) # needs sage.combinat Finite poset containing 14 elements """ from sage.combinat.posets.posets import Poset @@ -2108,24 +2125,25 @@ def closed_faces(self, labelled=True): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(2) # optional - sage.graphs - sage: a.hyperplanes() # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(2) + sage: a.hyperplanes() (Hyperplane t0 - t1 + 0,) - sage: a.closed_faces() # optional - sage.graphs + sage: a.closed_faces() (((0,), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line), ((1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line), ((-1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line)) - sage: a.closed_faces(labelled=False) # optional - sage.graphs + sage: a.closed_faces(labelled=False) (A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line) - sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] # optional - sage.graphs + sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] [((0,), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, (0, 0)), ((1,), A 2-dimensional polyhedron in QQ^2 defined @@ -2157,12 +2175,12 @@ def closed_faces(self, labelled=True): ((-1, -1), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, (-1, -2))] - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: a.hyperplanes() # optional - sage.graphs + sage: a = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: a.hyperplanes() # needs sage.graphs (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) - sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] # optional - sage.graphs + sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] # needs sage.graphs [((0, 0, 0), A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line, (0, 0, 0)), ((0, 1, 1), A 2-dimensional polyhedron in QQ^3 defined @@ -2200,10 +2218,10 @@ def closed_faces(self, labelled=True): ....: LHS = Qx.sum(x ** F[1].dim() for F in a.closed_faces()) ....: return LHS == RHS sage: a = hyperplane_arrangements.Catalan(2) - sage: test_number(a) # optional - sage.combinat + sage: test_number(a) # needs sage.combinat True - sage: a = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: test_number(a) # long time # optional - sage.combinat + sage: a = hyperplane_arrangements.Shi(3) + sage: test_number(a) # long time # needs sage.combinat True TESTS: @@ -2338,27 +2356,28 @@ def face_product(self, F, G, normalize=True): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: a.hyperplanes() # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) - sage: faces = {F0: F1 for F0, F1 in a.closed_faces()} # optional - sage.graphs - sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z # optional - sage.graphs - sage: xGyEz.representative_point() # optional - sage.graphs + sage: faces = {F0: F1 for F0, F1 in a.closed_faces()} + sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z + sage: xGyEz.representative_point() (0, -1, -1) - sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z # optional - sage.graphs - sage: xGyEz.representative_point() # optional - sage.graphs + sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z + sage: xGyEz.representative_point() (0, -1, -1) - sage: yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z # optional - sage.graphs - sage: xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z # optional - sage.graphs - sage: a.face_product(xGyEz, yGxGz) == xGyGz # optional - sage.graphs + sage: yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z + sage: xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z + sage: a.face_product(xGyEz, yGxGz) == xGyGz True - sage: a.face_product(yGxGz, xGyEz) == yGxGz # optional - sage.graphs + sage: a.face_product(yGxGz, xGyEz) == yGxGz True - sage: xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y # optional - sage.graphs - sage: xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y # optional - sage.graphs - sage: a.face_product(xEzGy, yGxGz) == xGzGy # optional - sage.graphs + sage: xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y + sage: xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y + sage: a.face_product(xEzGy, yGxGz) == xGzGy True """ f = F.representative_point() @@ -2433,8 +2452,9 @@ def face_semigroup_algebra(self, field=None, names='e'): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: [(i, F[0]) for i, F in enumerate(a.closed_faces())] # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: [(i, F[0]) for i, F in enumerate(a.closed_faces())] [(0, (0, 0, 0)), (1, (0, 1, 1)), (2, (0, -1, -1)), @@ -2448,44 +2468,45 @@ def face_semigroup_algebra(self, field=None, names='e'): (10, (-1, 1, 1)), (11, (-1, 1, -1)), (12, (-1, -1, -1))] - sage: U = a.face_semigroup_algebra(); U # optional - sage.graphs + sage: U = a.face_semigroup_algebra(); U Finite-dimensional algebra of degree 13 over Rational Field - sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() # optional - sage.graphs - sage: e0 * e1 # optional - sage.graphs + sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() + sage: e0 * e1 e1 - sage: e0 * e5 # optional - sage.graphs + sage: e0 * e5 e5 - sage: e5 * e0 # optional - sage.graphs + sage: e5 * e0 e5 - sage: e3 * e2 # optional - sage.graphs + sage: e3 * e2 e6 - sage: e7 * e12 # optional - sage.graphs + sage: e7 * e12 e7 - sage: e3 * e12 # optional - sage.graphs + sage: e3 * e12 e6 - sage: e4 * e8 # optional - sage.graphs + sage: e4 * e8 e4 - sage: e8 * e4 # optional - sage.graphs + sage: e8 * e4 e11 - sage: e8 * e1 # optional - sage.graphs + sage: e8 * e1 e11 - sage: e5 * e12 # optional - sage.graphs + sage: e5 * e12 e7 - sage: (e3 + 2*e4) * (e1 - e7) # optional - sage.graphs + sage: (e3 + 2*e4) * (e1 - e7) e4 - e6 - sage: U3 = a.face_semigroup_algebra(field=GF(3)); U3 # optional - sage.graphs sage.rings.finite_rings + sage: U3 = a.face_semigroup_algebra(field=GF(3)); U3 # needs sage.graphs sage.rings.finite_rings Finite-dimensional algebra of degree 13 over Finite Field of size 3 TESTS: The ``names`` keyword works:: - sage: a = hyperplane_arrangements.braid(3) # optional - sage.graphs - sage: U = a.face_semigroup_algebra(names='x'); U # optional - sage.graphs + sage: # needs sage.graphs + sage: a = hyperplane_arrangements.braid(3) + sage: U = a.face_semigroup_algebra(names='x'); U Finite-dimensional algebra of degree 13 over Rational Field - sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() # optional - sage.graphs - sage: e0 * e1 # optional - sage.graphs + sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() + sage: e0 * e1 x1 """ if field is None: @@ -2545,8 +2566,8 @@ def region_containing_point(self, p): TESTS:: sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3]) - sage: B = A.change_ring(FiniteField(7)) # optional - sage.rings.finite_rings - sage: B.region_containing_point((1,2)) # optional - sage.rings.finite_rings + sage: B = A.change_ring(FiniteField(7)) + sage: B.region_containing_point((1,2)) Traceback (most recent call last): ... ValueError: base field must have characteristic zero @@ -2584,8 +2605,8 @@ def _bounded_region_indices(self): EXAMPLES:: - sage: a = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: a._bounded_region_indices() # optional - sage.combinat + sage: a = hyperplane_arrangements.semiorder(3) + sage: a._bounded_region_indices() (2, 7, 8, 9, 10, 11, 16) """ from sage.geometry.polyhedron.constructor import Polyhedron @@ -2620,8 +2641,9 @@ def bounded_regions(self): EXAMPLES:: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: A.bounded_regions() # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: A.bounded_regions() (A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined @@ -2636,9 +2658,9 @@ def bounded_regions(self): as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line) - sage: A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded # optional - sage.combinat + sage: A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded False - sage: A.is_essential() # optional - sage.combinat + sage: A.is_essential() False """ return tuple(self.regions()[i] for i in self._bounded_region_indices()) @@ -2659,11 +2681,12 @@ def unbounded_regions(self): EXAMPLES:: - sage: A = hyperplane_arrangements.semiorder(3) # optional - sage.combinat - sage: B = A.essentialization() # optional - sage.combinat - sage: B.n_regions() - B.n_bounded_regions() # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.semiorder(3) + sage: B = A.essentialization() + sage: B.n_regions() - B.n_bounded_regions() 12 - sage: B.unbounded_regions() # optional - sage.combinat + sage: B.unbounded_regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined @@ -2711,8 +2734,8 @@ def whitney_data(self): EXAMPLES:: - sage: A = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: A.whitney_data() # optional - sage.combinat + sage: A = hyperplane_arrangements.Shi(3) + sage: A.whitney_data() # needs sage.combinat ( [ 1 -6 9] [ 1 6 6] [ 0 6 -15] [ 0 6 15] @@ -2761,12 +2784,13 @@ def doubly_indexed_whitney_number(self, i, j, kind=1): EXAMPLES:: - sage: A = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: A.doubly_indexed_whitney_number(0, 2) # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.Shi(3) + sage: A.doubly_indexed_whitney_number(0, 2) 9 - sage: A.whitney_number(2) # optional - sage.combinat + sage: A.whitney_number(2) 9 - sage: A.doubly_indexed_whitney_number(1, 2) # optional - sage.combinat + sage: A.doubly_indexed_whitney_number(1, 2) -15 REFERENCES: @@ -2811,20 +2835,21 @@ def whitney_number(self, k, kind=1): EXAMPLES:: - sage: A = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: A.whitney_number(0) # optional - sage.combinat + sage: # needs sage.combinat + sage: A = hyperplane_arrangements.Shi(3) + sage: A.whitney_number(0) 1 - sage: A.whitney_number(1) # optional - sage.combinat + sage: A.whitney_number(1) -6 - sage: A.whitney_number(2) # optional - sage.combinat + sage: A.whitney_number(2) 9 - sage: A.characteristic_polynomial() # optional - sage.combinat + sage: A.characteristic_polynomial() x^3 - 6*x^2 + 9*x - sage: A.whitney_number(1, kind=2) # optional - sage.combinat + sage: A.whitney_number(1, kind=2) 6 - sage: p = A.intersection_poset() # optional - sage.combinat - sage: r = p.rank_function() # optional - sage.combinat - sage: len([i for i in p if r(i) == 1]) # optional - sage.combinat + sage: p = A.intersection_poset() + sage: r = p.rank_function() + sage: len([i for i in p if r(i) == 1]) 6 """ if k >= 0 and k <= self.dimension(): @@ -3005,8 +3030,8 @@ def matroid(self): intersection lattice:: sage: f = sum([list(M.flats(i)) for i in range(M.rank() + 1)], []) - sage: PF = Poset([f, lambda x, y: x < y]) # optional - sage.combinat - sage: PF.is_isomorphic(A.intersection_poset()) # optional - sage.combinat + sage: PF = Poset([f, lambda x, y: x < y]) # needs sage.combinat + sage: PF.is_isomorphic(A.intersection_poset()) # needs sage.combinat True """ if not self.is_central(): @@ -3096,13 +3121,14 @@ def minimal_generated_number(self): Check that :trac:`26705` is fixed:: - sage: w = WeylGroup(['A', 4]).from_reduced_word([3, 4, 2, 1]) # optional - sage.combinat sage.groups - sage: I = w.inversion_arrangement() # optional - sage.combinat sage.groups - sage: I # optional - sage.combinat sage.groups + sage: # needs sage.combinat sage.groups + sage: w = WeylGroup(['A', 4]).from_reduced_word([3, 4, 2, 1]) + sage: I = w.inversion_arrangement() + sage: I Arrangement - sage: I.minimal_generated_number() # optional - sage.combinat sage.groups + sage: I.minimal_generated_number() 0 - sage: I.is_formal() # optional - sage.combinat sage.groups + sage: I.is_formal() True """ V = VectorSpace(self.base_ring(), self.dimension()) @@ -3184,9 +3210,9 @@ def derivation_module_free_chain(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix='s') # optional - sage.combinat sage.groups - sage: A = W.long_element().inversion_arrangement() # optional - sage.combinat sage.groups - sage: for M in A.derivation_module_free_chain(): print("%s\n"%M) # optional - sage.combinat sage.groups + sage: W = WeylGroup(['A',3], prefix='s') # needs sage.combinat sage.groups + sage: A = W.long_element().inversion_arrangement() # needs sage.combinat sage.groups + sage: for M in A.derivation_module_free_chain(): print("%s\n"%M) # needs sage.combinat sage.groups [ 1 0 0] [ 0 1 0] [ 0 0 a3] @@ -3260,8 +3286,8 @@ def is_free(self, algorithm="singular"): For type `A` arrangements, chordality is equivalent to freeness. We verify that in type `A_3`:: - sage: W = WeylGroup(['A', 3], prefix='s') # optional - sage.combinat sage.groups - sage: for x in W: # optional - sage.combinat sage.groups + sage: W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups + sage: for x in W: # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: assert A.matroid().is_chordal() == A.is_free() @@ -3269,8 +3295,8 @@ def is_free(self, algorithm="singular"): We check that the algorithms agree:: - sage: W = WeylGroup(['B', 3], prefix='s') # optional - sage.combinat sage.groups - sage: for x in W: # long time # optional - sage.combinat sage.groups + sage: W = WeylGroup(['B', 3], prefix='s') # needs sage.combinat sage.groups + sage: for x in W: # long time # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: assert (A.is_free(algorithm="BC") ....: == A.is_free(algorithm="singular")) @@ -3329,19 +3355,19 @@ def derivation_module_basis(self, algorithm="singular"): EXAMPLES:: - sage: W = WeylGroup(['A', 2], prefix='s') # optional - sage.combinat sage.groups - sage: A = W.long_element().inversion_arrangement() # optional - sage.combinat sage.groups - sage: A.derivation_module_basis() # optional - sage.combinat sage.groups + sage: W = WeylGroup(['A', 2], prefix='s') # needs sage.combinat sage.groups + sage: A = W.long_element().inversion_arrangement() # needs sage.combinat sage.groups + sage: A.derivation_module_basis() # needs sage.combinat sage.groups [(a1, a2), (0, a1*a2 + a2^2)] TESTS: We check the algorithms produce a basis with the same exponents:: - sage: W = WeylGroup(['A', 2], prefix='s') # optional - sage.combinat sage.groups - sage: def exponents(B): # optional - sage.combinat sage.groups + sage: W = WeylGroup(['A', 2], prefix='s') # needs sage.combinat sage.groups + sage: def exponents(B): ....: return sorted([max(x.degree() for x in b) for b in B]) - sage: for x in W: # long time # optional - sage.combinat sage.groups + sage: for x in W: # long time # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: B = A.derivation_module_basis(algorithm="singular") ....: Bp = A.derivation_module_basis(algorithm="BC") @@ -3633,7 +3659,8 @@ def ngens(self): EXAMPLES:: sage: L. = HyperplaneArrangements(QQ); L - Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z + Hyperplane arrangements in 3-dimensional linear space + over Rational Field with coordinates x, y, z sage: L.ngens() 3 """ diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 8284022d3d8..8d4b301f8d8 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -26,7 +26,7 @@ (3, 2, -5) sage: h.constant_term() -7 - sage: h.change_ring(GF(3)) # optional - sage.rings.finite_rings + sage: h.change_ring(GF(3)) Hyperplane 0*x + 2*y + z + 2 sage: h.point() (21/38, 7/19, -35/38) @@ -238,9 +238,9 @@ def _normal_pivot(self): sage: (x + 3/2*y - 2*z)._normal_pivot() 2 - sage: H. = HyperplaneArrangements(GF(5)) # optional - sage.rings.finite_rings - sage: V = H.ambient_space() # optional - sage.rings.finite_rings - sage: (x + 3*y - 4*z)._normal_pivot() # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(5)) + sage: V = H.ambient_space() + sage: (x + 3*y - 4*z)._normal_pivot() 1 """ try: @@ -397,16 +397,17 @@ def point(self): sage: h.point() in h True - sage: H. = HyperplaneArrangements(GF(3)) # optional - sage.rings.finite_rings - sage: h = 2*x + y + z + 1 # optional - sage.rings.finite_rings - sage: h.point() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(3)) + sage: h = 2*x + y + z + 1 + sage: h.point() (1, 0, 0) - sage: h.point().base_ring() # optional - sage.rings.finite_rings + sage: h.point().base_ring() Finite Field of size 3 - sage: H. = HyperplaneArrangements(GF(3)) # optional - sage.rings.finite_rings - sage: h = x + y + z + 1 # optional - sage.rings.finite_rings - sage: h.point() # optional - sage.rings.finite_rings + sage: H. = HyperplaneArrangements(GF(3)) + sage: h = x + y + z + 1 + sage: h.point() (2, 0, 0) """ P = self.parent() @@ -552,21 +553,23 @@ def primitive(self, signed=True): Check that :trac:`30078` is fixed:: - sage: R. = QuadraticField(2) # optional - sage.rings.number_field - sage: H. = HyperplaneArrangements(base_ring=R) # optional - sage.rings.number_field - sage: B = H([1,1,0], [2,2,0], [sqrt2,sqrt2,0]) # optional - sage.rings.number_field - sage: B # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QuadraticField(2) + sage: H. = HyperplaneArrangements(base_ring=R) + sage: B = H([1,1,0], [2,2,0], [sqrt2,sqrt2,0]) + sage: B Arrangement Check that :trac:`30749` is fixed:: - sage: tau = (1+AA(5).sqrt()) / 2 # optional - sage.rings.number_field - sage: ncn = [[2*tau+1,2*tau,tau],[2*tau+2,2*tau+1,tau+1]] # optional - sage.rings.number_field - sage: ncn += [[tau+1,tau+1,tau],[2*tau,2*tau,tau],[tau+1,tau+1,1]] # optional - sage.rings.number_field - sage: ncn += [[1,1,1],[1,1,0],[0,1,0],[1,0,0],[tau+1,tau,tau]] # optional - sage.rings.number_field - sage: H = HyperplaneArrangements(AA,names='xyz') # optional - sage.rings.number_field - sage: A = H([[0]+v for v in ncn]) # optional - sage.rings.number_field - sage: A.n_regions() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: tau = (1+AA(5).sqrt()) / 2 + sage: ncn = [[2*tau+1,2*tau,tau],[2*tau+2,2*tau+1,tau+1]] + sage: ncn += [[tau+1,tau+1,tau],[2*tau,2*tau,tau],[tau+1,tau+1,1]] + sage: ncn += [[1,1,1],[1,1,0],[0,1,0],[1,0,0],[tau+1,tau,tau]] + sage: H = HyperplaneArrangements(AA,names='xyz') + sage: A = H([[0]+v for v in ncn]) + sage: A.n_regions() 60 """ from sage.rings.rational_field import QQ @@ -638,7 +641,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L. = HyperplaneArrangements(QQ) - sage: (x + y - 2).plot() # optional - sage.plot + sage: (x + y - 2).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot_hyperplane diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 5d0b4aae4d7..83c4f80c325 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -90,7 +90,7 @@ def braid(self, n, K=QQ, names=None): EXAMPLES:: - sage: hyperplane_arrangements.braid(4) # optional - sage.graphs + sage: hyperplane_arrangements.braid(4) # needs sage.graphs Arrangement of 6 hyperplanes of dimension 4 and rank 3 """ x = polygen(QQ, 'x') @@ -124,18 +124,19 @@ def bigraphical(self, G, A=None, K=QQ, names=None): EXAMPLES:: - sage: G = graphs.CycleGraph(4) # optional - sage.graphs - sage: G.edges(sort=True) # optional - sage.graphs + sage: # needs sage.graphs + sage: G = graphs.CycleGraph(4) + sage: G.edges(sort=True) [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] - sage: G.edges(sort=True, labels=False) # optional - sage.graphs + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 3), (1, 2), (2, 3)] - sage: A = {0:{1:1, 3:2}, 1:{0:3, 2:0}, 2:{1:2, 3:1}, 3:{2:0, 0:2}} # optional - sage.graphs - sage: HA = hyperplane_arrangements.bigraphical(G, A) # optional - sage.graphs - sage: HA.n_regions() # optional - sage.graphs + sage: A = {0:{1:1, 3:2}, 1:{0:3, 2:0}, 2:{1:2, 3:1}, 3:{2:0, 0:2}} + sage: HA = hyperplane_arrangements.bigraphical(G, A) + sage: HA.n_regions() 63 - sage: hyperplane_arrangements.bigraphical(G, 'generic').n_regions() # optional - sage.graphs + sage: hyperplane_arrangements.bigraphical(G, 'generic').n_regions() 65 - sage: hyperplane_arrangements.bigraphical(G).n_regions() # optional - sage.graphs + sage: hyperplane_arrangements.bigraphical(G).n_regions() 59 REFERENCES: @@ -253,11 +254,12 @@ def G_semiorder(self, G, K=QQ, names=None): EXAMPLES:: - sage: G = graphs.CompleteGraph(5) # optional - sage.graphs - sage: hyperplane_arrangements.G_semiorder(G) # optional - sage.graphs + sage: # needs sage.graphs + sage: G = graphs.CompleteGraph(5) + sage: hyperplane_arrangements.G_semiorder(G) Arrangement of 20 hyperplanes of dimension 5 and rank 4 - sage: g = graphs.HouseGraph() # optional - sage.graphs - sage: hyperplane_arrangements.G_semiorder(g) # optional - sage.graphs + sage: g = graphs.HouseGraph() + sage: hyperplane_arrangements.G_semiorder(g) Arrangement of 12 hyperplanes of dimension 5 and rank 4 """ n = G.num_verts() @@ -291,13 +293,14 @@ def G_Shi(self, G, K=QQ, names=None): EXAMPLES:: - sage: G = graphs.CompleteGraph(5) # optional - sage.graphs - sage: hyperplane_arrangements.G_Shi(G) # optional - sage.graphs + sage: # needs sage.graphs + sage: G = graphs.CompleteGraph(5) + sage: hyperplane_arrangements.G_Shi(G) Arrangement of 20 hyperplanes of dimension 5 and rank 4 - sage: g = graphs.HouseGraph() # optional - sage.graphs - sage: hyperplane_arrangements.G_Shi(g) # optional - sage.graphs + sage: g = graphs.HouseGraph() + sage: hyperplane_arrangements.G_Shi(g) Arrangement of 12 hyperplanes of dimension 5 and rank 4 - sage: a = hyperplane_arrangements.G_Shi(graphs.WheelGraph(4)); a # optional - sage.graphs + sage: a = hyperplane_arrangements.G_Shi(graphs.WheelGraph(4)); a Arrangement of 12 hyperplanes of dimension 4 and rank 3 """ n = G.num_verts() @@ -333,20 +336,22 @@ def graphical(self, G, K=QQ, names=None): EXAMPLES:: - sage: G = graphs.CompleteGraph(5) # optional - sage.graphs - sage: hyperplane_arrangements.graphical(G) # optional - sage.graphs + sage: # needs sage.graphs + sage: G = graphs.CompleteGraph(5) + sage: hyperplane_arrangements.graphical(G) Arrangement of 10 hyperplanes of dimension 5 and rank 4 - sage: g = graphs.HouseGraph() # optional - sage.graphs - sage: hyperplane_arrangements.graphical(g) # optional - sage.graphs + sage: g = graphs.HouseGraph() + sage: hyperplane_arrangements.graphical(g) Arrangement of 6 hyperplanes of dimension 5 and rank 4 TESTS:: - sage: h = hyperplane_arrangements.graphical(g) # optional - sage.graphs - sage: h.characteristic_polynomial() # optional - sage.graphs + sage: # needs sage.graphs + sage: h = hyperplane_arrangements.graphical(g) + sage: h.characteristic_polynomial() x^5 - 6*x^4 + 14*x^3 - 15*x^2 + 6*x - sage: h.characteristic_polynomial.clear_cache() # long time # optional - sage.graphs - sage: h.characteristic_polynomial() # long time # optional - sage.graphs + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^5 - 6*x^4 + 14*x^3 - 15*x^2 + 6*x """ n = G.num_verts() @@ -388,18 +393,19 @@ def Ish(self, n, K=QQ, names=None): EXAMPLES:: - sage: a = hyperplane_arrangements.Ish(3); a # optional - sage.combinat + sage: # needs sage.combinat + sage: a = hyperplane_arrangements.Ish(3); a Arrangement of 6 hyperplanes of dimension 3 and rank 2 - sage: a.characteristic_polynomial() # optional - sage.combinat + sage: a.characteristic_polynomial() x^3 - 6*x^2 + 9*x - sage: b = hyperplane_arrangements.Shi(3) # optional - sage.combinat - sage: b.characteristic_polynomial() # optional - sage.combinat + sage: b = hyperplane_arrangements.Shi(3) + sage: b.characteristic_polynomial() x^3 - 6*x^2 + 9*x TESTS:: - sage: a.characteristic_polynomial.clear_cache() # long time # optional - sage.combinat - sage: a.characteristic_polynomial() # long time # optional - sage.combinat + sage: a.characteristic_polynomial.clear_cache() # long time # needs sage.combinat + sage: a.characteristic_polynomial() # long time # needs sage.combinat x^3 - 6*x^2 + 9*x REFERENCES: @@ -565,16 +571,17 @@ def semiorder(self, n, K=QQ, names=None): EXAMPLES:: - sage: hyperplane_arrangements.semiorder(4) # optional - sage.combinat + sage: hyperplane_arrangements.semiorder(4) Arrangement of 12 hyperplanes of dimension 4 and rank 3 TESTS:: - sage: h = hyperplane_arrangements.semiorder(5) # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: # needs sage.combinat + sage: h = hyperplane_arrangements.semiorder(5) + sage: h.characteristic_polynomial() x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x - sage: h.characteristic_polynomial.clear_cache() # long time # optional - sage.combinat - sage: h.characteristic_polynomial() # long time # optional - sage.combinat + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x """ H = make_parent(K, n, names) @@ -626,29 +633,30 @@ def Shi(self, data, K=QQ, names=None, m=1): EXAMPLES:: - sage: hyperplane_arrangements.Shi(4) # optional - sage.combinat + sage: # needs sage.combinat + sage: hyperplane_arrangements.Shi(4) Arrangement of 12 hyperplanes of dimension 4 and rank 3 - sage: hyperplane_arrangements.Shi("A3") # optional - sage.combinat + sage: hyperplane_arrangements.Shi("A3") Arrangement of 12 hyperplanes of dimension 4 and rank 3 - sage: hyperplane_arrangements.Shi("A3", m=2) # optional - sage.combinat + sage: hyperplane_arrangements.Shi("A3", m=2) Arrangement of 24 hyperplanes of dimension 4 and rank 3 - sage: hyperplane_arrangements.Shi("B4") # optional - sage.combinat + sage: hyperplane_arrangements.Shi("B4") Arrangement of 32 hyperplanes of dimension 4 and rank 4 - sage: hyperplane_arrangements.Shi("B4", m=3) # optional - sage.combinat + sage: hyperplane_arrangements.Shi("B4", m=3) Arrangement of 96 hyperplanes of dimension 4 and rank 4 - sage: hyperplane_arrangements.Shi("C3") # optional - sage.combinat + sage: hyperplane_arrangements.Shi("C3") Arrangement of 18 hyperplanes of dimension 3 and rank 3 - sage: hyperplane_arrangements.Shi("D4", m=3) # optional - sage.combinat + sage: hyperplane_arrangements.Shi("D4", m=3) Arrangement of 72 hyperplanes of dimension 4 and rank 4 - sage: hyperplane_arrangements.Shi("E6") # optional - sage.combinat + sage: hyperplane_arrangements.Shi("E6") Arrangement of 72 hyperplanes of dimension 8 and rank 6 - sage: hyperplane_arrangements.Shi("E6", m=2) # optional - sage.combinat + sage: hyperplane_arrangements.Shi("E6", m=2) Arrangement of 144 hyperplanes of dimension 8 and rank 6 If the Cartan type is not crystallographic, the Shi arrangement is not defined:: - sage: hyperplane_arrangements.Shi("H4") # optional - sage.combinat + sage: hyperplane_arrangements.Shi("H4") Traceback (most recent call last): ... NotImplementedError: Shi arrangements are not defined for non crystallographic Cartan types @@ -656,36 +664,38 @@ def Shi(self, data, K=QQ, names=None, m=1): The characteristic polynomial is pre-computed using the results of [Ath1996]_:: - sage: hyperplane_arrangements.Shi("A3").characteristic_polynomial() # optional - sage.combinat + sage: # needs sage.combinat + sage: hyperplane_arrangements.Shi("A3").characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x - sage: hyperplane_arrangements.Shi("A3", m=2).characteristic_polynomial() # optional - sage.combinat + sage: hyperplane_arrangements.Shi("A3", m=2).characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x - sage: hyperplane_arrangements.Shi("C3").characteristic_polynomial() # optional - sage.combinat + sage: hyperplane_arrangements.Shi("C3").characteristic_polynomial() x^3 - 18*x^2 + 108*x - 216 - sage: hyperplane_arrangements.Shi("E6").characteristic_polynomial() # optional - sage.combinat + sage: hyperplane_arrangements.Shi("E6").characteristic_polynomial() x^8 - 72*x^7 + 2160*x^6 - 34560*x^5 + 311040*x^4 - 1492992*x^3 + 2985984*x^2 - sage: hyperplane_arrangements.Shi("B4", m=3).characteristic_polynomial() # optional - sage.combinat + sage: hyperplane_arrangements.Shi("B4", m=3).characteristic_polynomial() x^4 - 96*x^3 + 3456*x^2 - 55296*x + 331776 TESTS:: - sage: h = hyperplane_arrangements.Shi(4) # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: # needs sage.combinat + sage: h = hyperplane_arrangements.Shi(4) + sage: h.characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x - sage: h.characteristic_polynomial.clear_cache() # long time # optional - sage.combinat - sage: h.characteristic_polynomial() # long time # optional - sage.combinat + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^4 - 12*x^3 + 48*x^2 - 64*x - sage: h = hyperplane_arrangements.Shi("A3", m=2) # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: h = hyperplane_arrangements.Shi("A3", m=2) + sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x - sage: h.characteristic_polynomial.clear_cache() # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: h.characteristic_polynomial.clear_cache() + sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x - sage: h = hyperplane_arrangements.Shi("B3", m=3) # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: h = hyperplane_arrangements.Shi("B3", m=3) + sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 - sage: h.characteristic_polynomial.clear_cache() # optional - sage.combinat - sage: h.characteristic_polynomial() # optional - sage.combinat + sage: h.characteristic_polynomial.clear_cache() + sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 """ if data in NN: diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index d2c62f2d547..be468c111bc 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -56,26 +56,26 @@ sage: H3. = HyperplaneArrangements(QQ) sage: A = H3([(1,0,0), 0], [(0,0,1), 5]) - sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, # optional - sage.plot + sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, # needs sage.plot ....: hyperplane_legend=False) Graphics3d Object sage: c = H3([(1,0,0),0], [(0,0,1),5]) - sage: c.plot(ranges=10) # optional - sage.plot + sage: c.plot(ranges=10) # needs sage.plot Graphics3d Object - sage: c.plot(ranges=[[9.5,10], [-3,3]]) # optional - sage.plot + sage: c.plot(ranges=[[9.5,10], [-3,3]]) # needs sage.plot Graphics3d Object - sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) # optional - sage.plot + sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) # needs sage.plot Graphics3d Object sage: H2. = HyperplaneArrangements(QQ) sage: h = H2([(1,1),0], [(1,-1),0], [(0,1),2]) - sage: h.plot(ranges=20) # optional - sage.plot + sage: h.plot(ranges=20) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[-1, 10]) # optional - sage.plot + sage: h.plot(ranges=[-1, 10]) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) # optional - sage.plot + sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) # needs sage.plot Graphics object consisting of 3 graphics primitives sage: a = hyperplane_arrangements.coordinate(3) @@ -84,24 +84,24 @@ sage: opts['label_offsets'] = [(0,2,2), (2,0,2), (2,2,0)] sage: opts['hyperplane_legend'] = False sage: opts['hyperplane_opacities'] = 0.7 - sage: a.plot(**opts) # optional - sage.plot + sage: a.plot(**opts) # needs sage.plot Graphics3d Object sage: opts['hyperplane_labels'] = 'short' - sage: a.plot(**opts) # optional - sage.plot + sage: a.plot(**opts) # needs sage.plot Graphics3d Object sage: H. = HyperplaneArrangements(QQ) sage: pts = H(3*u+4, 2*u+5, 7*u+1) - sage: pts.plot(hyperplane_colors=['yellow','black','blue']) # optional - sage.plot + sage: pts.plot(hyperplane_colors=['yellow','black','blue']) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') # optional - sage.plot + sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') # needs sage.plot Graphics object consisting of 3 graphics primitives sage: H. = HyperplaneArrangements(QQ) sage: a = H(x, y+1, y+2) - sage: a.plot(hyperplane_labels=True, label_colors='blue', label_fontsize=18) # optional - sage.plot + sage: a.plot(hyperplane_labels=True, label_colors='blue', label_fontsize=18) # needs sage.plot Graphics3d Object - sage: a.plot(hyperplane_labels=True, label_colors=['red','green','black']) # optional - sage.plot + sage: a.plot(hyperplane_labels=True, label_colors=['red','green','black']) # needs sage.plot Graphics3d Object """ from copy import copy @@ -145,8 +145,8 @@ def plot(hyperplane_arrangement, **kwds): EXAMPLES:: - sage: B = hyperplane_arrangements.semiorder(4) # optional - sage.combinat - sage: B.plot() # optional - sage.combinat sage.plot + sage: B = hyperplane_arrangements.semiorder(4) + sage: B.plot() # needs sage.combinat sage.plot Displaying the essentialization. Graphics3d Object """ @@ -331,34 +331,35 @@ def plot_hyperplane(hyperplane, **kwds): sage: H1. = HyperplaneArrangements(QQ) sage: a = 3*x + 4 - sage: a.plot() # indirect doctest # optional - sage.plot + sage: a.plot() # indirect doctest # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: a.plot(point_size=100, hyperplane_label='hello') # optional - sage.plot + sage: a.plot(point_size=100, hyperplane_label='hello') # needs sage.plot Graphics object consisting of 3 graphics primitives sage: H2. = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 - sage: b.plot() # optional - sage.plot + sage: b.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: b.plot(ranges=(1,5), label_offset=(2,-1)) # optional - sage.plot + sage: b.plot(ranges=(1,5), label_offset=(2,-1)) # needs sage.plot Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label': True, 'label_color': 'green', ....: 'label_fontsize': 24, 'label_offset': (0,1.5)} - sage: b.plot(**opts) # optional - sage.plot + sage: b.plot(**opts) # needs sage.plot Graphics object consisting of 2 graphics primitives + sage: # needs sage.plot sage: H3. = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 - sage: c.plot() # optional - sage.plot + sage: c.plot() Graphics3d Object - sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', # optional - sage.plot + sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', ....: frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 - sage: d.plot(opacity=0.8) # optional - sage.plot + sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 - sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) # optional - sage.plot + sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic(): @@ -486,22 +487,22 @@ def legend_3d(hyperplane_arrangement, hyperplane_colors, length): EXAMPLES:: - sage: a = hyperplane_arrangements.semiorder(3) # optional - sage.combinat + sage: a = hyperplane_arrangements.semiorder(3) sage: from sage.geometry.hyperplane_arrangement.plot import legend_3d - sage: legend_3d(a, list(colors.values())[:6], length='long') # optional - sage.combinat sage.plot + sage: legend_3d(a, list(colors.values())[:6], length='long') # needs sage.combinat sage.plot Graphics object consisting of 6 graphics primitives - sage: b = hyperplane_arrangements.semiorder(4) # optional - sage.combinat - sage: c = b.essentialization() # optional - sage.combinat - sage: legend_3d(c, list(colors.values())[:12], length='long') # optional - sage.combinat sage.plot + sage: b = hyperplane_arrangements.semiorder(4) + sage: c = b.essentialization() + sage: legend_3d(c, list(colors.values())[:12], length='long') # needs sage.combinat sage.plot Graphics object consisting of 12 graphics primitives - sage: legend_3d(c, list(colors.values())[:12], length='short') # optional - sage.combinat sage.plot + sage: legend_3d(c, list(colors.values())[:12], length='short') # needs sage.combinat sage.plot Graphics object consisting of 12 graphics primitives - sage: p = legend_3d(c, list(colors.values())[:12], length='short') # optional - sage.combinat sage.plot - sage: p.set_legend_options(ncol=4) # optional - sage.combinat sage.plot - sage: type(p) # optional - sage.combinat sage.plot + sage: p = legend_3d(c, list(colors.values())[:12], length='short') # needs sage.combinat sage.plot + sage: p.set_legend_options(ncol=4) # needs sage.combinat sage.plot + sage: type(p) # needs sage.combinat sage.plot """ if hyperplane_arrangement.dimension() != 3: diff --git a/src/sage/geometry/integral_points.pxi b/src/sage/geometry/integral_points.pxi index dae34bc99af..c45f7f1cb2e 100644 --- a/src/sage/geometry/integral_points.pxi +++ b/src/sage/geometry/integral_points.pxi @@ -474,8 +474,8 @@ cpdef rectangular_box_points(list box_min, list box_max, Long ints and non-integral polyhedra are explicitly allowed:: - sage: polytope = Polyhedron([[1], [10*pi.n()]], base_ring=RDF) # optional - sage.symbolic - sage: len(rectangular_box_points([-100], [100], polytope)) # optional - sage.symbolic + sage: polytope = Polyhedron([[1], [10*pi.n()]], base_ring=RDF) # needs sage.symbolic + sage: len(rectangular_box_points([-100], [100], polytope)) # needs sage.symbolic 31 sage: halfplane = Polyhedron(ieqs=[(-1,1,0)]) @@ -488,15 +488,16 @@ cpdef rectangular_box_points(list box_min, list box_max, Using a PPL polyhedron:: - sage: from ppl import Variable, Generator_System, C_Polyhedron, point # optional - pplpy - sage: gs = Generator_System() # optional - pplpy - sage: x = Variable(0); y = Variable(1); z = Variable(2) # optional - pplpy - sage: gs.insert(point(0*x + 1*y + 0*z)) # optional - pplpy - sage: gs.insert(point(0*x + 1*y + 3*z)) # optional - pplpy - sage: gs.insert(point(3*x + 1*y + 0*z)) # optional - pplpy - sage: gs.insert(point(3*x + 1*y + 3*z)) # optional - pplpy - sage: poly = C_Polyhedron(gs) # optional - pplpy - sage: rectangular_box_points([0]*3, [3]*3, poly) # optional - pplpy + sage: # needs pplpy + sage: from ppl import Variable, Generator_System, C_Polyhedron, point + sage: gs = Generator_System() + sage: x = Variable(0); y = Variable(1); z = Variable(2) + sage: gs.insert(point(0*x + 1*y + 0*z)) + sage: gs.insert(point(0*x + 1*y + 3*z)) + sage: gs.insert(point(3*x + 1*y + 0*z)) + sage: gs.insert(point(3*x + 1*y + 3*z)) + sage: poly = C_Polyhedron(gs) + sage: rectangular_box_points([0]*3, [3]*3, poly) ((0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 1, 3)) @@ -739,7 +740,7 @@ cdef class Inequality_generic: EXAMPLES:: sage: from sage.geometry.integral_points import Inequality_generic - sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # optional - sage.symbolic + sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # needs sage.symbolic generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 """ @@ -761,7 +762,7 @@ cdef class Inequality_generic: EXAMPLES:: sage: from sage.geometry.integral_points import Inequality_generic - sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # optional - sage.symbolic + sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # needs sage.symbolic generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 """ self.A = A @@ -1131,16 +1132,17 @@ cdef class InequalityCollection: EXAMPLES:: - sage: from ppl import Variable, Generator_System, C_Polyhedron, point # optional - pplpy - sage: gs = Generator_System() # optional - pplpy - sage: x = Variable(0); y = Variable(1); z = Variable(2) # optional - pplpy - sage: gs.insert(point(0*x + 0*y + 1*z)) # optional - pplpy - sage: gs.insert(point(0*x + 3*y + 1*z)) # optional - pplpy - sage: gs.insert(point(3*x + 0*y + 1*z)) # optional - pplpy - sage: gs.insert(point(3*x + 3*y + 1*z)) # optional - pplpy - sage: poly = C_Polyhedron(gs) # optional - pplpy - sage: from sage.geometry.integral_points import InequalityCollection # optional - pplpy - sage: InequalityCollection(poly, [0,2,1], [0]*3, [3]*3 ) # optional - pplpy + sage: # needs pplpy + sage: from ppl import Variable, Generator_System, C_Polyhedron, point + sage: gs = Generator_System() + sage: x = Variable(0); y = Variable(1); z = Variable(2) + sage: gs.insert(point(0*x + 0*y + 1*z)) + sage: gs.insert(point(0*x + 3*y + 1*z)) + sage: gs.insert(point(3*x + 0*y + 1*z)) + sage: gs.insert(point(3*x + 3*y + 1*z)) + sage: poly = C_Polyhedron(gs) + sage: from sage.geometry.integral_points import InequalityCollection + sage: InequalityCollection(poly, [0,2,1], [0]*3, [3]*3 ) The collection of inequalities integer: (0, 1, 0) x + -1 >= 0 integer: (0, -1, 0) x + 1 >= 0 @@ -1191,8 +1193,8 @@ cdef class InequalityCollection: Check that :trac:`21037` is fixed:: sage: P = Polyhedron(vertices=((0, 0), (17,3))) - sage: P += 1/1000*polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: P.integral_points() # optional - sage.rings.number_field + sage: P += 1/1000*polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: P.integral_points() # needs sage.rings.number_field ((0, 0), (17, 3)) """ cdef list A diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index eab90bd12d2..701b8e43ee8 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -239,7 +239,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): We draw a pretty picture of the polytope in 3-dimensional space:: - sage: p.plot3d().show() # optional - palp sage.plot + sage: p.plot3d().show() # needs palp sage.plot Now we add an extra point, which is in the interior of the polytope... @@ -295,7 +295,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): sage: p.points() Empty collection in 3-d lattice M - sage: p.faces() # optional - sage.graphs + sage: p.faces() # needs sage.graphs ((-1-d lattice polytope in 3-d lattice M,),) """ if isinstance(data, LatticePolytopeClass): @@ -464,7 +464,7 @@ def is_LatticePolytope(x): sage: is_LatticePolytope(1) False sage: p = LatticePolytope([(1,0), (0,1), (-1,-1)]) - sage: p # optional - palp + sage: p # needs palp 2-d reflexive polytope #0 in 2-d lattice M sage: is_LatticePolytope(p) True @@ -763,17 +763,18 @@ def _compute_facets(self): Check that :trac:`28741` is fixed:: + sage: # needs sage.graphs sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p -1-d lattice polytope in 3-d lattice M - sage: a = p.faces()[0][0] # optional - sage.graphs + sage: a = p.faces()[0][0] sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p -1-d lattice polytope in 3-d lattice M - sage: a = p.faces()[0][0]; a # optional - sage.graphs + sage: a = p.faces()[0][0]; a -1-d lattice polytope in 3-d lattice M - sage: a.facet_normals() # optional - sage.graphs + sage: a.facet_normals() Empty collection in 3-d lattice N - sage: a # optional - sage.graphs + sage: a -1-d lattice polytope in 3-d lattice M """ assert not hasattr(self, "_facet_normals") @@ -966,9 +967,9 @@ def _palp(self, command, reduce_dimension=False): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: o._palp("poly.x -f") # optional - palp + sage: o._palp("poly.x -f") # needs palp 'M:7 6 N:27 8 Pic:17 Cor:0\n' - sage: print(o._palp("nef.x -f -N -p")) # random time information # optional - palp + sage: print(o._palp("nef.x -f -N -p")) # random time information # needs palp M:27 8 N:7 6 codim=2 #part=5 H:[0] P:0 V:2 4 5 0sec 0cpu H:[0] P:2 V:3 4 5 0sec 0cpu @@ -976,18 +977,18 @@ def _palp(self, command, reduce_dimension=False): np=3 d:1 p:1 0sec 0cpu sage: p = LatticePolytope([[1]]) - sage: p._palp("poly.x -f") # optional - palp + sage: p._palp("poly.x -f") # needs palp Traceback (most recent call last): ... ValueError: Cannot run "poly.x -f" for the zero-dimensional polytope! Polytope: 0-d lattice polytope in 1-d lattice M sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p._palp("poly.x -f") # optional - palp + sage: p._palp("poly.x -f") # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! - sage: p._palp("poly.x -f", reduce_dimension=True) # optional - palp + sage: p._palp("poly.x -f", reduce_dimension=True) # needs palp 'M:5 4 F:4\n' """ if self.dim() <= 0: @@ -1098,22 +1099,23 @@ def _read_equations(self, data): For a reflexive polytope construct the polar polytope:: + sage: # needs palp sage: p = LatticePolytope([(1,0), (0,1), (-1,-1)]) sage: p.vertices() M( 1, 0), M( 0, 1), M(-1, -1) in 2-d lattice M - sage: s = p.poly_x("e") # optional - palp - sage: print(s) # optional - palp + sage: s = p.poly_x("e") + sage: print(s) 3 2 Vertices of P-dual <-> Equations of P 2 -1 -1 2 -1 -1 - sage: "_polar" in p.__dict__ # optional - palp + sage: "_polar" in p.__dict__ False - sage: p._read_equations(s) # optional - palp - sage: p._polar._vertices # optional - palp + sage: p._read_equations(s) + sage: p._polar._vertices N( 2, -1), N(-1, 2), N(-1, -1) @@ -1121,6 +1123,7 @@ def _read_equations(self, data): For a non-reflexive polytope cache facet equations:: + sage: # needs palp sage: p = LatticePolytope([(1,0), (0,2), (-1,-3 )]) sage: p.vertices() M( 1, 0), @@ -1131,19 +1134,19 @@ def _read_equations(self, data): False sage: "_facet_constants" in p.__dict__ False - sage: s = p.poly_x("e") # optional - palp - sage: print(s) # optional - palp + sage: s = p.poly_x("e") + sage: print(s) 3 2 Equations of P 5 -1 2 -2 -1 2 -3 2 3 - sage: p._read_equations(s) # optional - palp - sage: p._facet_normals # optional - palp + sage: p._read_equations(s) + sage: p._facet_normals N( 5, -1), N(-2, -1), N(-3, 2) in 2-d lattice N - sage: p._facet_constants # optional - palp + sage: p._facet_constants (2, 2, 3) """ if isinstance(data, str): @@ -1210,8 +1213,8 @@ def _read_nef_partitions(self, data): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-p -N -Lv") # optional - palp - sage: print(s) # random time values # optional - palp + sage: s = o.nef_x("-p -N -Lv") # needs palp + sage: print(s) # random time values # needs palp M:27 8 N:7 6 codim=2 #part=5 3 6 Vertices in N-lattice: 1 0 0 -1 0 0 @@ -1232,8 +1235,8 @@ def _read_nef_partitions(self, data): sage: o_copy = LatticePolytope(o.vertices()) sage: "_nef_partitions" in o_copy.__dict__ False - sage: o_copy._read_nef_partitions(s) # optional - palp - sage: o_copy._nef_partitions # optional - palp + sage: o_copy._read_nef_partitions(s) # needs palp + sage: o_copy._nef_partitions # needs palp [ Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, @@ -1335,7 +1338,7 @@ def _sort_faces(self, faces): sage: o = lattice_polytope.cross_polytope(3) sage: # indirect doctest - sage: for i, face in enumerate(o.faces(0)): # optional - sage.graphs + sage: for i, face in enumerate(o.faces(0)): # needs sage.graphs ....: if face.vertex(0) != o.vertex(i): ....: print("Wrong order!") """ @@ -1380,10 +1383,10 @@ def adjacent(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.adjacent() # optional - sage.graphs + sage: o.adjacent() # needs sage.graphs () - sage: face = o.faces(1)[0] # optional - sage.graphs - sage: face.adjacent() # optional - sage.graphs + sage: face = o.faces(1)[0] # needs sage.graphs + sage: face.adjacent() # needs sage.graphs (1-d face of 3-d reflexive polytope in 3-d lattice M, 1-d face of 3-d reflexive polytope in 3-d lattice M, 1-d face of 3-d reflexive polytope in 3-d lattice M, @@ -1505,12 +1508,14 @@ def ambient(self): 3-d reflexive polytope in 3-d lattice M sage: o.ambient() is o True - sage: face = o.faces(1)[0] # optional - sage.graphs - sage: face # optional - sage.graphs + + sage: # needs sage.graphs + sage: face = o.faces(1)[0] + sage: face 1-d face of 3-d reflexive polytope in 3-d lattice M - sage: face.ambient() # optional - sage.graphs + sage: face.ambient() 3-d reflexive polytope in 3-d lattice M - sage: face.ambient() is o # optional - sage.graphs + sage: face.ambient() is o True """ return self._ambient @@ -1533,14 +1538,15 @@ def ambient_facet_indices(self): But each of its other faces is contained in one or more facets:: - sage: face = o.faces(1)[0] # optional - sage.graphs - sage: face.ambient_facet_indices() # optional - sage.graphs + sage: # needs sage.graphs + sage: face = o.faces(1)[0] + sage: face.ambient_facet_indices() (4, 5) - sage: face.vertices() # optional - sage.graphs + sage: face.vertices() M(1, 0, 0), M(0, 1, 0) in 3-d lattice M - sage: o.facets()[face.ambient_facet_indices()[0]].vertices() # optional - sage.graphs + sage: o.facets()[face.ambient_facet_indices()[0]].vertices() M(1, 0, 0), M(0, 1, 0), M(0, 0, -1) @@ -1561,10 +1567,10 @@ def ambient_point_indices(self): EXAMPLES:: sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: face = cube.facets()[0] # optional - sage.graphs - sage: face.ambient_point_indices() # optional - palp sage.graphs + sage: face = cube.facets()[0] # needs sage.graphs + sage: face.ambient_point_indices() # needs palp sage.graphs (4, 5, 6, 7, 8, 9, 10, 11, 12) - sage: cube.points(face.ambient_point_indices()) == face.points() # optional - palp sage.graphs + sage: cube.points(face.ambient_point_indices()) == face.points() # needs palp sage.graphs True """ if self._ambient is self: @@ -1587,10 +1593,10 @@ def ambient_ordered_point_indices(self): EXAMPLES:: sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: face = cube.facets()[0] # optional - sage.graphs - sage: face.ambient_ordered_point_indices() # optional - palp sage.graphs + sage: face = cube.facets()[0] # needs sage.graphs + sage: face.ambient_ordered_point_indices() # needs palp sage.graphs (5, 8, 4, 9, 10, 11, 6, 12, 7) - sage: cube.points(face.ambient_ordered_point_indices()) # optional - palp sage.graphs + sage: cube.points(face.ambient_ordered_point_indices()) # needs palp sage.graphs N(-1, -1, -1), N(-1, -1, 0), N(-1, -1, 1), @@ -1621,8 +1627,8 @@ def ambient_vertex_indices(self): sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient_vertex_indices() (0, 1, 2, 3, 4, 5) - sage: face = o.faces(1)[0] # optional - sage.graphs - sage: face.ambient_vertex_indices() # optional - sage.graphs + sage: face = o.faces(1)[0] # needs sage.graphs + sage: face.ambient_vertex_indices() # needs sage.graphs (0, 1) """ return self._ambient_vertex_indices @@ -1641,7 +1647,7 @@ def boundary_point_indices(self): All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.points() # optional - palp + sage: square.points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -1652,18 +1658,18 @@ def boundary_point_indices(self): N( 0, 1), N( 1, 0) in 2-d lattice N - sage: square.boundary_point_indices() # optional - palp + sage: square.boundary_point_indices() # needs palp (0, 1, 2, 3, 4, 5, 7, 8) For an edge the boundary is formed by the end points:: - sage: face = square.edges()[0] # optional - sage.graphs - sage: face.points() # optional - sage.graphs + sage: face = square.edges()[0] # needs sage.graphs + sage: face.points() # needs sage.graphs N(-1, -1), N(-1, 1), N(-1, 0) in 2-d lattice N - sage: face.boundary_point_indices() # optional - sage.graphs + sage: face.boundary_point_indices() # needs sage.graphs (0, 1) """ return tuple(i @@ -1683,7 +1689,7 @@ def boundary_points(self): All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.boundary_points() # optional - palp + sage: square.boundary_points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -1696,8 +1702,8 @@ def boundary_points(self): For an edge the boundary is formed by the end points:: - sage: face = square.edges()[0] # optional - sage.graphs - sage: face.boundary_points() # optional - sage.graphs + sage: face = square.edges()[0] # needs sage.graphs + sage: face.boundary_points() # needs sage.graphs N(-1, -1), N(-1, 1) in 2-d lattice N @@ -1775,7 +1781,7 @@ def distances(self, point=None): EXAMPLES: The matrix of distances for a 3-dimensional octahedron:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.distances() # optional - palp + sage: o.distances() # needs palp [2 0 0 0 2 2 1] [2 2 0 0 0 2 1] [2 2 2 0 0 0 1] @@ -1794,7 +1800,7 @@ def distances(self, point=None): sage: o.distances([1,2,3/2]) (-3/2, 5/2, 11/2, 3/2, -1/2, -7/2, 1/2, 7/2) - sage: o.distances([1,2,sqrt(2)]) # optional - sage.symbolic + sage: o.distances([1,2,sqrt(2)]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert sqrt(2) to an element of Rational Field @@ -1802,17 +1808,17 @@ def distances(self, point=None): Now we create a non-spanning polytope:: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.distances() # optional - palp + sage: p.distances() # needs palp [2 2 0 0 1] [2 0 0 2 1] [0 0 2 2 1] [0 2 2 0 1] - sage: p.distances((1/2, 3, 0)) # optional - palp + sage: p.distances((1/2, 3, 0)) # needs palp (9/2, -3/2, -5/2, 7/2) This point is not even in the affine subspace of the polytope:: - sage: p.distances((1, 1, 1)) # optional - palp + sage: p.distances((1, 1, 1)) # needs palp (3, 1, -1, 1) """ if point is not None: @@ -1841,16 +1847,17 @@ def dual(self): EXAMPLES:: + sage: # needs sage.graphs sage: o = lattice_polytope.cross_polytope(4) - sage: e = o.edges()[0]; e # optional - sage.graphs + sage: e = o.edges()[0]; e 1-d face of 4-d reflexive polytope in 4-d lattice M - sage: ed = e.dual(); ed # optional - sage.graphs + sage: ed = e.dual(); ed 2-d face of 4-d reflexive polytope in 4-d lattice N - sage: ed.ambient() is e.ambient().polar() # optional - sage.graphs + sage: ed.ambient() is e.ambient().polar() True - sage: e.ambient_vertex_indices() == ed.ambient_facet_indices() # optional - sage.graphs + sage: e.ambient_vertex_indices() == ed.ambient_facet_indices() True - sage: e.ambient_facet_indices() == ed.ambient_vertex_indices() # optional - sage.graphs + sage: e.ambient_facet_indices() == ed.ambient_vertex_indices() True """ for f in self._ambient.polar().faces(codim=self.dim() + 1): @@ -1893,11 +1900,11 @@ def edges(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.edges() # optional - sage.graphs + sage: o.edges() # needs sage.graphs (1-d face of 3-d reflexive polytope in 3-d lattice M, ... 1-d face of 3-d reflexive polytope in 3-d lattice M) - sage: len(o.edges()) # optional - sage.graphs + sage: len(o.edges()) # needs sage.graphs 12 """ return self.faces(dim=1) @@ -1920,12 +1927,12 @@ def face_lattice(self): Let's take a look at the face lattice of a square:: sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) - sage: L = square.face_lattice(); L # optional - sage.graphs + sage: L = square.face_lattice(); L # needs sage.graphs Finite lattice containing 10 elements with distinguished linear extension To see all faces arranged by dimension, you can do this:: - sage: for level in L.level_sets(): print(level) # optional - sage.graphs + sage: for level in L.level_sets(): print(level) # needs sage.graphs [-1-d face of 2-d lattice polytope in 2-d lattice M] [0-d face of 2-d lattice polytope in 2-d lattice M, 0-d face of 2-d lattice polytope in 2-d lattice M, @@ -1939,31 +1946,31 @@ def face_lattice(self): For a particular face you can look at its actual vertices... :: - sage: face = L.level_sets()[1][0] # optional - sage.graphs - sage: face.vertices() # optional - sage.graphs + sage: face = L.level_sets()[1][0] # needs sage.graphs + sage: face.vertices() # needs sage.graphs M(0, 0) in 2-d lattice M ... or you can see the index of the vertex of the original polytope that corresponds to the above one:: - sage: face.ambient_vertex_indices() # optional - sage.graphs + sage: face.ambient_vertex_indices() # needs sage.graphs (0,) - sage: square.vertex(0) # optional - sage.graphs + sage: square.vertex(0) M(0, 0) An alternative to extracting faces from the face lattice is to use :meth:`faces` method:: - sage: face is square.faces(dim=0)[0] # optional - sage.graphs + sage: face is square.faces(dim=0)[0] # needs sage.graphs True The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:: - sage: face = L.level_sets()[1][0] # optional - sage.graphs - sage: D = L.hasse_diagram() # optional - sage.graphs - sage: sorted(D.neighbors(face)) # optional - sage.graphs + sage: face = L.level_sets()[1][0] # needs sage.graphs + sage: D = L.hasse_diagram() # needs sage.graphs + sage: sorted(D.neighbors(face)) # needs sage.graphs [-1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M] @@ -1971,43 +1978,45 @@ def face_lattice(self): However, you can achieve some of this functionality using :meth:`facets`, :meth:`facet_of`, and :meth:`adjacent` methods:: - sage: face = square.faces(0)[0] # optional - sage.graphs - sage: face # optional - sage.graphs + sage: # needs sage.graphs + sage: face = square.faces(0)[0] + sage: face 0-d face of 2-d lattice polytope in 2-d lattice M - sage: face.vertices() # optional - sage.graphs + sage: face.vertices() M(0, 0) in 2-d lattice M - sage: face.facets() # optional - sage.graphs + sage: face.facets() (-1-d face of 2-d lattice polytope in 2-d lattice M,) - sage: face.facet_of() # optional - sage.graphs + sage: face.facet_of() (1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M) - sage: face.adjacent() # optional - sage.graphs + sage: face.adjacent() (0-d face of 2-d lattice polytope in 2-d lattice M, 0-d face of 2-d lattice polytope in 2-d lattice M) - sage: face.adjacent()[0].vertices() # optional - sage.graphs + sage: face.adjacent()[0].vertices() M(1, 0) in 2-d lattice M Note that if ``p`` is a face of ``superp``, then the face lattice of ``p`` consists of (appropriate) faces of ``superp``:: + sage: # needs sage.graphs sage: superp = LatticePolytope([(1,2,3,4), (5,6,7,8), ....: (1,2,4,8), (1,3,9,7)]) - sage: superp.face_lattice() # optional - sage.graphs + sage: superp.face_lattice() Finite lattice containing 16 elements with distinguished linear extension - sage: superp.face_lattice().top() # optional - sage.graphs + sage: superp.face_lattice().top() 3-d lattice polytope in 4-d lattice M - sage: p = superp.facets()[0] # optional - sage.graphs - sage: p # optional - sage.graphs + sage: p = superp.facets()[0] + sage: p 2-d face of 3-d lattice polytope in 4-d lattice M - sage: p.face_lattice() # optional - sage.graphs + sage: p.face_lattice() Finite poset containing 8 elements with distinguished linear extension - sage: p.face_lattice().bottom() # optional - sage.graphs + sage: p.face_lattice().bottom() -1-d face of 3-d lattice polytope in 4-d lattice M - sage: p.face_lattice().top() # optional - sage.graphs + sage: p.face_lattice().top() 2-d face of 3-d lattice polytope in 4-d lattice M - sage: p.face_lattice().top() is p # optional - sage.graphs + sage: p.face_lattice().top() is p True """ if self._ambient is self: @@ -2097,7 +2106,7 @@ def faces(self, dim=None, codim=None): Let's take a look at the faces of a square:: sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) - sage: square.faces() # optional - sage.graphs + sage: square.faces() # needs sage.graphs ((-1-d face of 2-d lattice polytope in 2-d lattice M,), (0-d face of 2-d lattice polytope in 2-d lattice M, 0-d face of 2-d lattice polytope in 2-d lattice M, @@ -2111,7 +2120,7 @@ def faces(self, dim=None, codim=None): Its faces of dimension one (i.e., edges):: - sage: square.faces(dim=1) # optional - sage.graphs + sage: square.faces(dim=1) # needs sage.graphs (1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, @@ -2119,16 +2128,16 @@ def faces(self, dim=None, codim=None): Its faces of codimension one are the same (also edges):: - sage: square.faces(codim=1) is square.faces(dim=1) # optional - sage.graphs + sage: square.faces(codim=1) is square.faces(dim=1) # needs sage.graphs True Let's pick a particular face:: - sage: face = square.faces(dim=1)[0] # optional - sage.graphs + sage: face = square.faces(dim=1)[0] # needs sage.graphs Now you can look at the actual vertices of this face... :: - sage: face.vertices() # optional - sage.graphs + sage: face.vertices() # needs sage.graphs M(0, 0), M(0, 1) in 2-d lattice M @@ -2136,9 +2145,9 @@ def faces(self, dim=None, codim=None): ... or you can see indices of the vertices of the original polytope that correspond to the above ones:: - sage: face.ambient_vertex_indices() # optional - sage.graphs + sage: face.ambient_vertex_indices() # needs sage.graphs (0, 3) - sage: square.vertices(face.ambient_vertex_indices()) # optional - sage.graphs + sage: square.vertices(face.ambient_vertex_indices()) # needs sage.graphs M(0, 0), M(0, 1) in 2-d lattice M @@ -2363,13 +2372,14 @@ def facet_of(self): EXAMPLES:: + sage: # needs sage.graphs sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) - sage: square.facet_of() # optional - sage.graphs + sage: square.facet_of() () - sage: face = square.faces(0)[0] # optional - sage.graphs - sage: len(face.facet_of()) # optional - sage.graphs + sage: face = square.faces(0)[0] + sage: len(face.facet_of()) 2 - sage: face.facet_of()[1] # optional - sage.graphs + sage: face.facet_of()[1] 1-d face of 2-d lattice polytope in 2-d lattice M """ L = self._ambient.face_lattice() @@ -2387,11 +2397,11 @@ def facets(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.facets() # optional - sage.graphs + sage: o.facets() # needs sage.graphs (2-d face of 3-d reflexive polytope in 3-d lattice M, ... 2-d face of 3-d reflexive polytope in 3-d lattice M) - sage: len(o.facets()) # optional - sage.graphs + sage: len(o.facets()) # needs sage.graphs 8 """ return self.faces(codim=1) @@ -2419,14 +2429,14 @@ def incidence_matrix(self): [0 1 1 0] [1 1 0 0] [1 0 0 1] - sage: o.faces(1)[0].incidence_matrix() # optional - sage.graphs + sage: o.faces(1)[0].incidence_matrix() # needs sage.graphs [1 0] [0 1] sage: o = lattice_polytope.cross_polytope(4) sage: o.incidence_matrix().column(3).nonzero_positions() [3, 4, 5, 6] - sage: o.facets()[3].ambient_vertex_indices() # optional - sage.graphs + sage: o.facets()[3].ambient_vertex_indices() # needs sage.graphs (3, 4, 5, 6) TESTS:: @@ -2470,7 +2480,7 @@ def index(self): database:: sage: d = lattice_polytope.cross_polytope(2) - sage: d.index() # optional - palp + sage: d.index() # needs palp 3 Note that polytopes with the same index are not necessarily the @@ -2492,7 +2502,7 @@ def index(self): But they are in the same `GL(Z^n)` orbit and have the same normal form:: - sage: d.normal_form() # optional - palp + sage: d.normal_form() # needs palp M( 1, 0), M( 0, 1), M( 0, -1), @@ -2531,7 +2541,7 @@ def interior_point_indices(self): The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.points() # optional - palp + sage: square.points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -2542,18 +2552,18 @@ def interior_point_indices(self): N( 0, 1), N( 1, 0) in 2-d lattice N - sage: square.interior_point_indices() # optional - palp + sage: square.interior_point_indices() # needs palp (6,) Its edges also have a single interior point each:: - sage: face = square.edges()[0] # optional - sage.graphs - sage: face.points() # optional - sage.graphs + sage: face = square.edges()[0] # needs sage.graphs + sage: face.points() # needs sage.graphs N(-1, -1), N(-1, 1), N(-1, 0) in 2-d lattice N - sage: face.interior_point_indices() # optional - sage.graphs + sage: face.interior_point_indices() # needs sage.graphs (2,) """ return tuple(i @@ -2573,14 +2583,14 @@ def interior_points(self): The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.interior_points() # optional - palp + sage: square.interior_points() # needs palp N(0, 0) in 2-d lattice N Its edges also have a single interior point each:: - sage: face = square.edges()[0] # optional - sage.graphs - sage: face.interior_points() # optional - sage.graphs + sage: face = square.edges()[0] # needs sage.graphs + sage: face.interior_points() # needs sage.graphs N(-1, 0) in 2-d lattice N """ @@ -2666,7 +2676,7 @@ def ambient_vector_space(self, base_field=None): sage: p = LatticePolytope([(1,0)]) sage: p.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: p.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: p.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.lattice().vector_space(base_field=base_field) @@ -2727,7 +2737,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Nef-partitions of the 4-dimensional cross-polytope:: sage: p = lattice_polytope.cross_polytope(4) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp [ Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, @@ -2741,7 +2751,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Now we omit projections:: - sage: p.nef_partitions(keep_projections=False) # optional - palp + sage: p.nef_partitions(keep_projections=False) # needs palp [ Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, @@ -2754,7 +2764,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Currently Hodge numbers cannot be computed for a given nef-partition:: - sage: p.nef_partitions()[1].hodge_numbers() # optional - palp + sage: p.nef_partitions()[1].hodge_numbers() # needs palp Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)! @@ -2762,7 +2772,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, But they can be obtained from ``nef.x`` for all nef-partitions at once. Partitions will be exactly the same:: - sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011) # optional - palp + sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011), needs palp [ Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, @@ -2776,26 +2786,26 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Now it is possible to get Hodge numbers:: - sage: p.nef_partitions(hodge_numbers=True)[1].hodge_numbers() # optional - palp + sage: p.nef_partitions(hodge_numbers=True)[1].hodge_numbers() # needs palp (20,) Since nef-partitions are cached, their Hodge numbers are accessible after the first request, even if you do not specify ``hodge_numbers=True`` anymore:: - sage: p.nef_partitions()[1].hodge_numbers() # optional - palp + sage: p.nef_partitions()[1].hodge_numbers() # needs palp (20,) We illustrate removal of symmetric partitions on a diamond:: sage: p = lattice_polytope.cross_polytope(2) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp [ Nef-partition {0, 2} ⊔ {1, 3} (direct product), Nef-partition {0, 1} ⊔ {2, 3}, Nef-partition {0, 1, 2} ⊔ {3} (projection) ] - sage: p.nef_partitions(keep_symmetric=True) # optional - palp + sage: p.nef_partitions(keep_symmetric=True) # needs palp [ Nef-partition {0, 1, 3} ⊔ {2} (projection), Nef-partition {0, 2, 3} ⊔ {1} (projection), @@ -2810,7 +2820,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (-1,0,0), (0,-1,0), (0,0,-1)]) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp Traceback (most recent call last): ... ValueError: The given polytope is not reflexive! @@ -2864,8 +2874,8 @@ def nef_x(self, keys): nef-partitions:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-N -V -p") # optional - palp - sage: s # output contains random time # optional - palp + sage: s = o.nef_x("-N -V -p") # needs palp + sage: s # output contains random time # needs palp M:27 8 N:7 6 codim=2 #part=5 3 6 Vertices of P: 1 0 0 -1 0 0 @@ -2952,7 +2962,7 @@ def normal_form(self, algorithm="palp", permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: d.normal_form() # optional - palp + sage: d.normal_form() # needs palp M( 1, 0), M( 0, 1), M( 0, -1), @@ -2961,9 +2971,9 @@ def normal_form(self, algorithm="palp", permutation=False): The diamond is the 3rd polytope in the internal database:: - sage: d.index() # optional - palp + sage: d.index() # needs palp 3 - sage: d # optional - palp + sage: d # needs palp 2-d reflexive polytope #3 in 2-d lattice M You can get it in its normal form (in the default lattice) as :: @@ -2988,7 +2998,7 @@ def normal_form(self, algorithm="palp", permutation=False): We can perform the same examples using other algorithms:: sage: o = lattice_polytope.cross_polytope(2) - sage: o.normal_form(algorithm="palp_native") + sage: o.normal_form(algorithm="palp_native") # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), @@ -2996,7 +3006,7 @@ def normal_form(self, algorithm="palp", permutation=False): in 2-d lattice M sage: o = lattice_polytope.cross_polytope(2) - sage: o.normal_form(algorithm="palp_modified") + sage: o.normal_form(algorithm="palp_modified") # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), @@ -3054,13 +3064,13 @@ def _palp_modified_normal_form(self, permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: o._palp_modified_normal_form() # optional - sage.graphs + sage: o._palp_modified_normal_form() # needs sage.graphs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), M(-1, 0) in 2-d lattice M - sage: o._palp_modified_normal_form(permutation=True) # optional - sage.graphs + sage: o._palp_modified_normal_form(permutation=True) # needs sage.graphs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -3107,13 +3117,13 @@ def _palp_native_normal_form(self, permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: o._palp_native_normal_form() # optional - sage.groups + sage: o._palp_native_normal_form() # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), M(-1, 0) in 2-d lattice M - sage: o._palp_native_normal_form(permutation=True) # optional - sage.groups + sage: o._palp_native_normal_form(permutation=True) # needs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -3158,23 +3168,23 @@ def _palp_PM_max(self, check=False): sage: o = lattice_polytope.cross_polytope(2) sage: PM = o.vertex_facet_pairing_matrix() - sage: PM_max = PM.permutation_normal_form() # optional - sage.graphs - sage: PM_max == o._palp_PM_max() # optional - sage.graphs + sage: PM_max = PM.permutation_normal_form() # needs sage.graphs + sage: PM_max == o._palp_PM_max() # needs sage.graphs sage.groups True sage: P2 = ReflexivePolytope(2, 0) - sage: PM_max, permutations = P2._palp_PM_max(check=True) - sage: PM_max + sage: PM_max, permutations = P2._palp_PM_max(check=True) # needs sage.groups + sage: PM_max # needs sage.graphs [3 0 0] [0 3 0] [0 0 3] - sage: list(permutations.values()) + sage: list(permutations.values()) # needs sage.groups [[(1,2,3), (1,2,3)], [(1,3,2), (1,3,2)], [(1,3), (1,3)], [(1,2), (1,2)], [(), ()], [(2,3), (2,3)]] - sage: PM_max.automorphisms_of_rows_and_columns() + sage: PM_max.automorphisms_of_rows_and_columns() # needs sage.graphs [((), ()), ((1,2,3), (1,2,3)), ((1,3,2), (1,3,2)), @@ -3396,10 +3406,10 @@ def npoints(self): octahedron and its polar cube:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.npoints() # optional - palp + sage: o.npoints() # needs palp 7 sage: cube = o.polar() - sage: cube.npoints() # optional - palp + sage: cube.npoints() # needs palp 27 """ try: @@ -3435,9 +3445,9 @@ def origin(self): EXAMPLES:: sage: p = lattice_polytope.cross_polytope(2) - sage: p.origin() # optional - palp + sage: p.origin() # needs palp 4 - sage: p.point(p.origin()) # optional - palp + sage: p.point(p.origin()) # needs palp M(0, 0) sage: p = LatticePolytope(([1],[2])) @@ -3550,30 +3560,30 @@ def plot3d(self, EXAMPLES: The default plot of a cube:: sage: c = lattice_polytope.cross_polytope(3).polar() - sage: c.plot3d() # optional - palp sage.plot + sage: c.plot3d() # needs palp sage.plot Graphics3d Object Plot without facets and points, shown without the frame:: - sage: c.plot3d(show_facets=false, # optional - palp sage.plot + sage: c.plot3d(show_facets=false, # needs palp sage.plot ....: show_points=false).show(frame=False) Plot with facets of different colors:: - sage: c.plot3d(facet_colors=rainbow(c.nfacets(), 'rgbtuple')) # optional - palp sage.plot + sage: c.plot3d(facet_colors=rainbow(c.nfacets(), 'rgbtuple')) # needs palp sage.plot Graphics3d Object It is also possible to plot lower dimensional polytops in 3D (let's also change labels of vertices):: sage: c2 = lattice_polytope.cross_polytope(2) - sage: c2.plot3d(vlabels=["A", "B", "C", "D"]) # optional - palp sage.plot + sage: c2.plot3d(vlabels=["A", "B", "C", "D"]) # needs palp sage.plot Graphics3d Object TESTS:: sage: p = LatticePolytope([[0,0,0],[0,1,1],[1,0,1],[1,1,0]]) - sage: p.plot3d() # optional - palp sage.plot + sage: p.plot3d() # needs palp sage.plot Graphics3d Object """ dim = self.dim() @@ -3664,7 +3674,7 @@ def show3d(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.show3d() # optional - palp sage.plot + sage: o.show3d() # needs palp sage.plot """ self.plot3d().show(axis=False, frame=False) @@ -3684,14 +3694,14 @@ def point(self, i): M( 0, -1, 0), M( 0, 0, -1) in 3-d lattice M - sage: o.point(1) # optional - palp + sage: o.point(1) # needs palp M(0, 1, 0) The only other point in the octahedron is the origin:: - sage: o.point(6) # optional - palp + sage: o.point(6) # needs palp M(0, 0, 0) - sage: o.points() # optional - palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -3720,7 +3730,7 @@ def points(self, *args, **kwds): Lattice points of the octahedron and its polar cube:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.points() # optional - palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -3730,7 +3740,7 @@ def points(self, *args, **kwds): M( 0, 0, 0) in 3-d lattice M sage: cube = o.polar() - sage: cube.points() # optional - palp + sage: cube.points() # needs palp N( 1, -1, -1), N( 1, 1, -1), N( 1, 1, 1), @@ -3763,7 +3773,7 @@ def points(self, *args, **kwds): Lattice points of a 2-dimensional diamond in a 3-dimensional space:: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.points() # optional - palp + sage: p.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M(-1, 0, 0), @@ -3773,7 +3783,7 @@ def points(self, *args, **kwds): Only two of the above points:: - sage: p.points(1, 3) # optional - palp + sage: p.points(1, 3) # needs palp M(0, 1, 0), M(0, -1, 0) in 3-d lattice M @@ -3904,7 +3914,7 @@ def poly_x(self, keys, reduce_dimension=False): reflexive or not:: sage: o = lattice_polytope.cross_polytope(3) - sage: print(o.poly_x("e")) # optional - palp + sage: print(o.poly_x("e")) # needs palp 8 3 Vertices of P-dual <-> Equations of P -1 -1 1 1 -1 1 @@ -3922,7 +3932,7 @@ def poly_x(self, keys, reduce_dimension=False): sage: BIG = lattice_polytope.cross_polytope(7) sage: BIG 7-d reflexive polytope in 7-d lattice M - sage: BIG.poly_x("e") # optional - palp + sage: BIG.poly_x("e") # needs palp Traceback (most recent call last): ... ValueError: Error executing 'poly.x -fe' for the given polytope! @@ -3933,7 +3943,7 @@ def poly_x(self, keys, reduce_dimension=False): could, it would crush anyway):: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.poly_x("e") # optional - palp + sage: p.poly_x("e") # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! @@ -3941,7 +3951,7 @@ def poly_x(self, keys, reduce_dimension=False): But if you know what you are doing, you can call it for the polytope in some basis of the spanned space:: - sage: print(p.poly_x("e", reduce_dimension=True)) # optional - palp + sage: print(p.poly_x("e", reduce_dimension=True)) # needs palp 4 2 Equations of P -1 1 0 1 1 2 @@ -3958,9 +3968,9 @@ def skeleton(self): EXAMPLES:: sage: d = lattice_polytope.cross_polytope(2) - sage: g = d.skeleton(); g # optional - palp sage.graphs + sage: g = d.skeleton(); g # needs palp sage.graphs Graph on 4 vertices - sage: g.edges(sort=True) # optional - palp sage.graphs + sage: g.edges(sort=True) # needs palp sage.graphs [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] """ skeleton = Graph() @@ -3980,35 +3990,35 @@ def skeleton_points(self, k=1): sage: o = lattice_polytope.cross_polytope(3) sage: c = o.polar() - sage: c.skeleton_points() # optional - palp sage.graphs + sage: c.skeleton_points() # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26] The default was 1-skeleton:: - sage: c.skeleton_points(k=1) # optional - palp sage.graphs + sage: c.skeleton_points(k=1) # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26] 0-skeleton just lists all vertices:: - sage: c.skeleton_points(k=0) # optional - palp sage.graphs + sage: c.skeleton_points(k=0) # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7] 2-skeleton lists all points except for the origin (point #17):: - sage: c.skeleton_points(k=2) # optional - palp sage.graphs + sage: c.skeleton_points(k=2) # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26] 3-skeleton includes all points:: - sage: c.skeleton_points(k=3) # optional - palp sage.graphs + sage: c.skeleton_points(k=3) # needs palp [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] It is OK to compute higher dimensional skeletons - you will get the list of all points:: - sage: c.skeleton_points(k=100) # optional - palp sage.graphs + sage: c.skeleton_points(k=100) # needs palp [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] """ @@ -4036,7 +4046,7 @@ def skeleton_show(self, normal=None): EXAMPLES: Show a pretty picture of the octahedron:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.skeleton_show([1,2,4]) # optional - palp sage.plot + sage: o.skeleton_show([1,2,4]) # needs palp sage.plot Does not work for a diamond at the moment:: @@ -4064,7 +4074,7 @@ def traverse_boundary(self): EXAMPLES:: sage: p = lattice_polytope.cross_polytope(2).polar() - sage: p.traverse_boundary() # optional - sage.graphs + sage: p.traverse_boundary() # needs sage.graphs [3, 0, 1, 2] """ if self.dim() != 2: @@ -4193,9 +4203,9 @@ def is_NefPartition(x): sage: is_NefPartition(1) False sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0]; np # optional - palp + sage: np = o.nef_partitions()[0]; np # needs palp Nef-partition {0, 1, 3} ⊔ {2, 4, 5} - sage: is_NefPartition(np) # optional - palp + sage: is_NefPartition(np) # needs palp True """ return isinstance(x, NefPartition) @@ -4333,7 +4343,7 @@ class NefPartition(SageObject, Hashable): nef-partitions of a given reflexive polytope (they will be computed using ``nef.x`` program from PALP):: - sage: o.nef_partitions() # optional - palp + sage: o.nef_partitions() # needs palp [ Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), @@ -4350,8 +4360,8 @@ def __init__(self, data, Delta_polar, check=True): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0] # optional - palp - sage: TestSuite(np).run() # optional - palp + sage: np = o.nef_partitions()[0] # needs palp + sage: TestSuite(np).run() # needs palp """ if check and not Delta_polar.is_reflexive(): raise ValueError("nef-partitions can be constructed for reflexive " @@ -4386,9 +4396,9 @@ def __eq__(self, other): sage: np = NefPartition([0, 0, 1, 0, 1, 1], o) sage: np == np True - sage: np == o.nef_partitions()[0] # optional - palp + sage: np == o.nef_partitions()[0] # needs palp True - sage: np == o.nef_partitions()[1] # optional - palp + sage: np == o.nef_partitions()[1] # needs palp False sage: np2 = NefPartition(np._vertex_to_part, o) sage: np2 is np @@ -4447,9 +4457,9 @@ def __ne__(self, other): sage: np = NefPartition([0, 0, 1, 0, 1, 1], o) sage: np != np False - sage: np != o.nef_partitions()[0] # optional - palp + sage: np != o.nef_partitions()[0] # needs palp False - sage: np != o.nef_partitions()[1] # optional - palp + sage: np != o.nef_partitions()[1] # needs palp True sage: np2 = NefPartition(np._vertex_to_part, o) sage: np2 is np @@ -4729,14 +4739,15 @@ def hodge_numbers(self): Currently, you need to request Hodge numbers when you compute nef-partitions:: + sage: # long time, needs palp sage: p = lattice_polytope.cross_polytope(5) - sage: np = p.nef_partitions()[0] # long time (4s on sage.math, 2011) # optional - palp - sage: np.hodge_numbers() # long time # optional - palp + sage: np = p.nef_partitions()[0] # 4s on sage.math, 2011 + sage: np.hodge_numbers() Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)! - sage: np = p.nef_partitions(hodge_numbers=True)[0] # long time (13s on sage.math, 2011) # optional - palp - sage: np.hodge_numbers() # long time # optional - palp + sage: np = p.nef_partitions(hodge_numbers=True)[0] # 13s on sage.math, 2011 + sage: np.hodge_numbers() (19, 19) """ try: @@ -4914,11 +4925,11 @@ def part(self, i, all_points=False): Nef-partition {0, 1, 3} ⊔ {2, 4, 5} sage: np.part(0) (0, 1, 3) - sage: np.part(0, all_points=True) # optional - palp + sage: np.part(0, all_points=True) # needs palp (0, 1, 3) sage: np.dual().part(0) (0, 1, 2, 3) - sage: np.dual().part(0, all_points=True) # optional - palp + sage: np.dual().part(0, all_points=True) # needs palp (0, 1, 2, 3, 8) """ return self.parts(all_points)[i] @@ -4948,11 +4959,11 @@ def parts(self, all_points=False): Nef-partition {0, 1, 3} ⊔ {2, 4, 5} sage: np.parts() ((0, 1, 3), (2, 4, 5)) - sage: np.parts(all_points=True) # optional - palp + sage: np.parts(all_points=True) # needs palp ((0, 1, 3), (2, 4, 5)) sage: np.dual().parts() ((0, 1, 2, 3), (4, 5, 6, 7)) - sage: np.dual().parts(all_points=True) # optional - palp + sage: np.dual().parts(all_points=True) # needs palp ((0, 1, 2, 3, 8), (4, 5, 6, 7, 10)) """ parts = [[] for _ in range(self._nparts)] @@ -5026,29 +5037,29 @@ def part_of_point(self, i): sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,1), (0,1,-1), ....: (0,-1,1), (-1,1,0), (0,-1,-1), (-1,-1,0), (-1,-1,2)]) - sage: np = p.nef_partitions()[0]; np # optional - palp + sage: np = p.nef_partitions()[0]; np # needs palp Nef-partition {1, 2, 5, 7, 8} ⊔ {0, 3, 4, 6} sage: p.nvertices() 9 - sage: p.npoints() # optional - palp + sage: p.npoints() # needs palp 15 We see that the polytope has 6 more points in addition to vertices. One of them is the origin:: - sage: p.origin() # optional - palp + sage: p.origin() # needs palp 14 - sage: np.part_of_point(14) # optional - palp + sage: np.part_of_point(14) # needs palp Traceback (most recent call last): ... ValueError: the origin belongs to all parts! But the remaining 5 are partitioned by ``np``:: - sage: [n for n in range(p.npoints()) # optional - palp + sage: [n for n in range(p.npoints()) # needs palp ....: if p.origin() != n and np.part_of_point(n) == 0] [1, 2, 5, 7, 8, 9, 11, 13] - sage: [n for n in range(p.npoints()) # optional - palp + sage: [n for n in range(p.npoints()) # needs palp ....: if p.origin() != n and np.part_of_point(n) == 1] [0, 3, 4, 6, 10, 12] """ @@ -5081,27 +5092,29 @@ def _palp(command, polytopes, reduce_dimension=False): TESTS:: + sage: # needs palp sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -f", [o]) # optional - palp - sage: f = open(result_name) # optional - palp - sage: f.readlines() # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -f", [o]) + sage: f = open(result_name) + sage: f.readlines() ['M:7 6 N:27 8 Pic:17 Cor:0\n'] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: lattice_polytope._palp("poly.x -f", [p]) # optional - palp + sage: lattice_polytope._palp("poly.x -f", [p]) # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! - sage: result_name = lattice_polytope._palp("poly.x -f", [p], # optional - palp + sage: # needs palp + sage: result_name = lattice_polytope._palp("poly.x -f", [p], ....: reduce_dimension=True) - sage: f = open(result_name) # optional - palp - sage: f.readlines() # optional - palp + sage: f = open(result_name) + sage: f.readlines() ['M:5 4 F:4\n'] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ if _palp_dimension is not None: dot = command.find(".") @@ -5172,9 +5185,9 @@ def _palp_canonical_order(V, PM_max, permutations): sage: L = lattice_polytope.cross_polytope(2) sage: V = L.vertices() - sage: PM_max, permutations = L._palp_PM_max(check=True) # optional - sage.groups + sage: PM_max, permutations = L._palp_PM_max(check=True) # needs sage.groups sage: from sage.geometry.lattice_polytope import _palp_canonical_order - sage: _palp_canonical_order(V, PM_max, permutations) # optional - sage.groups + sage: _palp_canonical_order(V, PM_max, permutations) # needs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -5228,9 +5241,9 @@ def _palp_convert_permutation(permutation): EXAMPLES:: sage: from sage.geometry.lattice_polytope import _palp_convert_permutation - sage: _palp_convert_permutation('1023') # optional - sage.groups + sage: _palp_convert_permutation('1023') # needs sage.groups (1,2) - sage: _palp_convert_permutation('0123456789bac') # optional - sage.groups + sage: _palp_convert_permutation('0123456789bac') # needs sage.groups (11,12) """ def from_palp_index(i): @@ -5271,14 +5284,14 @@ def _read_nef_x_partitions(data): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-N -p") # optional - palp - sage: print(s) # random # optional - palp + sage: s = o.nef_x("-N -p") # needs palp + sage: print(s) # random # needs palp M:27 8 N:7 6 codim=2 #part=5 P:0 V:2 4 5 0sec 0cpu P:2 V:3 4 5 0sec 0cpu P:3 V:4 5 0sec 0cpu np=3 d:1 p:1 0sec 0cpu - sage: lattice_polytope._read_nef_x_partitions(s) # optional - palp + sage: lattice_polytope._read_nef_x_partitions(s) # needs palp [[2, 4, 5], [3, 4, 5], [4, 5]] """ if isinstance(data, str): @@ -5333,9 +5346,10 @@ def _read_poly_x_incidences(data, dim): TESTS:: + sage: # needs palp sage: p = lattice_polytope.cross_polytope(2) - sage: result_name = lattice_polytope._palp("poly.x -fi", [p]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fi", [p]) + sage: with open(result_name) as f: ....: print(f.read()) Incidences as binary numbers [F-vector=(4 4)]: v[d][i]: sum_j Incidence(i'th dim-d-face, j-th vertex) x 2^j @@ -5344,12 +5358,12 @@ def _read_poly_x_incidences(data, dim): f[d][i]: sum_j Incidence(i'th dim-d-face, j-th facet) x 2^j f[0]: 0011 0101 1010 1100 f[1]: 0001 0010 0100 1000 - sage: f = open(result_name) # optional - palp - sage: l = f.readline() # optional - palp - sage: lattice_polytope._read_poly_x_incidences(f, 2) # optional - palp + sage: f = open(result_name) + sage: l = f.readline() + sage: lattice_polytope._read_poly_x_incidences(f, 2) [[[3], [0], [2], [1]], [[0, 3], [2, 3], [0, 1], [1, 2]]] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ data.readline() lines = [data.readline().split() for i in range(dim)] @@ -5387,7 +5401,7 @@ def all_cached_data(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_cached_data([o]) # optional - palp + sage: lattice_polytope.all_cached_data([o]) # needs palp """ all_polars(polytopes) all_points(polytopes) @@ -5418,8 +5432,8 @@ def all_nef_partitions(polytopes, keep_symmetric=False): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_nef_partitions([o]) # optional - palp - sage: o.nef_partitions() # optional - palp + sage: lattice_polytope.all_nef_partitions([o]) # needs palp + sage: o.nef_partitions() # needs palp [ Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), @@ -5432,7 +5446,7 @@ def all_nef_partitions(polytopes, keep_symmetric=False): sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (-1,0,0), (0,-1,0), (0,0,-1)]) - sage: lattice_polytope.all_nef_partitions([o, p]) # optional - palp + sage: lattice_polytope.all_nef_partitions([o, p]) # needs palp Traceback (most recent call last): ... ValueError: nef-partitions can be computed for reflexive polytopes only @@ -5467,8 +5481,8 @@ def all_points(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_points([o]) # optional - palp - sage: o.points() # optional - palp + sage: lattice_polytope.all_points([o]) # needs palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -5520,8 +5534,8 @@ def all_polars(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_polars([o]) # optional - palp - sage: o.polar() # optional - palp + sage: lattice_polytope.all_polars([o]) # needs palp + sage: o.polar() # needs palp 3-d reflexive polytope in 3-d lattice N """ result_name = _palp("poly.x -fe", polytopes) @@ -5663,7 +5677,7 @@ def positive_integer_relations(points): sage: p = LatticePolytope([(1,0,0), (0,1,0), ....: (-1,-1,0), (0,0,1), (-1,0,-1)]) - sage: p.points() # optional - palp + sage: p.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M(-1, -1, 0), @@ -5675,7 +5689,7 @@ def positive_integer_relations(points): We can compute linear relations between its points in the following way:: - sage: p.points().matrix().kernel().echelonized_basis_matrix() # optional - palp + sage: p.points().matrix().kernel().echelonized_basis_matrix() # needs palp [ 1 0 0 1 1 0] [ 0 1 1 -1 -1 0] [ 0 0 0 0 0 1] @@ -5685,7 +5699,7 @@ def positive_integer_relations(points): coefficients are non-negative integers:: sage: points = p.points().column_matrix() - sage: lattice_polytope.positive_integer_relations(points) # optional - palp + sage: lattice_polytope.positive_integer_relations(points) # needs palp [1 0 0 1 1 0] [1 1 1 0 0 0] [0 0 0 0 0 1] @@ -5751,10 +5765,11 @@ def read_all_polytopes(file_name): We use poly.x to compute two polar polytopes and read them:: + sage: # needs palp sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) + sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of P-dual <-> Equations of P -1 1 @@ -5770,10 +5785,10 @@ def read_all_polytopes(file_name): 1 -1 -1 -1 1 -1 1 1 -1 - sage: lattice_polytope.read_all_polytopes(result_name) # optional - palp + sage: lattice_polytope.read_all_polytopes(result_name) [2-d reflexive polytope #14 in 2-d lattice M, 3-d reflexive polytope in 3-d lattice M] - sage: os.remove(result_name) # optional - palp + sage: os.remove(result_name) """ polytopes = [] with open(file_name) as f: @@ -5873,7 +5888,7 @@ def set_palp_dimension(d): Let's try to work with a 7-dimensional polytope:: sage: p = lattice_polytope.cross_polytope(7) - sage: p._palp("poly.x -fv") # optional - palp + sage: p._palp("poly.x -fv") # needs palp Traceback (most recent call last): ... ValueError: Error executing 'poly.x -fv' for the given polytope! @@ -5883,7 +5898,7 @@ def set_palp_dimension(d): However, we can work with this polytope by changing PALP dimension to 11:: sage: lattice_polytope.set_palp_dimension(11) - sage: p._palp("poly.x -fv") # optional - palp + sage: p._palp("poly.x -fv") # needs palp '7 14 Vertices of P...' Let's go back to default settings:: @@ -5914,10 +5929,11 @@ def skip_palp_matrix(data, n=1): EXAMPLES: We create a file with vertices of the square and the cube, but read only the second set:: + sage: # needs palp sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) + sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of P-dual <-> Equations of P -1 1 @@ -5933,14 +5949,14 @@ def skip_palp_matrix(data, n=1): 1 -1 -1 -1 1 -1 1 1 -1 - sage: f = open(result_name) # optional - palp - sage: lattice_polytope.skip_palp_matrix(f) # optional - palp - sage: lattice_polytope.read_palp_matrix(f) # optional - palp + sage: f = open(result_name) + sage: lattice_polytope.skip_palp_matrix(f) + sage: lattice_polytope.read_palp_matrix(f) [-1 1 -1 1 -1 1 -1 1] [-1 -1 1 1 -1 -1 1 1] [ 1 1 1 1 -1 -1 -1 -1] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ for i in range(n): line = data.readline() diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index b62e17193a3..0bc15952746 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -440,7 +440,7 @@ def evaluate(self, point): 9 sage: ex([1,1]) # syntactic sugar 9 - sage: ex([pi, e]) # optional - sage.symbolic + sage: ex([pi, e]) # needs sage.symbolic 2*pi + 3*e + 4 """ try: diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index 7eae994c6e3..28101e70646 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -464,7 +464,7 @@ def plot(self, **kwargs): sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]) - sage: polygon = NP.plot() # optional - sage.plot + sage: polygon = NP.plot() # needs sage.plot """ vertices = self.vertices() if len(vertices) == 0: diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index bec18228aca..2e20e508057 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -203,7 +203,7 @@ class PolyhedralComplex(GenericCellComplex): (A vertex at (0, 1/4),), (A vertex at (1/7, 2/7),), (A vertex at (1/3, 1/3),)] - sage: pc.plot() # optional - sage.plot + sage: pc.plot() # needs sage.plot Graphics object consisting of 10 graphics primitives sage: pc.is_pure() True @@ -752,17 +752,17 @@ def plot(self, **kwds): sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) sage: pc1 = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) - sage: g0 = pc1.plot(color='rainbow', **bb) # optional - sage.plot - sage: g1 = pc1.plot(explosion_factor=0.5, **bb) # optional - sage.plot - sage: g2 = pc1.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot + sage: g0 = pc1.plot(color='rainbow', **bb) # needs sage.plot + sage: g1 = pc1.plot(explosion_factor=0.5, **bb) # needs sage.plot + sage: g2 = pc1.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # needs sage.plot sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested sage: pc2 = PolyhedralComplex([polytopes.hypercube(3)]) sage: pc3 = pc2.subdivide(new_vertices=[(0, 0, 0)]) - sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', # optional - sage.plot + sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', # needs sage.plot ....: alpha=0.5, axes=False, online=True) sage: pc4 = pc2.subdivide(make_simplicial=True) - sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', # optional - sage.plot + sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', # needs sage.plot ....: wireframe='white', point={'color':'red', 'size':10}, ....: alpha=0.6, online=True) sage: pc5 = PolyhedralComplex([ @@ -773,7 +773,7 @@ def plot(self, **kwds): ....: Polyhedron(rays=[[-1,0,0], [0,-1,0], [0,0,1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,-1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,1]])]) - sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, # optional - sage.plot + sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, # needs sage.plot ....: point={'size': 20}, axes=False, online=True) """ @@ -1001,7 +1001,7 @@ def face_poset(self): sage: poset Finite poset containing 11 elements sage: d = {i: i.vertices_matrix() for i in poset} - sage: poset.plot(element_labels=d) # optional - sage.plot + sage: poset.plot(element_labels=d) # needs sage.plot Graphics object consisting of 28 graphics primitives For a nonbounded polyhedral complex:: @@ -2532,11 +2532,11 @@ def exploded_plot(polyhedra, *, sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (1, 1), (2, 0)]) - sage: exploded_plot([p1, p2, p3]) # optional - sage.plot + sage: exploded_plot([p1, p2, p3]) # needs sage.plot Graphics object consisting of 20 graphics primitives - sage: exploded_plot([p1, p2, p3], center=(1, 1)) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1)) # needs sage.plot Graphics object consisting of 19 graphics primitives - sage: exploded_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # needs sage.plot Graphics object consisting of 23 graphics primitives """ from sage.plot.colors import rainbow diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py index ed3f6cac169..a39ad446a80 100644 --- a/src/sage/geometry/polyhedron/backend_cdd_rdf.py +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -134,6 +134,7 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal Test that :trac:`29568` is fixed:: + sage: # needs sage.groups sage: P = polytopes.buckyball(exact=False) sage: Q = P + P.center() sage: P.is_combinatorially_isomorphic(Q) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 4e190c09cda..77d83c4a381 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -7,15 +7,16 @@ EXAMPLES:: + sage: # needs sage.rings.number_field sage: p0 = (0, 0) sage: p1 = (1, 0) - sage: p2 = (1/2, AA(3).sqrt()/2) # optional - sage.rings.number_field - sage: equilateral_triangle = Polyhedron([p0, p1, p2]) # optional - sage.rings.number_field - sage: equilateral_triangle.vertices() # optional - sage.rings.number_field + sage: p2 = (1/2, AA(3).sqrt()/2) + sage: equilateral_triangle = Polyhedron([p0, p1, p2]) + sage: equilateral_triangle.vertices() (A vertex at (0, 0), A vertex at (1, 0), A vertex at (0.500000000000000?, 0.866025403784439?)) - sage: equilateral_triangle.inequalities() # optional - sage.rings.number_field + sage: equilateral_triangle.inequalities() (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -46,23 +47,24 @@ class Polyhedron_field(Polyhedron_base): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # needs sage.rings.number_field ....: rays=[(1,1)], lines=[], backend='field', base_ring=AA) - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field TESTS:: - sage: K. = QuadraticField(3) # optional - sage.rings.number_field - sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: K. = QuadraticField(3) # needs sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # needs sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field Check that :trac:`19013` is fixed:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field - sage: P1 = Polyhedron([[0,1],[1,1],[1,-phi+1]]) # optional - sage.rings.number_field - sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) # optional - sage.rings.number_field - sage: P1.intersection(P2) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - x - 1, embedding=1.618) + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]]) + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) + sage: P1.intersection(P2) The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 @@ -85,10 +87,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_zero(0) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_zero(0) # needs sage.rings.number_field sage.symbolic True - sage: p._is_zero(1/100000) # optional - sage.rings.number_field + sage: p._is_zero(1/100000) # needs sage.rings.number_fiedl False """ return x == 0 @@ -107,10 +109,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_nonneg(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_nonneg(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field + sage: p._is_nonneg(-1/100000) # needs sage.rings.number_field sage.symbolic False """ return x >= 0 @@ -129,10 +131,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_positive(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_positive(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_positive(0) # optional - sage.rings.number_field + sage: p._is_positive(0) # needs sage.rings.number_field sage.symbolic False """ return x > 0 @@ -152,12 +154,12 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p # optional - sage.rings.number_field + sage: p # needs sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices """ self._init_Vrepresentation(*Vrep) @@ -246,13 +248,13 @@ def _init_Vrepresentation(self, vertices, rays, lines): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field ....: Vrep_minimal=True, ....: Hrep_minimal=True) - sage: p.vertices_list() # optional - sage.rings.number_field + sage: p.vertices_list() # needs sage.rings.number_field [[0], [1]] """ self._Vrepresentation = [] @@ -271,15 +273,15 @@ def _init_Vrepresentation_backend(self, Vrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # needs sage.rings.number_field sage.symbolic ....: (sqrt(2), 0), ....: (4, sqrt(5)/6)], ....: base_ring=AA, backend='field') - sage: p.Hrepresentation() # optional - sage.rings.number_field + sage: p.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() # optional - sage.rings.number_field + sage: p.Vrepresentation() # needs sage.rings.number_field sage.symbolic (A vertex at (0.?e-16, 0.7071067811865475?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -294,12 +296,12 @@ def _init_Hrepresentation(self, inequalities, equations): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p.inequalities_list() # optional - sage.rings.number_field + sage: p.inequalities_list() # needs sage.rings.number_field [[0, 1], [1, -1]] """ self._Hrepresentation = [] @@ -316,15 +318,15 @@ def _init_Hrepresentation_backend(self, Hrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # needs sage.rings.number_field sage.symbolic ....: (sqrt(2), 0), ....: (4, sqrt(5)/6)], ....: base_ring=AA, backend='field') - sage: p.Hrepresentation() # optional - sage.rings.number_field + sage: p.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() # optional - sage.rings.number_field + sage: p.Vrepresentation() # needs sage.rings.number_field sage.symbolic (A vertex at (0.?e-16, 0.7071067811865475?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -337,11 +339,11 @@ def _init_empty_polyhedron(self): TESTS:: - sage: empty = Polyhedron(backend='field', base_ring=AA); empty # optional - sage.rings.number_field + sage: empty = Polyhedron(backend='field', base_ring=AA); empty # needs sage.rings.number_field The empty polyhedron in AA^0 - sage: empty.Vrepresentation() # optional - sage.rings.number_field + sage: empty.Vrepresentation() # needs sage.rings.number_field () - sage: empty.Hrepresentation() # optional - sage.rings.number_field + sage: empty.Hrepresentation() # needs sage.rings.number_field (An equation -1 == 0,) sage: Polyhedron(vertices=[], backend='field') The empty polyhedron in QQ^0 diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index ce389f090a2..19da8cce5e5 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -156,7 +156,7 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): Algebraic polyhedra:: - sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], # optional - sage.rings.number_field sage.symbolic + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], # needs sage.rings.number_field sage.symbolic ....: backend='normaliz', verbose=True) # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 1 @@ -168,13 +168,13 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): (a) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^2 - 2', 'a', '[1.414213562373095 +/- 2.99e-16]'], subspace=[], vertices=[[1, 1], [[[0, 1], [1, 1]], 1]]) - sage: P # optional - sage.rings.number_field sage.symbolic + sage: P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field sage.symbolic + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (1), A vertex at (sqrt(2))) - sage: P = polytopes.icosahedron(exact=True, # optional - sage.rings.number_field + sage: P = polytopes.icosahedron(exact=True, # needs sage.rings.number_field ....: backend='normaliz'); P A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 @@ -182,7 +182,7 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): defined as the convex hull of 12 vertices sage: x = polygen(ZZ) - sage: P = Polyhedron(vertices=[[sqrt(2)], # optional - sage.rings.number_field sage.symbolic + sage: P = Polyhedron(vertices=[[sqrt(2)], # needs sage.rings.number_field sage.symbolic ....: [AA.polynomial_root(x^3 - 2, RIF(0,3))]], ....: backend='normaliz', verbose=True) # ----8<---- Equivalent Normaliz input file ----8<---- @@ -195,10 +195,10 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): (a^2) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^6 - 2', 'a', '[1.122462048309373 +/- 5.38e-16]'], subspace=[], vertices=[[[[0, 1], [0, 1], [0, 1], [1, 1], [0, 1], [0, 1]], 1], [[[0, 1], [0, 1], [1, 1], [0, 1], [0, 1], [0, 1]], 1]]) - sage: P # optional - sage.rings.number_field sage.symbolic + sage: P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field sage.symbolic + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ @@ -248,23 +248,24 @@ def _nmz_result(self, normaliz_cone, property): ... NormalizError: Some error in the normaliz input data detected: Unknown ConeProperty... - sage: x = polygen(QQ, 'x') # optional - sage.rings.number_field - sage: K. = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(0, 0), (1, 1), (a, 3), (-1, a**2)], # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') + sage: K. = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) + sage: p = Polyhedron(vertices=[(0, 0), (1, 1), (a, 3), (-1, a**2)], ....: rays=[(-1,-a)], backend='normaliz') - sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) # optional - sage.rings.number_field + sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) [[-1, a^2, 1], [1, 1, 1], [a, 3, 1]] - sage: triangulation_generators = p._nmz_result(p._normaliz_cone, # optional - sage.rings.number_field + sage: triangulation_generators = p._nmz_result(p._normaliz_cone, ....: 'Triangulation')[1] - sage: sorted(triangulation_generators) # optional - sage.rings.number_field + sage: sorted(triangulation_generators) [[-a^2, -3, 0], [-1, a^2, 1], [0, 0, 1], [1, 1, 1], [a, 3, 1]] - sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 True - sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 True - sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') [[-1/3*a^2, -1, 0]] - sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') [] """ def rational_handler(list): @@ -309,7 +310,7 @@ def _convert_to_pynormaliz(x): TESTS:: - sage: K. = QuadraticField(2) # optional - sage.rings.number_field + sage: K. = QuadraticField(2) # needs sage.rings.number_field sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._convert_to_pynormaliz(17) 17 @@ -321,9 +322,9 @@ def _convert_to_pynormaliz(x): [[28, 5]] sage: Pn._convert_to_pynormaliz(28901824309821093821093812093810928309183091832091/5234573685674784567853456543456456786543456765) [[28901824309821093821093812093810928309183091832091, 5234573685674784567853456543456456786543456765]] - sage: Pn._convert_to_pynormaliz(7 + sqrt2) # optional - sage.rings.number_field + sage: Pn._convert_to_pynormaliz(7 + sqrt2) # needs sage.rings.number_field [[7, 1], [1, 1]] - sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) # optional - sage.rings.number_field + sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) # needs sage.rings.number_field [[7, 2], [1, 1]] sage: Pn._convert_to_pynormaliz([[1, 2], (3, 4)]) [[1, 2], [3, 4]] @@ -331,8 +332,8 @@ def _convert_to_pynormaliz(x): Check that :trac:`29836` is fixed:: sage: P = polytopes.simplex(backend='normaliz') - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: P.dilation(sqrt2) # optional - sage.rings.number_field + sage: K. = QuadraticField(2) # needs sage.rings.number_field + sage: P.dilation(sqrt2) # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices @@ -367,17 +368,17 @@ def _init_from_normaliz_data(self, data, internal_base_ring=None, verbose=False) [[0, -1, 2], [0, 2, -1]] sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz - sage: from sage.rings.qqbar import AA # optional - sage.rings.number_field - sage: from sage.rings.number_field.number_field import QuadraticField # optional - sage.rings.number_field + sage: from sage.rings.qqbar import AA # needs sage.rings.number_field + sage: from sage.rings.number_field.number_field import QuadraticField # needs sage.rings.number_field sage: data = {'number_field': ['a^2 - 2', 'a', '[1.4 +/- 0.1]'], ....: 'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz - sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - sage.rings.number_field - sage: Polyhedron_normaliz(parent, None, None, # indirect doctest, optional - sage.rings.number_field + sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # needs sage.rings.number_field + sage: Polyhedron_normaliz(parent, None, None, # needs sage.rings.number_field ....: normaliz_data=data, ....: internal_base_ring=QuadraticField(2)) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 1 vertex and 2 rays - sage: _.inequalities_list() # optional - sage.rings.number_field + sage: _.inequalities_list() # needs sage.rings.number_field [[0, -1/2, 1], [0, 2, -1]] """ if internal_base_ring is None: @@ -432,10 +433,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field sage.symbolic - sage: p._is_zero(0) # optional - sage.rings.number_field sage.symbolic + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_zero(0) # needs sage.rings.number_field sage.symbolic True - sage: p._is_zero(1/100000) # optional - sage.rings.number_field sage.symbolic + sage: p._is_zero(1/100000) # needs sage.rings.number_field sage.symbolic False """ return x == 0 @@ -454,10 +455,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field sage.symbolic - sage: p._is_nonneg(1) # optional - sage.rings.number_field sage.symbolic + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_nonneg(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field sage.symbolic + sage: p._is_nonneg(-1/100000) # needs sage.rings.number_field sage.symbolic False """ return x >= 0 @@ -476,10 +477,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field sage.symbolic - sage: p._is_positive(1) # optional - sage.rings.number_field sage.symbolic + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_positive(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_positive(0) # optional - sage.rings.number_field sage.symbolic + sage: p._is_positive(0) # needs sage.rings.number_field sage.symbolic False """ return x > 0 @@ -586,24 +587,25 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): TESTS:: - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: p = Polyhedron(ieqs=[(1, a, 0)], backend='normaliz') # optional - sage.rings.number_field - sage: p & p == p # optional - sage.rings.number_field + sage: K. = QuadraticField(2) # needs sage.rings.number_field + sage: p = Polyhedron(ieqs=[(1, a, 0)], backend='normaliz') # needs sage.rings.number_field + sage: p & p == p # needs sage.rings.number_field True Check that :trac:`30248` is fixed, that maps as input works:: - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: q = Polyhedron(backend='normaliz', base_ring=AA, ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]) sage: def make_new_Hrep(h): ....: return tuple(x if i == 0 else -1*x ....: for i, x in enumerate(h._vector)) - sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) # optional - sage.rings.number_field - sage: new_equations = map(make_new_Hrep, q.equation_generator()) # optional - sage.rings.number_field - sage: parent = q.parent() # optional - sage.rings.number_field - sage: new_q = parent.element_class(parent, None, # optional - sage.rings.number_field + sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) + sage: new_equations = map(make_new_Hrep, q.equation_generator()) + sage: parent = q.parent() + sage: new_q = parent.element_class(parent, None, ....: [new_inequalities, new_equations]) - sage: new_q # optional - sage.rings.number_field + sage: new_q A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ @@ -736,7 +738,7 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, ....: for arg in args) sage: test_poly(polytopes.simplex(backend='normaliz')) True - sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # optional - sage.rings.number_field + sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # needs sage.rings.number_field True sage: test_poly(Polyhedron(vertices=[[1,0], [0,1]], rays=[[1,1]], ....: backend='normaliz')) @@ -1022,7 +1024,7 @@ def _number_field_triple(internal_base_ring): sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._number_field_triple(QQ) is None True - sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field + sage: Pn._number_field_triple(QuadraticField(5)) # needs sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ R = internal_base_ring @@ -1271,11 +1273,12 @@ def __setstate__(self, state): sage: P2 == P True - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - sage.rings.number_field - sage: P1 = loads(dumps(P)) # optional - sage.rings.number_field - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, ....: internal_base_ring=P1._internal_base_ring) - sage: P == P2 # optional - sage.rings.number_field + sage: P == P2 True Test that :trac:`31820` is fixed:: @@ -1325,7 +1328,7 @@ def integral_hull(self): sage: P = Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], ....: backend='normaliz') sage: PI = P.integral_hull() - sage: P.plot(color='yellow') + PI.plot(color='green') # optional - sage.plot + sage: P.plot(color='yellow') + PI.plot(color='green') # needs sage.plot Graphics object consisting of 10 graphics primitives sage: PI.Vrepresentation() (A vertex at (-1, 0), @@ -1453,8 +1456,8 @@ def _volume_normaliz(self, measure='euclidean'): Check that :trac:`28872` is fixed:: - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - sage.rings.number_field - sage: P.volume(measure='induced_lattice') # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') # needs sage.rings.number_field + sage: P.volume(measure='induced_lattice') # needs sage.rings.number_field -1056*sqrt5 + 2400 Some sanity checks that the ambient volume works correctly:: @@ -1466,12 +1469,12 @@ def _volume_normaliz(self, measure='euclidean'): sage: s._volume_normaliz(measure='ambient') 0 - sage: P = polytopes.regular_polygon(3, backend='normaliz') # optional - sage.rings.number_field - sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(3, backend='normaliz') # needs sage.rings.number_field + sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # needs sage.rings.number_field True - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - sage.rings.number_field - sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') # needs sage.rings.number_field + sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # needs sage.rings.number_field True sage: P = Polyhedron(rays=[[1]], backend='normaliz') @@ -1976,9 +1979,9 @@ def integral_points(self, threshold=10000): sage: pts1 = P.integral_points() sage: all(P.contains(p) for p in pts1) True - sage: pts2 = LatticePolytope(v).points() # optional - palp + sage: pts2 = LatticePolytope(v).points() # needs palp sage: for p in pts1: p.set_immutable() - sage: set(pts1) == set(pts2) # optional - palp + sage: set(pts1) == set(pts2) # needs palp True sage: timeit('Polyhedron(v, backend='normaliz').integral_points()') # not tested - random @@ -2238,16 +2241,17 @@ class functions. is equal to 1 = `\chi_{trivial}` (Prop 6.1 [Stap2011]_). Here is the computation for the 3-dimensional standard simplex:: + sage: # needs sage.groups sage: S = polytopes.simplex(3, backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: G.is_isomorphic(SymmetricGroup(4)) # optional - sage.groups + sage: G = S.restricted_automorphism_group(output='permutation') + sage: G.is_isomorphic(SymmetricGroup(4)) True - sage: len(G) # optional - sage.groups + sage: len(G) 24 - sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - sage.groups + sage: Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 - sage: G.character_table() # optional - sage.groups + sage: G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -2259,29 +2263,30 @@ class functions. `\pm(0,0,1),\pm(1,0,1), \pm(0,1,1), \pm(1,1,1)` and let G = `\Zmod{2}` act on P as follows:: + sage: # needs sage.groups sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], ....: [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') - sage: K = P.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) # optional - sage.groups - sage: conj_reps = G.conjugacy_classes_representatives() # optional - sage.groups - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group=G) # optional - sage.groups - sage: list(Dict.keys())[0] # optional - sage.groups + sage: K = P.restricted_automorphism_group(output='permutation') + sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) + sage: conj_reps = G.conjugacy_classes_representatives() + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group=G) + sage: list(Dict.keys())[0] (0,2)(1,3)(4,6)(5,7) - sage: list(Dict.values())[0] # optional - sage.groups + sage: list(Dict.values())[0] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] - sage: len(G) # optional - sage.groups + sage: len(G) 2 - sage: G.character_table() # optional - sage.groups + sage: G.character_table() [ 1 1] [ 1 -1] Then we calculate the rational function `H^*(t)`:: - sage: Hst = P._Hstar_function_normaliz(G); Hst # optional - sage.groups + sage: Hst = P._Hstar_function_normaliz(G); Hst # needs sage.groups (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) @@ -2289,7 +2294,7 @@ class functions. ``'Hstar_as_lin_comb'``. The first coordinate is the coefficient of the trivial character; the second is the coefficient of the sign character:: - sage: lin = P._Hstar_function_normaliz(G, output='Hstar_as_lin_comb'); lin # optional - sage.groups + sage: lin = P._Hstar_function_normaliz(G, output='Hstar_as_lin_comb'); lin # needs sage.groups ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1)) """ from sage.groups.conjugacy_classes import ConjugacyClassGAP @@ -2400,14 +2405,14 @@ def _Hstar_as_rat_fct(self, initial_Hstar): sage: simplex = Polyhedron(vertices=[[0,0,0], [1,0,0], ....: [0,1,0], [0,0,1]], backend='normaliz') - sage: Hstar = simplex.Hstar_function(); Hstar # indirect doctest # optional - sage.rings.number_field + sage: Hstar = simplex.Hstar_function(); Hstar # indirect doctest # needs sage.rings.number_field chi_4 The polynomial is `\chi_4 \cdot t^0`. We can see which irreducible representation `\chi_4` corresponds to by looking at the character table:: - sage: G = simplex.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: char = G.character_table(); char # optional - sage.groups + sage: G = simplex.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: char = G.character_table(); char # needs sage.groups [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -2421,14 +2426,14 @@ def _Hstar_as_rat_fct(self, initial_Hstar): sage: square = Polyhedron(vertices=[[1,1], [-1,1], [-1,-1], [1,-1]], ....: backend='normaliz') - sage: Hstar = square.Hstar_function(); Hstar # optional - sage.rings.number_field + sage: Hstar = square.Hstar_function(); Hstar # needs sage.rings.number_field chi_0*t^2 + (2*chi_0 + chi_2 + chi_3 + chi_4)*t + chi_0 Plugging in the values from the first column of the character table below yields the `h^*`-polynomial of the square, `t^2+6t+1`:: - sage: G = square.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: G.character_table() # optional - sage.groups + sage: G = square.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: G.character_table() # needs sage.groups [ 1 1 1 1 1] [ 1 -1 -1 1 1] [ 1 -1 1 -1 1] @@ -2475,30 +2480,32 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: + sage: # needs sage.groups sage: p3 = polytopes.permutahedron(3, backend='normaliz') - sage: G = p3.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - sage.groups - sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - sage.groups - sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - sage.groups - sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - sage.groups + sage: G = p3.restricted_automorphism_group(output='permutation') + sage: reflection12 = G([(0,2),(1,4),(3,5)]) + sage: reflection23 = G([(0,1),(2,3),(4,5)]) + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) + sage: S3.is_isomorphic(SymmetricGroup(3)) True - sage: Hstar = p3.Hstar_function(S3) # optional - sage.groups sage.rings.number_field - sage: Hlin = p3.Hstar_function(S3, output='Hstar_as_lin_comb') # optional - sage.groups sage.rings.number_field - sage: p3._is_effective_normaliz(Hstar, Hlin) # optional - sage.groups sage.rings.number_field + sage: Hstar = p3.Hstar_function(S3) # needs sage.rings.number_field + sage: Hlin = p3.Hstar_function(S3, output='Hstar_as_lin_comb') # needs sage.rings.number_field + sage: p3._is_effective_normaliz(Hstar, Hlin) # needs sage.rings.number_field True If the `H^*`-series is not polynomial, then it is not effective:: + sage: # needs sage.groups sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], ....: [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') - sage: G = P.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - sage.groups - sage: Hstar = P.Hstar_function(H); Hstar # optional - sage.groups sage.rings.number_field + sage: G = P.restricted_automorphism_group(output='permutation') + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) + sage: Hstar = P.Hstar_function(H); Hstar # needs sage.rings.number_field (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) - sage: Hstar_lin = P.Hstar_function(H, output='Hstar_as_lin_comb') # optional - sage.groups sage.rings.number_field - sage: P._is_effective_normaliz(Hstar, Hstar_lin) # optional - sage.groups sage.rings.number_field + sage: Hstar_lin = P.Hstar_function(H, output='Hstar_as_lin_comb') # needs sage.rings.number_field + sage: P._is_effective_normaliz(Hstar, Hstar_lin) # needs sage.rings.number_field False """ if not Hstar.denominator().is_unit(): diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 650c41f1e36..e79688bea5f 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -39,27 +39,26 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): EXAMPLES:: - sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field') # optional - sage.rings.number_field - sage: P # optional - sage.rings.number_field + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field'); P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (1), A vertex at (sqrt(2))) - sage: P = polytopes.icosahedron(exact=True, backend='number_field') # optional - sage.rings.number_field - sage: P # optional - sage.rings.number_field + sage: P = polytopes.icosahedron(exact=True, backend='number_field') # needs sage.rings.number_field + sage: P # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices - sage: x = polygen(ZZ); P = Polyhedron( # optional - sage.rings.number_field sage.symbolic + sage: x = polygen(ZZ); P = Polyhedron( # needs sage.rings.number_field sage.symbolic ....: vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], ....: backend='number_field') - sage: P # optional - sage.rings.number_field + sage: P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (sqrt(2)), A vertex at (2^(1/3))) TESTS: @@ -67,19 +66,21 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): Tests from :class:`~sage.geometry.polyhedron.backend_field.Polyhedron_field` -- here the data are already either in a number field or in ``AA``:: - sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field - ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # needs sage.rings.number_field + ....: rays=[(1,1)], lines=[], backend='number_field', + ....: base_ring=AA) + sage: TestSuite(p).run() # needs sage.rings.number_field - sage: K. = QuadraticField(3) # optional - sage.rings.number_field - sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # optional - sage.rings.number_field - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: K. = QuadraticField(3) # needs sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # needs sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 - x - 1, embedding=1.618) # optional - sage.rings.number_field - sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') # optional - sage.rings.number_field - sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') # optional - sage.rings.number_field - sage: P1.intersection(P2) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - x - 1, embedding=1.618) + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') + sage: P1.intersection(P2) The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 @@ -120,11 +121,11 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, Check that the coordinates of a vertex get simplified in the Symbolic Ring:: - sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') # optional - sage.symbolic + sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') # needs sage.symbolic sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field - sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p # optional - sage.symbolic + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p # needs sage.symbolic A 2-dimensional polyhedron in (Symbolic Ring)^2 defined as the convex hull of 3 vertices - sage: p.vertices()[0][0] # optional - sage.symbolic + sage: p.vertices()[0][0] 0 """ (vertices, rays, lines), internal_base_ring \ diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index 52aaeb2743b..624ae2f6340 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -77,13 +77,14 @@ class Polyhedron_polymake(Polyhedron_base): It can also be obtained differently:: - sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], # optional - jupymake + sage: # optional - jupymake + sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], ....: backend='polymake') - sage: P # optional - jupymake + sage: P The empty polyhedron in QQ^2 - sage: P.Vrepresentation() # optional - jupymake + sage: P.Vrepresentation() () - sage: P.Hrepresentation() # optional - jupymake + sage: P.Hrepresentation() (An equation -1 == 0,) The full polyhedron:: @@ -96,8 +97,8 @@ class Polyhedron_polymake(Polyhedron_base): Quadratic fields work:: - sage: V = polytopes.dodecahedron().vertices_list() # optional - sage.rings.number_field - sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake # optional - sage.rings.number_field + sage: V = polytopes.dodecahedron().vertices_list() # needs sage.rings.number_field + sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake, needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 @@ -211,11 +212,12 @@ def __init__(self, parent, Vrep, Hrep, polymake_polytope=None, **kwds): TESTS: - sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - jupymake + sage: # optional - jupymake + sage: p = Polyhedron(backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], ....: backend='polymake') - sage: TestSuite(p).run() # optional - jupymake + sage: TestSuite(p).run() We skip the Lawrence test because it involves numerically unstable floating point arithmetic:: @@ -226,14 +228,15 @@ def __init__(self, parent, Vrep, Hrep, polymake_polytope=None, **kwds): :: - sage: p = Polyhedron(rays=[[1,1]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(rays=[[1]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(vertices=[[]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake + sage: # optional - jupymake + sage: p = Polyhedron(rays=[[1,1]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(rays=[[1]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[[]], backend='polymake') + sage: TestSuite(p).run() """ if polymake_polytope is not None: if Hrep is not None or Vrep is not None: @@ -250,7 +253,7 @@ def _init_from_polymake_polytope(self, polymake_polytope): TESTS:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - jupymake """ self._polymake_polytope = polymake_polytope @@ -281,7 +284,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo EXAMPLES:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Vrepresentation(p, [], [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake @@ -348,7 +351,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): EXAMPLES:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake @@ -644,31 +647,35 @@ def __setstate__(self, state): Test that the obtained cone is valid:: - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake - sage: P = polytopes.permutahedron(4, backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake + sage: P = polytopes.permutahedron(4, backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) - sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) sage: P = Polyhedron(backend='polymake') # optional - jupymake sage: P1 = loads(dumps(P)) # optional - jupymake sage: P._test_polymake_pickling(other=P1) # optional - jupymake - sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) - sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - jupymake # optional - sage.rings.number_field + sage: # optional - jupymake, needs sage.rings.number_field + sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') Possible output... - sage: P1 = loads(dumps(P)) # optional - jupymake # optional - sage.rings.number_field - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake # optional - sage.rings.number_field - sage: P._test_polymake_pickling(other=P2) # optional - jupymake # optional - sage.rings.number_field + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) """ if "_pickle_vertices" in state[1]: vertices = state[1].pop("_pickle_vertices") diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index ff5be490df5..ec26e49075c 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -124,8 +124,8 @@ class Polyhedron_base(Polyhedron_base7): :: - sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)) # optional - sage.graphs - sage: TestSuite(p).run() # optional - sage.graphs + sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)) # needs sage.combinat sage.graphs + sage: TestSuite(p).run() :: @@ -136,13 +136,13 @@ class Polyhedron_base(Polyhedron_base7): :: sage: P3 = polytopes.permutahedron(3) - sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1], [1,2,3]]) # optional - sage.combinat - sage: TestSuite(P).run() # optional - sage.combinat + sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1], [1,2,3]]) + sage: TestSuite(P).run() :: - sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1]], lines=[[1,0,0]]) # optional - sage.combinat - sage: TestSuite(P).run() # optional - sage.combinat + sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1]], lines=[[1,0,0]]) + sage: TestSuite(P).run() :: @@ -234,44 +234,46 @@ def to_linear_program(self, solver=None, return_variable=False, base_ring=None): Irrational algebraic linear program over an embedded number field:: - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: lp, x = p.to_linear_program(return_variable=True) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: p = polytopes.icosahedron() + sage: lp, x = p.to_linear_program(return_variable=True) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() 1/4*sqrt5 + 3/4 Same example with floating point:: - sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # tol 1e-5 # optional - sage.rings.number_field + sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # tol 1e-5 # needs sage.rings.number_field 1.3090169943749475 Same example with a specific floating point solver:: - sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK') # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # tol 1e-8 # optional - sage.rings.number_field + sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK') + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # tol 1e-8 # needs sage.rings.number_field 1.3090169943749475 Irrational algebraic linear program over `AA`:: - sage: p = polytopes.icosahedron(base_ring=AA) # optional - sage.rings.number_field - sage: lp, x = p.to_linear_program(return_variable=True) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # long time # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: p = polytopes.icosahedron(base_ring=AA) + sage: lp, x = p.to_linear_program(return_variable=True) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # long time 1.309016994374948? TESTS:: - sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)); p # optional - sage.graphs + sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)); p # needs sage.combinat sage.graphs A 19-dimensional polyhedron in QQ^27 defined as the convex hull of 1 vertex and 148 rays - sage: p.to_linear_program().polyhedron() == p # optional - sage.graphs + sage: p.to_linear_program().polyhedron() == p True - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: p.to_linear_program(solver='PPL') # optional - sage.rings.number_field + sage: p = polytopes.icosahedron() # needs sage.rings.number_field + sage: p.to_linear_program(solver='PPL') # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: The PPL backend only supports rational data. @@ -317,17 +319,18 @@ def boundary_complex(self): The boundary complex of the octahedron:: + sage: # needs sage.graphs sage: oc = polytopes.octahedron() - sage: sc_oc = oc.boundary_complex() # optional - sage.graphs - sage: fl_oc = oc.face_lattice() # optional - sage.combinat sage.graphs - sage: fl_sc = sc_oc.face_poset() # optional - sage.combinat sage.graphs - sage: [len(x) for x in fl_oc.level_sets()] # optional - sage.combinat sage.graphs + sage: sc_oc = oc.boundary_complex() + sage: fl_oc = oc.face_lattice() # needs sage.combinat + sage: fl_sc = sc_oc.face_poset() # needs sage.combinat + sage: [len(x) for x in fl_oc.level_sets()] # needs sage.combinat [1, 6, 12, 8, 1] - sage: [len(x) for x in fl_sc.level_sets()] # optional - sage.combinat sage.graphs + sage: [len(x) for x in fl_sc.level_sets()] # needs sage.combinat [6, 12, 8] - sage: sc_oc.euler_characteristic() # optional - sage.graphs + sage: sc_oc.euler_characteristic() 2 - sage: sc_oc.homology() # optional - sage.graphs + sage: sc_oc.homology() {0: 0, 1: 0, 2: Z} The polyhedron should be simplicial:: @@ -556,7 +559,7 @@ def is_inscribed(self, certificate=False): sage: V = P.Vrepresentation() sage: H = P.Hrepresentation() sage: parent = P.parent() - sage: for V1 in Permutations(V): # optional - sage.combinat + sage: for V1 in Permutations(V): ....: P1 = parent._element_constructor_( ....: [V1, [], []], [H, []], Vrep_minimal=True, Hrep_minimal=True) ....: assert P1.is_inscribed() @@ -624,7 +627,7 @@ def hyperplane_arrangement(self): EXAMPLES:: sage: p = polytopes.hypercube(2) - sage: p.hyperplane_arrangement() # optional - sage.combinat + sage: p.hyperplane_arrangement() Arrangement <-t0 + 1 | -t1 + 1 | t1 + 1 | t0 + 1> """ names = tuple('t' + str(i) for i in range(self.ambient_dim())) @@ -680,10 +683,10 @@ def normal_fan(self, direction='inner'): ... ValueError: the normal fan is only defined for full-dimensional polytopes - sage: R = Polyhedron(vertices=[[0, 0], # optional - sage.rings.number_field sage.symbolic + sage: R = Polyhedron(vertices=[[0, 0], # needs sage.rings.number_field sage.symbolic ....: [AA(sqrt(2)), 0], ....: [0, AA(sqrt(2))]]) - sage: R.normal_fan() # optional - sage.rings.number_field sage.symbolic + sage: R.normal_fan() # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... NotImplementedError: normal fan handles only polytopes over the rationals @@ -764,8 +767,8 @@ def face_fan(self): The polytope has to have rational coordinates:: - sage: S = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: S.face_fan() # optional - sage.rings.number_field + sage: S = polytopes.dodecahedron() # needs sage.rings.number_field + sage: S.face_fan() # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: face fan handles only polytopes over the rationals @@ -856,8 +859,8 @@ def barycentric_subdivision(self, subdivision_frac=None): sage: P.barycentric_subdivision() A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices - sage: P = polytopes.regular_polygon(4, base_ring=QQ) # optional - sage.rings.number_field - sage: P.barycentric_subdivision() # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(4, base_ring=QQ) # needs sage.rings.number_field + sage: P.barycentric_subdivision() # needs sage.rings.number_field A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8 vertices @@ -969,19 +972,20 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona `\pm 1` 2-dimensional square. The permutations are written in terms of the vertices of the square:: - sage: square = Polyhedron(vertices=[[1,1], [-1,1], # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.groups + sage: square = Polyhedron(vertices=[[1,1], [-1,1], ....: [-1,-1], [1,-1]], ....: backend='normaliz') - sage: square.vertices() # optional - pynormaliz + sage: square.vertices() (A vertex at (-1, -1), A vertex at (-1, 1), A vertex at (1, -1), A vertex at (1, 1)) - sage: aut_square = square.restricted_automorphism_group(output='permutation') # optional - pynormaliz sage.groups - sage: conj_reps = aut_square.conjugacy_classes_representatives() # optional - pynormaliz sage.groups - sage: gens_dict = square.permutations_to_matrices(conj_reps) # optional - pynormaliz sage.groups - sage: rotation_180 = aut_square([(0,3),(1,2)]) # optional - pynormaliz sage.groups - sage: rotation_180, gens_dict[rotation_180] # optional - pynormaliz sage.groups + sage: aut_square = square.restricted_automorphism_group(output='permutation') + sage: conj_reps = aut_square.conjugacy_classes_representatives() + sage: gens_dict = square.permutations_to_matrices(conj_reps) + sage: rotation_180 = aut_square([(0,3),(1,2)]) + sage: rotation_180, gens_dict[rotation_180] ( [-1 0 0] [ 0 -1 0] @@ -990,13 +994,14 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona This example tests the functionality for additional elements:: + sage: # needs sage.groups sage.rings.real_mpfr sage: C = polytopes.cross_polytope(2) - sage: G = C.restricted_automorphism_group(output='permutation') # optional - sage.groups sage.rings.real_mpfr - sage: conj_reps = G.conjugacy_classes_representatives() # optional - sage.groups sage.rings.real_mpfr - sage: add_elt = G([(0, 2, 3, 1)]) # optional - sage.groups sage.rings.real_mpfr - sage: dict = C.permutations_to_matrices(conj_reps, # optional - sage.groups sage.rings.real_mpfr + sage: G = C.restricted_automorphism_group(output='permutation') + sage: conj_reps = G.conjugacy_classes_representatives() + sage: add_elt = G([(0, 2, 3, 1)]) + sage: dict = C.permutations_to_matrices(conj_reps, ....: additional_elts=[add_elt]) - sage: dict[add_elt] # optional - sage.groups sage.rings.real_mpfr + sage: dict[add_elt] [ 0 1 0] [-1 0 0] [ 0 0 1] @@ -1063,7 +1068,7 @@ def bounding_box(self, integral=False, integral_hull=False): (None, None) sage: Polyhedron([(1/3,2/3), (3/3, 4/3)]).bounding_box(integral_hull=True) ((1, 1), (1, 1)) - sage: polytopes.buckyball(exact=False).bounding_box() # optional - sage.groups + sage: polytopes.buckyball(exact=False).bounding_box() # needs sage.groups ((-0.8090169944, -0.8090169944, -0.8090169944), (0.8090169944, 0.8090169944, 0.8090169944)) @@ -1143,38 +1148,39 @@ def _polymake_init_(self): Non-pointed polyhedron:: + sage: # optional - jupymake sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], lines=[[1, 0]]) - sage: PP = polymake(P) # optional - jupymake - sage: PP.VERTICES # optional - jupymake + sage: PP = polymake(P) + sage: PP.VERTICES 1 0 1 1 0 0 - sage: PP.FACETS # optional - jupymake + sage: PP.FACETS 1 0 -1 0 0 1 - sage: PP.LINEALITY_SPACE # optional - jupymake + sage: PP.LINEALITY_SPACE 0 1 0 Algebraic polyhedron:: - sage: P = polytopes.dodecahedron(); P # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(); P # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 20 vertices - sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake sage.rings.number_field + sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake, needs sage.rings.number_field Maybe recompile warning... Polytope>[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake sage.rings.number_field + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake, needs sage.rings.number_field 1 -1+1r5 -4+2r5 0 Floating-point polyhedron:: - sage: P = polytopes.dodecahedron(exact=False); P # optional - sage.groups + sage: P = polytopes.dodecahedron(exact=False); P # needs sage.groups A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 20 vertices - sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake sage.groups + sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake, needs sage.groups There may be a recompilation warning... Polytope[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake sage.groups + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake, needs sage.groups 1 -0.472135955 0 -1.236067978 """ diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 3f6f9d31f7a..556eefc5148 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -83,10 +83,10 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: from sage.geometry.polyhedron.parent import Polyhedra_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1/2], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # needs sage.rings.number_field ....: Vrep_minimal=False, Hrep_minimal=True) Traceback (most recent call last): ... @@ -406,13 +406,13 @@ def change_ring(self, base_ring, backend=None): ... TypeError: cannot change the base ring to the Integer Ring - sage: P = polytopes.regular_polygon(3); P # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(3); P # needs sage.rings.number_field A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field (A vertex at (0.?e-16, 1.000000000000000?), A vertex at (0.866025403784439?, -0.500000000000000?), A vertex at (-0.866025403784439?, -0.500000000000000?)) - sage: P.change_ring(QQ) # optional - sage.rings.number_field + sage: P.change_ring(QQ) # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: cannot change the base ring to the Rational Field @@ -425,11 +425,11 @@ def change_ring(self, base_ring, backend=None): base ring from an exact ring into ``RDF`` may cause a loss of data:: - sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # optional - sage.rings.number_field + sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # needs sage.rings.number_field A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: Q = P.change_ring(RDF); Q # optional - sage.rings.number_field + sage: Q = P.change_ring(RDF); Q # needs sage.rings.number_field A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: P.n_vertices() == Q.n_vertices() # optional - sage.rings.number_field + sage: P.n_vertices() == Q.n_vertices() # needs sage.rings.number_field False """ from sage.categories.rings import Rings @@ -577,8 +577,8 @@ def is_compact(self): EXAMPLES:: - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: p.is_compact() # optional - sage.rings.number_field + sage: p = polytopes.icosahedron() # needs sage.rings.number_field + sage: p.is_compact() # needs sage.rings.number_field True sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0],[0,0,0,1],[1,-1,0,0]]) sage: p.is_compact() @@ -890,11 +890,12 @@ def inequalities(self): An inequality (0, 1, 0) x + 0 >= 0, An inequality (0, 0, 1) x + 0 >= 0) - sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) # optional - sage.combinat - sage: ieqs = p3.inequalities() # optional - sage.combinat - sage: ieqs[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) + sage: ieqs = p3.inequalities() + sage: ieqs[0] An inequality (0, 1, 1, 1) x - 6 >= 0 - sage: list(_) # optional - sage.combinat + sage: list(_) [-6, 0, 1, 1, 1] """ return tuple(self.inequality_generator()) @@ -915,13 +916,14 @@ def inequalities_list(self): sage: p.inequalities_list()[0:3] [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] - sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) # optional - sage.combinat - sage: ieqs = p3.inequalities_list() # optional - sage.combinat - sage: ieqs[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) + sage: ieqs = p3.inequalities_list() + sage: ieqs[0] [-6, 0, 1, 1, 1] - sage: ieqs[-1] # optional - sage.combinat + sage: ieqs[-1] [-3, 0, 1, 0, 1] - sage: ieqs == [list(x) for x in p3.inequality_generator()] # optional - sage.combinat + sage: ieqs == [list(x) for x in p3.inequality_generator()] True """ return [list(x) for x in self.inequality_generator()] @@ -1317,8 +1319,8 @@ def backend(self): sage: triangle = Polyhedron(vertices = [[1, 0], [0, 1], [1, 1]]) sage: triangle.backend() 'ppl' - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: D.backend() # optional - sage.rings.number_field + sage: D = polytopes.dodecahedron() # needs sage.rings.number_field + sage: D.backend() # needs sage.rings.number_field 'field' sage: P = Polyhedron([[1.23]]) sage: P.backend() @@ -1352,10 +1354,10 @@ def cdd_Hrepresentation(self): end - sage: triangle = Polyhedron(vertices=[[1,0], [0,1], [1,1]], base_ring=AA) # optional - sage.rings.number_field - sage: triangle.base_ring() # optional - sage.rings.number_field + sage: triangle = Polyhedron(vertices=[[1,0], [0,1], [1,1]], base_ring=AA) # needs sage.rings.number_field + sage: triangle.base_ring() # needs sage.rings.number_field Algebraic Real Field - sage: triangle.cdd_Hrepresentation() # optional - sage.rings.number_field + sage: triangle.cdd_Hrepresentation() # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: the base ring must be ZZ, QQ, or RDF diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 9236996fb0a..77b7bf4427e 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -95,14 +95,15 @@ def __hash__(self): r""" TESTS:: - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(0, 1, a), (3, a, 5)], # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(2) + sage: p = Polyhedron(vertices=[(0, 1, a), (3, a, 5)], ....: rays=[(a, 2, 3), (0, 0, 1)], ....: base_ring=K) - sage: q = Polyhedron(vertices=[(3, a, 5), (0, 1, a)], # optional - sage.rings.number_field + sage: q = Polyhedron(vertices=[(3, a, 5), (0, 1, a)], ....: rays=[(0, 0, 1), (a, 2, 3)], ....: base_ring=K) - sage: hash(p) == hash(q) # optional - sage.rings.number_field + sage: hash(p) == hash(q) True """ # TODO: find something better *but* fast @@ -401,11 +402,11 @@ def ambient_vector_space(self, base_field=None): sage: poly_test.ambient_vector_space() is poly_test.ambient() True - sage: poly_test.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: poly_test.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 4 over Algebraic Real Field sage: poly_test.ambient_vector_space(RDF) Vector space of dimension 4 over Real Double Field - sage: poly_test.ambient_vector_space(SR) # optional - sage.symbolic + sage: poly_test.ambient_vector_space(SR) # needs sage.symbolic Vector space of dimension 4 over Symbolic Ring """ return self.Vrepresentation_space().vector_space(base_field=base_field) @@ -620,14 +621,15 @@ def contains(self, point): The point need not have coordinates in the same field as the polyhedron:: + sage: # needs sage.symbolic sage: ray = Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) - sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok # optional - sage.symbolic + sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok True - sage: a = var('a') # optional - sage.symbolic - sage: ray.contains([a,0]) # a might be negative! # optional - sage.symbolic + sage: a = var('a') + sage: ray.contains([a,0]) # a might be negative! False - sage: assume(a>0) # optional - sage.symbolic - sage: ray.contains([a,0]) # optional - sage.symbolic + sage: assume(a>0) + sage: ray.contains([a,0]) True sage: ray.contains(['hello', 'kitty']) # no common ring for coordinates False diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index 41ec3ad203d..0594d0c6708 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -95,7 +95,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field False """ if not self.is_compact(): @@ -145,7 +145,7 @@ def lattice_polytope(self, envelope=False): sage: P = Polyhedron(vertices=[(1, 0), (0, 1), (-1, 0), (0, -1)]) sage: lp = P.lattice_polytope(); lp 2-d reflexive polytope... in 2-d lattice M - sage: lp # optional - palp polytopes_db + sage: lp # optional - polytopes_db, needs palp 2-d reflexive polytope #3 in 2-d lattice M sage: lp.vertices() M(-1, 0), @@ -164,7 +164,7 @@ def lattice_polytope(self, envelope=False): to add the argument "envelope=True" to compute an enveloping lattice polytope. sage: lp = P.lattice_polytope(True) - sage: lp # optional - palp polytopes_db + sage: lp # optional - polytopes_db, needs palp 2-d reflexive polytope #5 in 2-d lattice M sage: lp.vertices() M(-1, 0), @@ -208,9 +208,9 @@ def _integral_points_PALP(self): EXAMPLES:: - sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])._integral_points_PALP() # optional - palp + sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp [M(-1, -1), M(0, 1), M(1, 0), M(1, 1), M(0, 0)] - sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)]).lattice_polytope(True).points() # optional - palp + sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)]).lattice_polytope(True).points() # needs palp M(-1, -1), M(-1, 0), M( 0, -1), @@ -219,7 +219,7 @@ def _integral_points_PALP(self): M( 1, 0), M( 0, 0) in 2-d lattice M - sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)])._integral_points_PALP() # optional - palp + sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp [M(1, 1), M(0, 1), M(1, 0), M(0, 0)] """ if not self.is_compact(): @@ -263,10 +263,11 @@ def h_star_vector(self): volume = `\frac{1}{dim(S)!}`) is always 1. Here we test this on simplices up to dimension 3:: - sage: s1 = polytopes.simplex(1,backend='normaliz') # optional - pynormaliz - sage: s2 = polytopes.simplex(2,backend='normaliz') # optional - pynormaliz - sage: s3 = polytopes.simplex(3,backend='normaliz') # optional - pynormaliz - sage: [s1.h_star_vector(), s2.h_star_vector(), s3.h_star_vector()] # optional - pynormaliz + sage: # optional - pynormaliz + sage: s1 = polytopes.simplex(1,backend='normaliz') + sage: s2 = polytopes.simplex(2,backend='normaliz') + sage: s3 = polytopes.simplex(3,backend='normaliz') + sage: [s1.h_star_vector(), s2.h_star_vector(), s3.h_star_vector()] [[1], [1], [1]] For a less trivial example, we compute the `h^*`-vector of the @@ -276,8 +277,8 @@ def h_star_vector(self): sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz sage: cube.h_star_vector() # optional - pynormaliz [1, 4, 1] - sage: from sage.combinat.combinat import eulerian_number # optional - sage.combinat - sage: [eulerian_number(3,i) for i in range(3)] # optional - sage.combinat + sage: from sage.combinat.combinat import eulerian_number + sage: [eulerian_number(3,i) for i in range(3)] [1, 4, 1] TESTS:: @@ -294,8 +295,8 @@ def h_star_vector(self): ... TypeError: The h_star vector is only defined for lattice polytopes - sage: t2 = Polyhedron(vertices=[[AA(sqrt(2))], [1/2]]) # optional - sage.rings.number_field - sage: t2.h_star_vector() # optional - sage.rings.number_field + sage: t2 = Polyhedron(vertices=[[AA(sqrt(2))], [1/2]]) # needs sage.rings.number_field sage.symbolic + sage: t2.h_star_vector() # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... TypeError: The h_star vector is only defined for lattice polytopes @@ -446,9 +447,9 @@ def integral_points(self, threshold=100000): sage: pts1 = P.integral_points() # Sage's own code sage: all(P.contains(p) for p in pts1) True - sage: pts2 = LatticePolytope(v).points() # optional - palp + sage: pts2 = LatticePolytope(v).points() # needs palp sage: for p in pts1: p.set_immutable() - sage: set(pts1) == set(pts2) # optional - palp + sage: set(pts1) == set(pts2) # needs palp True sage: timeit('Polyhedron(v).integral_points()') # not tested - random @@ -642,13 +643,15 @@ def random_integral_point(self, **kwds): EXAMPLES:: sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]) - sage: P.random_integral_point() # random + sage: P.random_integral_point() # random (0, 0) sage: P.random_integral_point() in P.integral_points() True - sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib') # random, optional - latte_int + sage: P.random_integral_point(explicit_enumeration_threshold=0, # random, optional - latte_int + ....: triangulation='cddlib') (1, 1) - sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib', foo=7) # optional - latte_int + sage: P.random_integral_point(explicit_enumeration_threshold=0, # optional - latte_int + ....: triangulation='cddlib', foo=7) Traceback (most recent call last): ... RuntimeError: ... @@ -765,36 +768,37 @@ def generating_function_of_integral_points(self, **kwds): EXAMPLES:: - sage: P2 = ( - ....: Polyhedron(ieqs=[(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, -1)]), - ....: Polyhedron(ieqs=[(0, -1, 0, 1), (0, 1, 0, 0), (0, 0, 1, 0)])) - sage: P2[0].generating_function_of_integral_points(sort_factors=True) # optional - sage.combinat + sage: # needs sage.combinat + sage: P2 = (Polyhedron(ieqs=[(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, -1)]), + ....: Polyhedron(ieqs=[(0, -1, 0, 1), (0, 1, 0, 0), (0, 0, 1, 0)])) + sage: P2[0].generating_function_of_integral_points(sort_factors=True) 1 * (-y0 + 1)^-1 * (-y1 + 1)^-1 * (-y0*y2 + 1)^-1 - sage: P2[1].generating_function_of_integral_points(sort_factors=True) # optional - sage.combinat + sage: P2[1].generating_function_of_integral_points(sort_factors=True) 1 * (-y1 + 1)^-1 * (-y2 + 1)^-1 * (-y0*y2 + 1)^-1 sage: (P2[0] & P2[1]).Hrepresentation() (An equation (1, 0, -1) x + 0 == 0, An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) - sage: (P2[0] & P2[1]).generating_function_of_integral_points(sort_factors=True) # optional - sage.combinat + sage: (P2[0] & P2[1]).generating_function_of_integral_points(sort_factors=True) 1 * (-y1 + 1)^-1 * (-y0*y2 + 1)^-1 The number of integer partitions `1 \leq r_0 \leq r_1 \leq r_2 \leq r_3 \leq r_4`:: + sage: # needs sage.combinat sage: P = Polyhedron(ieqs=[(-1, 1, 0, 0, 0, 0), (0, -1, 1, 0, 0, 0), ....: (0, 0, -1, 1, 0, 0), (0, 0, 0, -1, 1, 0), ....: (0, 0, 0, 0, -1, 1)]) - sage: f = P.generating_function_of_integral_points(sort_factors=True); f # optional - sage.combinat + sage: f = P.generating_function_of_integral_points(sort_factors=True); f y0*y1*y2*y3*y4 * (-y4 + 1)^-1 * (-y3*y4 + 1)^-1 * (-y2*y3*y4 + 1)^-1 * (-y1*y2*y3*y4 + 1)^-1 * (-y0*y1*y2*y3*y4 + 1)^-1 - sage: f = f.value() # optional - sage.combinat - sage: P. = PowerSeriesRing(ZZ) # optional - sage.combinat - sage: c = f.subs({y: z for y in f.parent().gens()}); c # optional - sage.combinat + sage: f = f.value() + sage: P. = PowerSeriesRing(ZZ) + sage: c = f.subs({y: z for y in f.parent().gens()}); c z^5 + z^6 + 2*z^7 + 3*z^8 + 5*z^9 + 7*z^10 + 10*z^11 + 13*z^12 + 18*z^13 + 23*z^14 + 30*z^15 + 37*z^16 + 47*z^17 + 57*z^18 + 70*z^19 + 84*z^20 + 101*z^21 + 119*z^22 + 141*z^23 + 164*z^24 + O(z^25) - sage: ([Partitions(k, length=5).cardinality() for k in range(5,20)] == # optional - sage.combinat + sage: ([Partitions(k, length=5).cardinality() for k in range(5,20)] == ....: c.truncate().coefficients(sparse=False)[5:20]) True diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 807714afde3..8904d9fac82 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -135,8 +135,9 @@ def slack_matrix(self): [1 0 1 0 0 1] [1 0 0 0 1 1] - sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: P.slack_matrix() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: P.slack_matrix() [1/2*sqrt5 - 1/2 0 0 1 1/2*sqrt5 - 1/2 0] [ 0 0 1/2*sqrt5 - 1/2 1/2*sqrt5 - 1/2 1 0] [ 0 1/2*sqrt5 - 1/2 1 0 1/2*sqrt5 - 1/2 0] @@ -153,7 +154,7 @@ def slack_matrix(self): sage: Polyhedron().slack_matrix() [] - sage: Polyhedron(base_ring=QuadraticField(2)).slack_matrix().base_ring() # optional - sage.rings.number_field + sage: Polyhedron(base_ring=QuadraticField(2)).slack_matrix().base_ring() # needs sage.rings.number_field Number Field in a with defining polynomial x^2 - 2 with a = 1.41... """ if not self.n_Vrepresentation() or not self.n_Hrepresentation(): @@ -274,7 +275,7 @@ def incidence_matrix(self): sage: P = polytopes.twenty_four_cell() sage: M = P.incidence_matrix() - sage: sum(sum(x) for x in M) == P.flag_f_vector(0, 3) # optional - sage.combinat + sage: sum(sum(x) for x in M) == P.flag_f_vector(0, 3) # needs sage.combinat True TESTS: @@ -287,10 +288,11 @@ def incidence_matrix(self): Test that this method works for inexact base ring (``cdd`` sets the cache already):: - sage: P = polytopes.dodecahedron(exact=False) # optional - sage.groups - sage: M = P.incidence_matrix.cache # optional - sage.groups - sage: P.incidence_matrix.clear_cache() # optional - sage.groups - sage: M == P.incidence_matrix() # optional - sage.groups + sage: # needs sage.groups + sage: P = polytopes.dodecahedron(exact=False) + sage: M = P.incidence_matrix.cache + sage: P.incidence_matrix.clear_cache() + sage: M == P.incidence_matrix() True """ if self.base_ring() in (ZZ, QQ): @@ -1008,8 +1010,8 @@ def vertex_adjacency_matrix(self, algorithm=None): sage: M = Q.vertex_adjacency_matrix() sage: sum(M) (4, 4, 3, 3, 4, 4, 4, 3, 3) - sage: G = Q.vertex_graph() # optional - sage.graphs - sage: G.degree() # optional - sage.graphs + sage: G = Q.vertex_graph() # needs sage.graphs + sage: G.degree() # needs sage.graphs [4, 4, 3, 3, 4, 4, 4, 3, 3] TESTS: @@ -1154,11 +1156,11 @@ def simplicity(self): EXAMPLES:: - sage: polytopes.hypersimplex(4,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(4,2).simplicity() 1 - sage: polytopes.hypersimplex(5,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(5,2).simplicity() 2 - sage: polytopes.hypersimplex(6,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(6,2).simplicity() 3 sage: polytopes.simplex(3).simplicity() 3 @@ -1207,7 +1209,7 @@ def simpliciality(self): sage: polytopes.cyclic_polytope(10,4).simpliciality() 3 - sage: polytopes.hypersimplex(5,2).simpliciality() # optional - sage.combinat + sage: polytopes.hypersimplex(5,2).simpliciality() 2 sage: polytopes.cross_polytope(4).simpliciality() 3 @@ -1293,8 +1295,8 @@ def is_pyramid(self, certificate=False): True sage: P.is_pyramid(certificate=True) (True, A vertex at (1, 0, 0, 0)) - sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: egyptian_pyramid.is_pyramid() # optional - sage.rings.number_field + sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.rings.number_field + sage: egyptian_pyramid.is_pyramid() # needs sage.rings.number_field True sage: Q = polytopes.octahedron() sage: Q.is_pyramid() @@ -1463,13 +1465,13 @@ def is_lawrence_polytope(self): EXAMPLES:: - sage: P = polytopes.hypersimplex(5,2) # optional - sage.combinat - sage: L = P.lawrence_polytope() # optional - sage.combinat - sage: L.is_lattice_polytope() # optional - sage.combinat + sage: P = polytopes.hypersimplex(5,2) + sage: L = P.lawrence_polytope() + sage: L.is_lattice_polytope() True - sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # optional - sage.number_field - sage: egyptian_pyramid.is_lawrence_polytope() # optional - sage.number_field + sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.number_field + sage: egyptian_pyramid.is_lawrence_polytope() # needs sage.number_field True sage: polytopes.octahedron().is_lawrence_polytope() diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index ae092615ac5..5313d64b357 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -95,7 +95,7 @@ def vertex_facet_graph(self, labels=True): sage: P = polytopes.cube() sage: G = P.vertex_facet_graph(); G Digraph on 14 vertices - sage: G.vertices(key = lambda v: str(v)) + sage: G.vertices(sort=True, key=lambda v: str(v)) [A vertex at (-1, -1, -1), A vertex at (-1, -1, 1), A vertex at (-1, 1, -1), diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index 906334eda3d..89feb2d7b0f 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -324,7 +324,7 @@ def _test_pyramid(self, tester=None, **options): TESTS: - sage: polytopes.regular_polygon(4)._test_pyramid() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(4)._test_pyramid() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -1057,7 +1057,7 @@ def join(self, other): sage: C = polytopes.hypercube(5) sage: S = Polyhedron([[1]]) - sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) # optional - sage.graphs + sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) # needs sage.graphs True sage: P = polytopes.simplex(backend='cdd') @@ -1355,10 +1355,11 @@ def intersection(self, other): Check that :trac:`19012` is fixed:: - sage: K. = QuadraticField(5) # optional - sage.rings.number_field - sage: P = Polyhedron([[0, 0], [0, a], [1, 1]]) # optional - sage.rings.number_field - sage: Q = Polyhedron(ieqs=[[-1, a, 1]]) # optional - sage.rings.number_field - sage: P.intersection(Q) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(5) + sage: P = Polyhedron([[0, 0], [0, a], [1, 1]]) + sage: Q = Polyhedron(ieqs=[[-1, a, 1]]) + sage: P.intersection(Q) A 2-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^2 defined as the convex hull of 4 vertices @@ -1712,23 +1713,25 @@ def linear_transformation(self, linear_transf, new_base_ring=None): sage: b3_proj = proj_mat * b3; b3_proj A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: square = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: square.vertices_list() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: square = polytopes.regular_polygon(4) + sage: square.vertices_list() [[0, -1], [1, 0], [-1, 0], [0, 1]] - sage: transf = matrix([[1,1], [0,1]]) # optional - sage.rings.number_field - sage: sheared = transf * square # optional - sage.rings.number_field - sage: sheared.vertices_list() # optional - sage.rings.number_field + sage: transf = matrix([[1,1], [0,1]]) + sage: sheared = transf * square + sage: sheared.vertices_list() [[-1, -1], [1, 0], [-1, 0], [1, 1]] - sage: sheared == square.linear_transformation(transf) # optional - sage.rings.number_field + sage: sheared == square.linear_transformation(transf) True Specifying the new base ring may avoid coercion failure:: - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: L. = QuadraticField(3) # optional - sage.rings.number_field - sage: P = polytopes.cube()*sqrt2 # optional - sage.rings.number_field - sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) # optional - sage.rings.number_field - sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(2) + sage: L. = QuadraticField(3) + sage: P = polytopes.cube()*sqrt2 + sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) + sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) A 3-dimensional polyhedron in (Number Field in sqrt2sqrt3 with defining polynomial x^4 - 10*x^2 + 1 with sqrt2sqrt3 = 0.3178372451957823?)^3 @@ -1736,7 +1739,7 @@ def linear_transformation(self, linear_transf, new_base_ring=None): Linear transformation without specified new base ring fails in this case:: - sage: M*P # optional - sage.rings.number_field + sage: M*P # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: @@ -1760,7 +1763,7 @@ def linear_transformation(self, linear_transf, new_base_ring=None): A 3-dimensional polyhedron in RDF^4 defined as the convex hull of 5 vertices sage: (1/1 * proj_mat) * b3 A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices - sage: (AA(2).sqrt() * proj_mat) * b3 # optional - sage.rings.number_field + sage: (AA(2).sqrt() * proj_mat) * b3 # needs sage.rings.number_field A 3-dimensional polyhedron in AA^4 defined as the convex hull of 5 vertices Check that zero-matrices act correctly:: @@ -2014,7 +2017,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): A vertex at (-1/3, 1, 1), A vertex at (-1/3, 1, -1), A vertex at (-1/3, -1, -1)) - sage: face_trunc.face_lattice().is_isomorphic(Cube.face_lattice()) # optional - sage.combinat sage.graphs + sage: face_trunc.face_lattice().is_isomorphic(Cube.face_lattice()) # needs sage.combinat sage.graphs True TESTS: @@ -2113,15 +2116,16 @@ def stack(self, face, position=None): (1, 9, 16, 9, 1) sage: stacked_square_large = cube.stack(square_face, position=10) - sage: hexaprism = polytopes.regular_polygon(6).prism() # optional - sage.rings.number_field - sage: hexaprism.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: hexaprism = polytopes.regular_polygon(6).prism() + sage: hexaprism.f_vector() (1, 12, 18, 8, 1) - sage: square_face = hexaprism.faces(2)[2] # optional - sage.rings.number_field - sage: stacked_hexaprism = hexaprism.stack(square_face) # optional - sage.rings.number_field - sage: stacked_hexaprism.f_vector() # optional - sage.rings.number_field + sage: square_face = hexaprism.faces(2)[2] + sage: stacked_hexaprism = hexaprism.stack(square_face) + sage: stacked_hexaprism.f_vector() (1, 13, 22, 11, 1) - sage: hexaprism.stack(square_face, position=4) # optional - sage.rings.number_field + sage: hexaprism.stack(square_face, position=4) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the chosen position is too large @@ -2241,17 +2245,18 @@ def wedge(self, face, width=1): EXAMPLES:: - sage: P_4 = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P_4 = polytopes.regular_polygon(4) + sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 A 3-dimensional polyhedron in AA^3 defined as the convex hull of 6 vertices - sage: triangular_prism = polytopes.regular_polygon(3).prism() # optional - sage.rings.number_field - sage: W1.is_combinatorially_isomorphic(triangular_prism) # optional - sage.graphs sage.rings.number_field + sage: triangular_prism = polytopes.regular_polygon(3).prism() + sage: W1.is_combinatorially_isomorphic(triangular_prism) # needs sage.graphs True - sage: Q = polytopes.hypersimplex(4,2) # optional - sage.combinat - sage: W2 = Q.wedge(Q.faces(2)[7]); W2 # optional - sage.combinat + sage: Q = polytopes.hypersimplex(4,2) + sage: W2 = Q.wedge(Q.faces(2)[7]); W2 A 4-dimensional polyhedron in QQ^5 defined as the convex hull of 9 vertices - sage: W2.vertices() # optional - sage.combinat + sage: W2.vertices() (A vertex at (1, 1, 0, 0, 1), A vertex at (1, 1, 0, 0, -1), A vertex at (1, 0, 1, 0, 1), @@ -2262,9 +2267,9 @@ def wedge(self, face, width=1): A vertex at (0, 1, 1, 0, 0), A vertex at (0, 1, 0, 1, 0)) - sage: W3 = Q.wedge(Q.faces(1)[11]); W3 # optional - sage.combinat + sage: W3 = Q.wedge(Q.faces(1)[11]); W3 A 4-dimensional polyhedron in QQ^5 defined as the convex hull of 10 vertices - sage: W3.vertices() # optional - sage.combinat + sage: W3.vertices() (A vertex at (1, 1, 0, 0, -2), A vertex at (1, 1, 0, 0, 2), A vertex at (1, 0, 1, 0, -2), @@ -2277,9 +2282,9 @@ def wedge(self, face, width=1): A vertex at (0, 1, 1, 0, -1)) sage: C_3_7 = polytopes.cyclic_polytope(3,7) - sage: P_6 = polytopes.regular_polygon(6) # optional - sage.rings.number_field - sage: W4 = P_6.wedge(P_6.faces(1)[0]) # optional - sage.rings.number_field - sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) # optional - sage.graphs sage.rings.number_field + sage: P_6 = polytopes.regular_polygon(6) # needs sage.rings.number_field + sage: W4 = P_6.wedge(P_6.faces(1)[0]) # needs sage.rings.number_field + sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) # needs sage.graphs sage.rings.number_field True REFERENCES: @@ -2363,10 +2368,11 @@ def face_split(self, face): EXAMPLES:: - sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: f = pentagon.faces(1)[0] # optional - sage.rings.number_field - sage: fsplit_pentagon = pentagon.face_split(f) # optional - sage.rings.number_field - sage: fsplit_pentagon.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: pentagon = polytopes.regular_polygon(5) + sage: f = pentagon.faces(1)[0] + sage: fsplit_pentagon = pentagon.face_split(f) + sage: fsplit_pentagon.f_vector() (1, 7, 14, 9, 1) TESTS: @@ -2450,7 +2456,7 @@ def _test_lawrence(self, tester=None, **options): Check that :trac:`28725` is fixed:: - sage: polytopes.regular_polygon(3)._test_lawrence() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(3)._test_lawrence() # needs sage.rings.number_field Check that :trac:`30293` is fixed:: @@ -2559,10 +2565,11 @@ def one_point_suspension(self, vertex): sage: ops_cube.f_vector() (1, 9, 24, 24, 9, 1) - sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: v = pentagon.vertices()[0] # optional - sage.rings.number_field - sage: ops_pentagon = pentagon.one_point_suspension(v) # optional - sage.rings.number_field - sage: ops_pentagon.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: pentagon = polytopes.regular_polygon(5) + sage: v = pentagon.vertices()[0] + sage: ops_pentagon = pentagon.one_point_suspension(v) + sage: ops_pentagon.f_vector() (1, 6, 12, 8, 1) It works with a polyhedral face as well:: diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index e125b5228a0..b9d23daefa1 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -45,9 +45,9 @@ class Polyhedron_base6(Polyhedron_base5): sage: from sage.geometry.polyhedron.base6 import Polyhedron_base6 sage: P = polytopes.cube() - sage: Polyhedron_base6.plot(P) # optional - sage.plot + sage: Polyhedron_base6.plot(P) # needs sage.plot Graphics3d Object - sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) # optional - sage.plot + sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) # needs sage.plot \RequirePackage{luatex85} \documentclass[tikz]{standalone} \begin{document} @@ -130,7 +130,7 @@ class Polyhedron_base6(Polyhedron_base5): \end{document} sage: Q = polytopes.hypercube(4) - sage: Polyhedron_base6.show(Q) # optional - sage.plot + sage: Polyhedron_base6.show(Q) # needs sage.plot sage: Polyhedron_base6.schlegel_projection(Q) The projection of a polyhedron into 3 dimensions @@ -194,55 +194,59 @@ def plot(self, By default, the wireframe is rendered in blue and the fill in green:: - sage: square.plot() # optional - sage.plot + sage: # needs sage.plot + sage: square.plot() Graphics object consisting of 6 graphics primitives - sage: point.plot() # optional - sage.plot + sage: point.plot() Graphics object consisting of 1 graphics primitive - sage: line.plot() # optional - sage.plot + sage: line.plot() Graphics object consisting of 2 graphics primitives - sage: cube.plot() # optional - sage.plot + sage: cube.plot() Graphics3d Object - sage: hypercube.plot() # optional - sage.plot + sage: hypercube.plot() Graphics3d Object Draw the lines in red and nothing else:: - sage: square.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(point=False, line='red', polygon=False) Graphics object consisting of 4 graphics primitives - sage: point.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: point.plot(point=False, line='red', polygon=False) Graphics object consisting of 0 graphics primitives - sage: line.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: line.plot(point=False, line='red', polygon=False) Graphics object consisting of 1 graphics primitive - sage: cube.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: cube.plot(point=False, line='red', polygon=False) Graphics3d Object - sage: hypercube.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: hypercube.plot(point=False, line='red', polygon=False) Graphics3d Object Draw points in red, no lines, and a blue polygon:: - sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 2 graphics primitives - sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 1 graphics primitive - sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 1 graphics primitive - sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics3d Object - sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics3d Object If we instead use the ``fill`` and ``wireframe`` options, the coloring depends on the dimension of the object:: - sage: square.plot(fill='green', wireframe='red') # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(fill='green', wireframe='red') Graphics object consisting of 6 graphics primitives - sage: point.plot(fill='green', wireframe='red') # optional - sage.plot + sage: point.plot(fill='green', wireframe='red') Graphics object consisting of 1 graphics primitive - sage: line.plot(fill='green', wireframe='red') # optional - sage.plot + sage: line.plot(fill='green', wireframe='red') Graphics object consisting of 2 graphics primitives - sage: cube.plot(fill='green', wireframe='red') # optional - sage.plot + sage: cube.plot(fill='green', wireframe='red') Graphics3d Object - sage: hypercube.plot(fill='green', wireframe='red') # optional - sage.plot + sage: hypercube.plot(fill='green', wireframe='red') Graphics3d Object It is possible to draw polyhedra up to dimension 4, no matter what the @@ -251,32 +255,32 @@ def plot(self, sage: hcube = polytopes.hypercube(5) sage: facet = hcube.facets()[0].as_polyhedron(); facet A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices - sage: facet.plot() # optional - sage.plot + sage: facet.plot() # needs sage.plot Graphics3d Object For a 3d plot, we may draw the polygons with rainbow colors, using any of the following ways:: - sage: cube.plot(polygon='rainbow') # optional - sage.plot + sage: cube.plot(polygon='rainbow') # needs sage.plot Graphics3d Object - sage: cube.plot(polygon={'color':'rainbow'}) # optional - sage.plot + sage: cube.plot(polygon={'color':'rainbow'}) # needs sage.plot Graphics3d Object - sage: cube.plot(fill='rainbow') # optional - sage.plot + sage: cube.plot(fill='rainbow') # needs sage.plot Graphics3d Object For a 3d plot, the size of a point, the thickness of a line and the width of an arrow are controlled by the respective parameters:: sage: prism = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0]], rays=[[0,0,1]]) - sage: prism.plot(size=20, thickness=30, width=1) # optional - sage.plot + sage: prism.plot(size=20, thickness=30, width=1) # needs sage.plot Graphics3d Object - sage: prism.plot(point={'size':20, 'color':'black'}, # optional - sage.plot + sage: prism.plot(point={'size':20, 'color':'black'}, # needs sage.plot ....: line={'thickness':30, 'width':1, 'color':'black'}, ....: polygon='rainbow') Graphics3d Object TESTS:: - sage: for p in square.plot(): # optional - sage.plot + sage: for p in square.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 4 point(s) blue Line defined by 2 points @@ -285,18 +289,18 @@ def plot(self, blue Line defined by 2 points green Polygon defined by 4 points - sage: for p in line.plot(): # optional - sage.plot + sage: for p in line.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 2 point(s) green Line defined by 2 points - sage: for p in point.plot(): # optional - sage.plot + sage: for p in point.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) green Point set defined by 1 point(s) Draw the lines in red and nothing else:: - sage: for p in square.plot(point=False, line='red', polygon=False): # optional - sage.plot + sage: for p in square.plot(point=False, line='red', polygon=False): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points red Line defined by 2 points @@ -305,66 +309,68 @@ def plot(self, Draw vertices in red, no lines, and a blue polygon:: - sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 4 point(s) (0, 0, 1) Polygon defined by 4 points - sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 2 point(s) - sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) Draw in red without wireframe:: - sage: for p in square.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in square.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Polygon defined by 4 points - sage: for p in line.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in line.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points - sage: for p in point.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in point.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) We try to draw the polytope in 2 or 3 dimensions:: - sage: type(Polyhedron(ieqs=[(1,)]).plot()) # optional - sage.plot + sage: # needs sage.plot + sage: type(Polyhedron(ieqs=[(1,)]).plot()) - sage: type(polytopes.hypercube(1).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(1).plot()) - sage: type(polytopes.hypercube(2).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(2).plot()) - sage: type(polytopes.hypercube(3).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(3).plot()) In 4d a projection to 3d is used:: - sage: type(polytopes.hypercube(4).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(4).plot()) # needs sage.plot - sage: type(polytopes.hypercube(5).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(5).plot()) Traceback (most recent call last): ... NotImplementedError: plotting of 5-dimensional polyhedra not implemented If the polyhedron is not full-dimensional, the :meth:`affine_hull_projection` is used if necessary:: - sage: type(Polyhedron([(0,), (1,)]).plot()) # optional - sage.plot + sage: # needs sage.plot + sage: type(Polyhedron([(0,), (1,)]).plot()) - sage: type(Polyhedron([(0,0), (1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0), (1,1)]).plot()) - sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) - sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) TESTS: @@ -382,28 +388,29 @@ def plot(self, Check that :trac:`31802` is fixed:: + sage: # needs sage.plot sage: halfspace = Polyhedron(rays=[(0, 0, 1)], lines=[(1, 0, 0), (0, 1, 0)]) sage: len(halfspace.projection().arrows) 5 - sage: halfspace.plot(fill=(0, 1, 0)) # optional - sage.plot + sage: halfspace.plot(fill=(0, 1, 0)) Graphics3d Object sage: fullspace = Polyhedron(lines=[(1, 0, 0), (0, 1, 0), (0, 0, 1)]) sage: len(fullspace.projection().arrows) 6 - sage: fullspace.plot(color=(1, 0, 0), alpha=0.5) # optional - sage.plot + sage: fullspace.plot(color=(1, 0, 0), alpha=0.5) Graphics3d Object sage: cone = Polyhedron(rays=[(1, 0, 0), (0, 1, 0), (0, 0, 1)]) - sage: cone.plot(fill='rainbow', alpha=0.6) # optional - sage.plot + sage: cone.plot(fill='rainbow', alpha=0.6) Graphics3d Object sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0)], rays=[(-1, 1, 0), (1, 1, 0), (0, 0, 1)]) - sage: p.plot(fill='mediumspringgreen', point='red', size=30, width=2) # optional - sage.plot + sage: p.plot(fill='mediumspringgreen', point='red', size=30, width=2) Graphics3d Object sage: cylinder = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)]) - sage: cylinder.plot(fill='red') # check it is not all black # optional - sage.plot + sage: cylinder.plot(fill='red') # check it is not all black # needs sage.plot Graphics3d Object sage: quarter = Polyhedron(rays=[(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) - sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors # optional - sage.plot + sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors # needs sage.plot Graphics3d Object """ def merge_options(*opts): @@ -472,7 +479,7 @@ def show(self, **kwds): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: square.show(point='red') # optional - sage.plot + sage: square.show(point='red') # needs sage.plot """ self.plot(**kwds).show() @@ -546,9 +553,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: + sage: # needs sage.plot sage: co = polytopes.cuboctahedron() - sage: Img = co.tikz([0, 0, 1], 0, output_type='TikzPicture') # optional - sage.plot - sage: Img # optional - sage.plot + sage: Img = co.tikz([0, 0, 1], 0, output_type='TikzPicture') + sage: Img \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -565,7 +573,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: print('\n'.join(Img.content().splitlines()[12:21])) # optional - sage.plot + sage: print('\n'.join(Img.content().splitlines()[12:21])) %% with the command: ._tikz_3d_in_3d and parameters: %% view = [0, 0, 1] %% angle = 0 @@ -575,7 +583,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% opacity = 0.8 %% vertex_color = green %% axis = False - sage: print('\n'.join(Img.content().splitlines()[22:26])) # optional - sage.plot + sage: print('\n'.join(Img.content().splitlines()[22:26])) %% Coordinate of the vertices: %% \coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000); @@ -583,9 +591,9 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, When output type is a :class:`sage.misc.latex_standalone.TikzPicture`:: + sage: # needs sage.plot sage: co = polytopes.cuboctahedron() - sage: t = co.tikz([674, 108, -731], 112, output_type='TikzPicture') # optional - sage.plot - sage: t # optional - sage.plot + sage: t = co.tikz([674, 108, -731], 112, output_type='TikzPicture'); t \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -602,7 +610,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: path_to_file = t.pdf() # not tested # optional - sage.plot + sage: path_to_file = t.pdf() # not tested """ return self.projection().tikz(view, angle, scale, @@ -694,8 +702,8 @@ def gale_transform(self): Check that :trac:`29073` is fixed:: - sage: P = polytopes.icosahedron(exact=False) # optional - sage.groups - sage: sum(P.gale_transform()).norm() < 1e-15 # optional - sage.groups + sage: P = polytopes.icosahedron(exact=False) # needs sage.groups + sage: sum(P.gale_transform()).norm() < 1e-15 # needs sage.groups True """ if not self.is_compact(): @@ -786,8 +794,8 @@ def render_solid(self, **kwds): EXAMPLES:: sage: p = polytopes.hypercube(3) - sage: p_solid = p.render_solid(opacity=.7) # optional - sage.plot - sage: type(p_solid) # optional - sage.plot + sage: p_solid = p.render_solid(opacity=.7) # needs sage.plot + sage: type(p_solid) # needs sage.plot """ proj = self.projection() @@ -805,8 +813,8 @@ def render_wireframe(self, **kwds): EXAMPLES:: sage: p = Polyhedron([[1,2,],[1,1],[0,0]]) - sage: p_wireframe = p.render_wireframe() # optional - sage.plot - sage: p_wireframe._objects # optional - sage.plot + sage: p_wireframe = p.render_wireframe() # needs sage.plot + sage: p_wireframe._objects # needs sage.plot [Line defined by 2 points, Line defined by 2 points, Line defined by 2 points] """ proj = self.projection() @@ -855,24 +863,25 @@ def schlegel_projection(self, facet=None, position=None): sage: tfcube.facets()[-1] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1]) - sage: sp.plot() # optional - sage.plot + sage: sp.plot() # needs sage.plot Graphics3d Object The same truncated cube but see inside the tetrahedral facet:: sage: tfcube.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) # optional - sage.symbolic - sage: sp.plot() # optional - sage.plot sage.symbolic + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) # needs sage.symbolic + sage: sp.plot() # needs sage.plot sage.symbolic Graphics3d Object A different values of ``position`` changes the projection:: - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 1/2) # optional - sage.symbolic - sage: sp.plot() # optional - sage.plot sage.symbolic + sage: # needs sage.symbolic + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 1/2) + sage: sp.plot() # needs sage.plot Graphics3d Object - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 4) # optional - sage.symbolic - sage: sp.plot() # optional - sage.plot sage.symbolic + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 4) + sage: sp.plot() # needs sage.plot Graphics3d Object A value which is too large give a projection point that sees more than @@ -941,7 +950,7 @@ def _affine_hull_projection(self, *, sage: P1 = Polyhedron(vertices=[[-1, 1], [0, -1], [0, 0], [-1, -1]]) sage: P2 = Polyhedron(vertices=[[1, 1], [1, -1], [0, -1], [0, 0]]) sage: P = P1.intersection(P2) - sage: A, b = P.affine_hull_projection(as_affine_map=True, # optional - sage.rings.number_field + sage: A, b = P.affine_hull_projection(as_affine_map=True, ....: orthonormal=True, extend=True) sage: Polyhedron([(2,3,4)]).affine_hull_projection() @@ -953,7 +962,7 @@ def _affine_hull_projection(self, *, 'field' sage: P = Polyhedron(vertices=[[0,0], [1,0]], backend='field') - sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, # optional - sage.rings.number_field + sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, ....: extend=True).backend() 'field' @@ -968,11 +977,11 @@ def _affine_hull_projection(self, *, sage: P = Polyhedron(V) sage: P.affine_hull_projection() A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices - sage: P.affine_hull_projection(orthonormal=True) # optional - sage.symbolic + sage: P.affine_hull_projection(orthonormal=True) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: P.affine_hull_projection(orthonormal=True, extend=True) # needs sage.rings.number_field A 4-dimensional polyhedron in AA^4 defined as the convex hull of 6 vertices """ result = AffineHullProjectionData() @@ -1188,13 +1197,13 @@ def affine_hull_projection(self, A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices sage: A.vertices() (A vertex at (0), A vertex at (2)) - sage: A = L.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field + sage: A = L.affine_hull_projection(orthonormal=True) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() # needs sage.rings.number_field (A vertex at (1.414213562373095?), A vertex at (0.?e-18)) More generally:: @@ -1220,9 +1229,9 @@ def affine_hull_projection(self, A vertex at (2, 0, 0), A vertex at (1, 3/2, 0), A vertex at (1, 1/2, 4/3)) - sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() # needs sage.rings.number_field (A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?), A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18), A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18), @@ -1230,103 +1239,108 @@ def affine_hull_projection(self, With the parameter ``minimal`` one can get a minimal base ring:: + sage: # needs sage.rings.number_field sage: s = polytopes.simplex(3) - sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field - sage: s_AA.base_ring() # optional - sage.rings.number_field + sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) + sage: s_AA.base_ring() Algebraic Real Field - sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, # optional - sage.rings.number_field + sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, ....: minimal=True) - sage: s_full.base_ring() # optional - sage.rings.number_field + sage: s_full.base_ring() Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = 0.5176380902050415? More examples with the ``orthonormal`` parameter:: - sage: P = polytopes.permutahedron(3); P # optional - sage.combinat sage.rings.number_field + sage: P = polytopes.permutahedron(3); P A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: set([F.as_polyhedron().affine_hull_projection( # optional - sage.combinat sage.rings.number_field + sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field ....: orthonormal=True, extend=True).volume() ....: for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))} True - sage: set([F.as_polyhedron().affine_hull_projection( # optional - sage.combinat sage.rings.number_field + sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field ....: orthonormal=True, extend=True).volume() ....: for F in P.affine_hull_projection( ....: orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))} True - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: F = D.faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: F.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: D = polytopes.dodecahedron() + sage: F = D.faces(2)[0].as_polyhedron() + sage: F.affine_hull_projection(orthogonal=True) A 2-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^2 defined as the convex hull of 5 vertices - sage: F.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: F.affine_hull_projection(orthonormal=True, extend=True) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(2) + sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() (A vertex at (0, 0), A vertex at (sqrt2, sqrt2)) - sage: A = P.affine_hull_projection(orthonormal=True); A # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True); A A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() (A vertex at (0), A vertex at (2)) - sage: K. = QuadraticField(3) # optional - sage.rings.number_field - sage: P = Polyhedron([2*[K.zero()], 2*[sqrt3]]); P # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(3) + sage: P = Polyhedron([2*[K.zero()], 2*[sqrt3]]); P A 1-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() (A vertex at (0, 0), A vertex at (sqrt3, sqrt3)) - sage: A = P.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True) Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() (A vertex at (0), A vertex at (2.449489742783178?)) - sage: sqrt(6).n() # optional - sage.rings.number_field + sage: sqrt(6).n() 2.44948974278318 The affine hull is combinatorially equivalent to the input:: - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) # needs sage.rings.number_field True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # needs sage.rings.number_field ....: orthogonal=True)) True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # needs sage.rings.number_field ....: orthonormal=True, extend=True)) True The ``orthonormal=True`` parameter preserves volumes; it provides an isometric copy of the polyhedron:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field - sage: _, c= P.is_inscribed(certificate=True) # optional - sage.rings.number_field - sage: c # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) + sage: _, c= P.is_inscribed(certificate=True) + sage: c (0.4721359549995794?, 0.6498393924658126?) - sage: circumradius = (c - vector(P.vertices()[0])).norm() # optional - sage.rings.number_field - sage: p = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: p.volume() # optional - sage.rings.number_field + sage: circumradius = (c - vector(P.vertices()[0])).norm() + sage: p = polytopes.regular_polygon(5) + sage: p.volume() 2.377641290737884? - sage: P.volume() # optional - sage.rings.number_field + sage: P.volume() 1.53406271079097? - sage: p.volume()*circumradius^2 # optional - sage.rings.number_field + sage: p.volume()*circumradius^2 1.534062710790965? - sage: P.volume() == p.volume()*circumradius^2 # optional - sage.rings.number_field + sage: P.volume() == p.volume()*circumradius^2 True One can also use ``orthogonal`` parameter to calculate volumes; @@ -1334,31 +1348,33 @@ def affine_hull_projection(self, by the square root of the determinant of the linear part of the affine transformation times its transpose:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, ....: extend=True) - sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field - sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, # optional - sage.rings.number_field + sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) + sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, ....: as_affine_map=True) - sage: Adet = (A.matrix().transpose()*A.matrix()).det() # optional - sage.rings.number_field - sage: Pnormal.volume() # optional - sage.rings.number_field + sage: Adet = (A.matrix().transpose()*A.matrix()).det() + sage: Pnormal.volume() 1.53406271079097? - sage: Pgonal.volume()/Adet.sqrt(extend=True) # optional - sage.rings.number_field + sage: Pgonal.volume()/Adet.sqrt(extend=True) -80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240) - sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) # optional - sage.rings.number_field + sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) 1.5340627107909646813 - sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) # optional - sage.rings.number_field + sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) True Another example with ``as_affine_map=True``:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat sage.rings.number_field - sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.combinat sage.rings.number_field - sage: A, b = P.affine_hull_projection(orthonormal=True, extend=True, # optional - sage.combinat sage.rings.number_field + sage: # needs sage.combinat sage.rings.number_field + sage: P = polytopes.permutahedron(4) + sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) + sage: A, b = P.affine_hull_projection(orthonormal=True, extend=True, ....: as_affine_map=True) - sage: Q.center() # optional - sage.combinat sage.rings.number_field + sage: Q.center() (0.7071067811865475?, 1.224744871391589?, 1.732050807568878?) - sage: A(P.center()) + b == Q.center() # optional - sage.combinat sage.rings.number_field + sage: A(P.center()) + b == Q.center() True For unbounded, non full-dimensional polyhedra, the ``orthogonal=True`` and ``orthonormal=True`` @@ -1506,8 +1522,8 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): TESTS:: - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: D.facets()[0].as_polyhedron()._test_affine_hull_projection() # optional - sage.rings.number_field + sage: D = polytopes.dodecahedron() # needs sage.rings.number_field + sage: D.facets()[0].as_polyhedron()._test_affine_hull_projection() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -1595,48 +1611,50 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien EXAMPLES:: + sage: # needs sage.symbolic sage: triangle = Polyhedron([(1, 0, 0), (0, 1, 0), (0, 0, 1)]); triangle A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: A = triangle.affine_hull_manifold(name='A'); A # optional - sage.symbolic + sage: A = triangle.affine_hull_manifold(name='A'); A 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 - sage: A.embedding().display() # optional - sage.symbolic + sage: A.embedding().display() A → E^3 (x0, x1) ↦ (x, y, z) = (t0 + x0, t0 + x1, t0 - x0 - x1 + 1) - sage: A.embedding().inverse().display() # optional - sage.symbolic + sage: A.embedding().inverse().display() E^3 → A (x, y, z) ↦ (x0, x1) = (x, y) - sage: A.adapted_chart() # optional - sage.symbolic + sage: A.adapted_chart() [Chart (E^3, (x0_E3, x1_E3, t0_E3))] - sage: A.normal().display() # optional - sage.symbolic + sage: A.normal().display() n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z - sage: A.induced_metric() # Need to call this before volume_form # optional - sage.symbolic + sage: A.induced_metric() # Need to call this before volume_form Riemannian metric gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 - sage: A.volume_form() # optional - sage.symbolic + sage: A.volume_form() 2-form eps_gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 Orthogonal version:: - sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A # optional - sage.symbolic + sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A # needs sage.symbolic 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 - sage: A.embedding().display() # optional - sage.symbolic + sage: A.embedding().display() # needs sage.symbolic A → E^3 (x0, x1) ↦ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1, t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1) - sage: A.embedding().inverse().display() # optional - sage.symbolic + sage: A.embedding().inverse().display() # needs sage.symbolic E^3 → A (x, y, z) ↦ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2) Arrangement of affine hull of facets:: - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: E3 = EuclideanSpace(3) # optional - sage.rings.number_field sage.symbolic - sage: submanifolds = [ # long time # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: D = polytopes.dodecahedron() + sage: E3 = EuclideanSpace(3) + sage: submanifolds = [ # long time ....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}', ....: orthogonal=True, ambient_space=E3) ....: for i, F in enumerate(D.facets())] - sage: sum(FM.plot({}, # not tested # long time # optional - sage.symbolic sage.plot sage.rings.number_field + sage: sum(FM.plot({}, # long time, not tested # needs sage.plot ....: srange(-2, 2, 0.1), srange(-2, 2, 0.1), ....: opacity=0.2) ....: for FM in submanifolds) + D.plot() @@ -1646,7 +1664,7 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien sage: cube = polytopes.cube(); cube A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices - sage: cube.affine_hull_manifold() # optional - sage.symbolic + sage: cube.affine_hull_manifold() # needs sage.symbolic Euclidean space E^3 """ diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index ce632e1655d..c1c06b90a28 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -43,16 +43,17 @@ class Polyhedron_base7(Polyhedron_base6): TESTS:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.base7 import Polyhedron_base7 - sage: P = polytopes.associahedron(['A', 3]) # optional - sage.combinat - sage: Polyhedron_base7.centroid(P) # optional - sage.combinat + sage: P = polytopes.associahedron(['A', 3]) + sage: Polyhedron_base7.centroid(P) (81/632, 36/79, 81/632) - sage: Polyhedron_base7.triangulate(P) # optional - sage.combinat + sage: Polyhedron_base7.triangulate(P) (<0,1,2,13>, <0,1,7,13>, <0,2,5,13>, <0,6,7,12>, <0,6,8,13>, <0,6,12,13>, <0,7,12,13>, <1,2,7,12>, <1,2,12,13>, <1,7,12,13>, <2,3,7,12>, <2,3,12,13>, <3,4,7,12>, <3,11,12,13>, <6,8,9,12>, <6,8,12,13>, <6,9,10,12>, <8,9,12,13>) - sage: Polyhedron_base7.volume(P, measure='induced') # optional - sage.combinat + sage: Polyhedron_base7.volume(P, measure='induced') 79/3 """ @cached_method(do_pickle=True) @@ -91,8 +92,8 @@ def centroid(self, engine='auto', **kwds): sage: P.centroid() (1/4, 0, 0) - sage: P = polytopes.associahedron(['A', 2]) # optional - sage.combinat - sage: P.centroid() # optional - sage.combinat + sage: P = polytopes.associahedron(['A', 2]) # needs sage.combinat + sage: P.centroid() # needs sage.combinat (2/21, 2/21) sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz @@ -258,15 +259,16 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s The normaliz engine can triangulate pointed cones:: - sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,1], # optional - pynormaliz + sage: # optional - pynormaliz + sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,1], ....: [0,1,1], [1,1,1]], ....: backend='normaliz') - sage: C1.triangulate(engine='normaliz') # optional - pynormaliz + sage: C1.triangulate(engine='normaliz') (<0,1,2>, <1,2,3>) - sage: C2 = Polyhedron(rays=[[1,0,1], [0,0,1], # optional - pynormaliz + sage: C2 = Polyhedron(rays=[[1,0,1], [0,0,1], ....: [0,1,1], [1,1,10/9]], ....: backend='normaliz') - sage: C2.triangulate(engine='normaliz') # optional - pynormaliz + sage: C2.triangulate(engine='normaliz') (<0,1,2>, <1,2,3>) They can also be affine cones:: @@ -389,13 +391,14 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): EXAMPLES:: - sage: polytopes.hypercube(3)._volume_latte() # optional - latte_int + sage: # optional - latte_int + sage: polytopes.hypercube(3)._volume_latte() 8 - sage: (polytopes.hypercube(3)*2)._volume_latte() # optional - latte_int + sage: (polytopes.hypercube(3)*2)._volume_latte() 64 - sage: polytopes.twenty_four_cell()._volume_latte() # optional - latte_int + sage: polytopes.twenty_four_cell()._volume_latte() 2 - sage: polytopes.cuboctahedron()._volume_latte() # optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte() 20/3 TESTS: @@ -514,13 +517,13 @@ def volume(self, measure='ambient', engine='auto', **kwds): If the base ring is exact, the answer is exact:: - sage: P5 = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: P5.volume() # optional - sage.rings.number_field + sage: P5 = polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: P5.volume() # needs sage.rings.number_field 2.377641290737884? - sage: polytopes.icosahedron().volume() # optional - sage.rings.number_field + sage: polytopes.icosahedron().volume() # needs sage.rings.number_field 5/12*sqrt5 + 5/4 - sage: numerical_approx(_) # abs tol 1e9 # optional - sage.rings.number_field + sage: numerical_approx(_) # abs tol 1e9 # needs sage.rings.number_field 2.18169499062491 When considering lower-dimensional polytopes, we can ask for the @@ -533,36 +536,38 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: P = Polyhedron([[0, 0], [1, 1]]) sage: P.volume() 0 - sage: P.volume(measure='induced') # optional - sage.rings.number_field + sage: P.volume(measure='induced') # needs sage.rings.number_field 1.414213562373095? sage: P.volume(measure='induced_rational') # optional - latte_int 1 - sage: S = polytopes.regular_polygon(6); S # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: S = polytopes.regular_polygon(6); S A 2-dimensional polyhedron in AA^2 defined as the convex hull of 6 vertices - sage: edge = S.faces(1)[4].as_polyhedron() # optional - sage.rings.number_field - sage: edge.vertices() # optional - sage.rings.number_field + sage: edge = S.faces(1)[4].as_polyhedron() + sage: edge.vertices() (A vertex at (0.866025403784439?, 1/2), A vertex at (0, 1)) - sage: edge.volume() # optional - sage.rings.number_field + sage: edge.volume() 0 - sage: edge.volume(measure='induced') # optional - sage.rings.number_field + sage: edge.volume(measure='induced') 1 - sage: P = Polyhedron(backend='normaliz', # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz', ....: vertices=[[1,0,0], [0,0,1], ....: [-1,1,1], [-1,2,0]]) - sage: P.volume() # optional - pynormaliz + sage: P.volume() 0 - sage: P.volume(measure='induced') # optional - pynormaliz sage.rings.number_field + sage: P.volume(measure='induced') # needs sage.rings.number_field 2.598076211353316? - sage: P.volume(measure='induced', engine='normaliz') # optional - pynormaliz + sage: P.volume(measure='induced', engine='normaliz') 2.598076211353316 - sage: P.volume(measure='induced_rational') # optional - pynormaliz latte_int + sage: P.volume(measure='induced_rational') # optional - latte_int 3/2 - sage: P.volume(measure='induced_rational', # optional - pynormaliz + sage: P.volume(measure='induced_rational', ....: engine='normaliz') 3/2 - sage: P.volume(measure='induced_lattice') # optional - pynormaliz + sage: P.volume(measure='induced_lattice') 3 The same polytope without normaliz backend:: @@ -571,35 +576,37 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: P.volume(measure='induced_lattice', engine='latte') # optional - latte_int 3 - sage: Dexact = polytopes.dodecahedron() # optional - sage.rings.number_field sage.groups + sage: # needs sage.groups sage.rings.number_field + sage: Dexact = polytopes.dodecahedron() sage: F0 = Dexact.faces(2)[0].as_polyhedron() - sage: v = F0.volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field sage.groups + sage: v = F0.volume(measure='induced', engine='internal'); v 1.53406271079097? sage: F4 = Dexact.faces(2)[4].as_polyhedron() - sage: v = F4.volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field sage.groups + sage: v = F4.volume(measure='induced', engine='internal'); v 1.53406271079097? - sage: RDF(v) # abs tol 1e-9 # optional - sage.rings.number_field sage.groups + sage: RDF(v) # abs tol 1e-9 1.53406271079044 - sage: Dinexact = polytopes.dodecahedron(exact=False) # optional - sage.groups + sage: # needs sage.groups + sage: Dinexact = polytopes.dodecahedron(exact=False) sage: F2 = Dinexact.faces(2)[2].as_polyhedron() - sage: w = F2.volume(measure='induced', engine='internal') # optional - sage.groups + sage: w = F2.volume(measure='induced', engine='internal') sage: RDF(w) # abs tol 1e-9 1.5340627082974878 - sage: all(polytopes.simplex(d).volume(measure='induced') # optional - sage.rings.number_field sage.symbolic + sage: all(polytopes.simplex(d).volume(measure='induced') # needs sage.rings.number_field sage.symbolic ....: == sqrt(d+1)/factorial(d) ....: for d in range(1,5)) True sage: I = Polyhedron([[-3, 0], [0, 9]]) - sage: I.volume(measure='induced') # optional - sage.rings.number_field + sage: I.volume(measure='induced') # needs sage.rings.number_field 9.48683298050514? sage: I.volume(measure='induced_rational') # optional - latte_int 3 sage: T = Polyhedron([[3, 0, 0], [0, 4, 0], [0, 0, 5]]) - sage: T.volume(measure='induced') # optional - sage.rings.number_field + sage: T.volume(measure='induced') # needs sage.rings.number_field 13.86542462386205? sage: T.volume(measure='induced_rational') # optional - latte_int 1/2 @@ -628,7 +635,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): 0 sage: P.volume(measure='induced_rational') # optional - pynormaliz +Infinity - sage: P.volume(measure='induced_rational',engine='latte') # optional - latte_int + sage: P.volume(measure='induced_rational',engine='latte') +Infinity The volume in `0`-dimensional space is taken by counting measure:: @@ -809,7 +816,7 @@ def integrate(self, function, measure='ambient', **kwds): sage: x, y = polygens(QQ, 'x, y') sage: P = Polyhedron(vertices=[[0,0], [1,1]]) - sage: P.integrate(x*y) # optional - latte_int + sage: P.integrate(x*y) 0 sage: ixy = P.integrate(x*y, measure='induced'); ixy # optional - latte_int 0.4714045207910317? @@ -825,21 +832,21 @@ def integrate(self, function, measure='ambient', **kwds): sage: R. = QQ[] sage: P = polytopes.simplex(2) - sage: V = AA(P.volume(measure='induced')) # optional - sage.rings.number_field - sage: V.radical_expression() # optional - sage.rings.number_field sage.symbolic + sage: V = AA(P.volume(measure='induced')) # needs sage.rings.number_field + sage: V.radical_expression() # needs sage.rings.number_field sage.symbolic 1/2*sqrt(3) - sage: P.integrate(R(1), measure='induced') == V # optional - latte_int sage.rings.number_field sage.symbolic + sage: P.integrate(R(1), measure='induced') == V # optional - latte_int, needs sage.rings.number_field sage.symbolic True Computing the mass center:: - sage: (P.integrate(x, measure='induced') # optional - latte_int sage.rings.number_field sage.symbolic + sage: (P.integrate(x, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic ....: / V).radical_expression() 1/3 - sage: (P.integrate(y, measure='induced') # optional - latte_int sage.rings.number_field sage.symbolic + sage: (P.integrate(y, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic ....: / V).radical_expression() 1/3 - sage: (P.integrate(z, measure='induced') # optional - latte_int sage.rings.number_field sage.symbolic + sage: (P.integrate(z, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic ....: / V).radical_expression() 1/3 @@ -854,8 +861,8 @@ def integrate(self, function, measure='ambient', **kwds): Testing a polytope with non-rational vertices:: - sage: P = polytopes.icosahedron() # optional - sage.rings.number_field - sage: P.integrate(x^2*y^2*z^2) # optional - latte_int sage.rings.number_field + sage: P = polytopes.icosahedron() # needs sage.rings.number_field + sage: P.integrate(x^2*y^2*z^2) # optional - latte_int, needs sage.rings.number_field Traceback (most recent call last): ... TypeError: the base ring must be ZZ, QQ, or RDF @@ -870,7 +877,7 @@ def integrate(self, function, measure='ambient', **kwds): Testing a polytope with floating point coordinates:: sage: P = Polyhedron(vertices=[[0, 0], [1, 0], [1.1, 1.1], [0, 1]]) - sage: P.integrate('[[1,[2,2]]]') # optional - latte_int + sage: P.integrate('[[1,[2,2]]]') Traceback (most recent call last): ... TypeError: LattE integrale cannot be applied over inexact rings diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 7aa1c568480..007f000eb56 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -132,7 +132,7 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, sage: Q = P*(8/9) sage: Q.integral_points_count() 1 - sage: Q.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int + sage: Q.integral_points_count(explicit_enumeration_threshold=0) 1 Unbounded polyhedra (with or without lattice points) are not supported:: @@ -150,12 +150,12 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, "Fibonacci" knapsacks (preprocessing helps a lot):: - sage: def fibonacci_knapsack(d, b, backend=None): # optional - sage.combinat + sage: def fibonacci_knapsack(d, b, backend=None): ....: lp = MixedIntegerLinearProgram(base_ring=QQ) ....: x = lp.new_variable(nonnegative=True) ....: lp.add_constraint(lp.sum(fibonacci(i+3)*x[i] for i in range(d)) <= b) ....: return lp.polyhedron(backend=backend) - sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False # optional - sage.combinat + sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False # needs sage.combinat 33 TESTS: @@ -163,10 +163,10 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, We check that :trac:`21491` is fixed:: sage: P = Polyhedron(ieqs=[], eqns=[[-10,0,1],[-10,1,0]]) - sage: P.integral_points_count() # optional - latte_int + sage: P.integral_points_count() 1 sage: P = Polyhedron(ieqs=[], eqns=[[-11,0,2],[-10,1,0]]) - sage: P.integral_points_count() # optional - latte_int + sage: P.integral_points_count() 0 """ if self.is_empty(): @@ -296,23 +296,24 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: poly(1) # optional - latte_int 6 - sage: len(simplex.integral_points()) # optional - latte_int + sage: len(simplex.integral_points()) 6 sage: poly(2) # optional - latte_int 36 - sage: len((2*simplex).integral_points()) # optional - latte_int + sage: len((2*simplex).integral_points()) 36 Now we find the same Ehrhart polynomial, this time using ``engine='normaliz'``. To use the Normaliz engine, the ``simplex`` must be defined with ``backend='normaliz'``:: - sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), # optional - pynormaliz + sage: # optional - pynormaliz + sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)], ....: backend='normaliz') - sage: simplex = simplex.change_ring(QQ) # optional - pynormaliz - sage: poly = simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz - sage: poly # optional - pynormaliz + sage: simplex = simplex.change_ring(QQ) + sage: poly = simplex.ehrhart_polynomial(engine='normaliz') + sage: poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 If the ``engine='normaliz'``, the backend should be ``'normaliz'``, otherwise @@ -321,7 +322,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)]) sage: simplex = simplex.change_ring(QQ) - sage: simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz' @@ -348,11 +349,12 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, The cache of the Ehrhart polynomial is being pickled:: - sage: P = polytopes.cube().change_ring(QQ) # optional - latte_int - sage: P.ehrhart_polynomial() # optional - latte_int + sage: # optional - latte_int + sage: P = polytopes.cube().change_ring(QQ) + sage: P.ehrhart_polynomial() 8*t^3 + 12*t^2 + 6*t + 1 - sage: Q = loads(dumps(P)) # optional - latte_int - sage: Q.ehrhart_polynomial.is_in_cache() # optional - latte_int + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_polynomial.is_in_cache() True """ # check if ``self`` is compact and has vertices in ZZ @@ -525,32 +527,35 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, If the polytope happens to be a lattice polytope, the Ehrhart polynomial is returned:: - sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), # optional - pynormaliz + sage: # optional - pynormaliz + sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), ....: (-3,2,1), (1,-1,-2)], ....: backend='normaliz') - sage: simplex = simplex.change_ring(QQ) # optional - pynormaliz - sage: poly = simplex.ehrhart_quasipolynomial( # optional - pynormaliz + sage: simplex = simplex.change_ring(QQ) + sage: poly = simplex.ehrhart_quasipolynomial( ....: engine='normaliz'); poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 - sage: simplex.ehrhart_polynomial() # optional - pynormaliz latte_int + sage: simplex.ehrhart_polynomial() # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 TESTS: The cache of the Ehrhart quasipolynomial is being pickled:: - sage: P = polytopes.cuboctahedron(backend='normaliz')/2 # optional - pynormaliz - sage: P.ehrhart_quasipolynomial() # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = polytopes.cuboctahedron(backend='normaliz')/2 + sage: P.ehrhart_quasipolynomial() (5/6*t^3 + 2*t^2 + 5/3*t + 1, 5/6*t^3 + 1/2*t^2 + 1/6*t - 1/2) - sage: Q = loads(dumps(P)) # optional - pynormaliz - sage: Q.ehrhart_quasipolynomial.is_in_cache() # optional - pynormaliz + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_quasipolynomial.is_in_cache() True - sage: P = polytopes.cuboctahedron().change_ring(QQ) # optional - latte_int - sage: P.ehrhart_quasipolynomial(engine='latte') # optional - latte_int + sage: # optional - latte_int + sage: P = polytopes.cuboctahedron().change_ring(QQ) + sage: P.ehrhart_quasipolynomial(engine='latte') 20/3*t^3 + 8*t^2 + 10/3*t + 1 - sage: Q = loads(dumps(P)) # optional - latte_int - sage: Q.ehrhart_quasipolynomial.is_in_cache(engine='latte') # optional - latte_int + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_quasipolynomial.is_in_cache(engine='latte') True """ if self.is_empty(): @@ -626,7 +631,7 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): TESTS:: sage: line_seg = Polyhedron(vertices=[[0],[1/2]]) - sage: line_seg._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz + sage: line_seg._ehrhart_quasipolynomial_normaliz() Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz' @@ -709,25 +714,26 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: p(1) # optional - latte_int 6 - sage: len(P.integral_points()) # optional - latte_int + sage: len(P.integral_points()) 6 sage: p(2) # optional - latte_int 36 - sage: len((2*P).integral_points()) # optional - latte_int + sage: len((2*P).integral_points()) 36 The unit hypercubes:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1], repeat=d))) - sage: hypercube(3)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(3)._ehrhart_polynomial_latte() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(4)._ehrhart_polynomial_latte() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(5)._ehrhart_polynomial_latte() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(6)._ehrhart_polynomial_latte() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 TESTS: @@ -863,19 +869,20 @@ def fixed_subpolytope(self, vertex_permutation): The next example shows that :meth:`fixed_subpolytope` works for rational polytopes:: - sage: P = Polyhedron(vertices=[[0], [1/2]], # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0], [1/2]], ....: backend='normaliz') - sage: P.vertices() # optional - pynormaliz + sage: P.vertices() (A vertex at (0), A vertex at (1/2)) - sage: G = P.restricted_automorphism_group( # optional - pynormaliz + sage: G = P.restricted_automorphism_group( ....: output='permutation'); G Permutation Group with generators [(0,1)] - sage: len(G) # optional - pynormaliz + sage: len(G) 2 - sage: fixed_set = P.fixed_subpolytope(G.gens()[0]) # optional - pynormaliz - sage: fixed_set # optional - pynormaliz + sage: fixed_set = P.fixed_subpolytope(G.gens()[0]) + sage: fixed_set A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex - sage: fixed_set.vertices_list() # optional - pynormaliz + sage: fixed_set.vertices_list() [[1/4]] """ if self.is_empty(): @@ -939,23 +946,24 @@ def fixed_subpolytopes(self, conj_class_reps): Here is an example for the square:: - sage: p = polytopes.hypercube(2, backend='normaliz'); p # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.groups + sage: p = polytopes.hypercube(2, backend='normaliz'); p A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices - sage: aut_p = p.restricted_automorphism_group( # optional - pynormaliz sage.groups + sage: aut_p = p.restricted_automorphism_group( ....: output='permutation') - sage: aut_p.order() # optional - pynormaliz sage.groups + sage: aut_p.order() 8 - sage: conj_list = aut_p.conjugacy_classes_representatives() # optional - pynormaliz sage.groups - sage: fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) # optional - pynormaliz sage.groups - sage: fixedpolytopes_dict[aut_p([(0,3),(1,2)])] # optional - pynormaliz sage.groups + sage: conj_list = aut_p.conjugacy_classes_representatives() + sage: fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) + sage: fixedpolytopes_dict[aut_p([(0,3),(1,2)])] A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex TESTS:: sage: P = Polyhedron(vertices=[[1, 1]], rays=[[1, 1]]) - sage: aut_P = P.restricted_automorphism_group(output='permutation') # optional - sage.groups - sage: conj_list = aut_P.conjugacy_classes_representatives() # optional - sage.groups - sage: P.fixed_subpolytopes(conj_list) # optional - sage.groups + sage: aut_P = P.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: conj_list = aut_P.conjugacy_classes_representatives() # needs sage.groups + sage: P.fixed_subpolytopes(conj_list) # needs sage.groups Traceback (most recent call last): ... NotImplementedError: unbounded polyhedra are not supported @@ -1021,15 +1029,16 @@ class functions. is equal to 1 = `\chi_{trivial}` (Prop 6.1 [Stap2011]_). Here is the computation for the 3-dimensional standard simplex:: - sage: S = polytopes.simplex(3, backend='normaliz'); S # optional - pynormaliz + sage: # optional - pynormaliz + sage: S = polytopes.simplex(3, backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group( # optional - pynormaliz + sage: G = S.restricted_automorphism_group( ....: output='permutation') - sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + sage: G.is_isomorphic(SymmetricGroup(4)) True - sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz + sage: Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -1041,26 +1050,27 @@ class functions. `\pm(0,0,1),\pm(1,0,1), \pm(0,1,1), \pm(1,1,1)` and let G = `\Zmod{2}` act on P as follows:: - sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], ....: [-1,0,-1], [0,1,1], ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') - sage: K = P.restricted_automorphism_group( # optional - pynormaliz + sage: K = P.restricted_automorphism_group( ....: output='permutation') - sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, # optional - pynormaliz + sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) + sage: conj_reps = G.conjugacy_classes_representatives() + sage: Dict = P.permutations_to_matrices(conj_reps, ....: acting_group=G) - sage: list(Dict.keys())[0] # optional - pynormaliz + sage: list(Dict.keys())[0] (0,2)(1,3)(4,6)(5,7) - sage: list(Dict.values())[0] # optional - pynormaliz + sage: list(Dict.values())[0] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] - sage: len(G) # optional - pynormaliz + sage: len(G) 2 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 1] [ 1 -1] @@ -1170,35 +1180,37 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p3 = polytopes.permutahedron(3, backend='normaliz') # optional - pynormaliz - sage: G = p3.restricted_automorphism_group( # optional - pynormaliz + sage: # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend='normaliz') + sage: G = p3.restricted_automorphism_group( ....: output='permutation') - sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz - sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz - sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz - sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + sage: reflection12 = G([(0,2),(1,4),(3,5)]) + sage: reflection23 = G([(0,1),(2,3),(4,5)]) + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) + sage: S3.is_isomorphic(SymmetricGroup(3)) True - sage: Hstar = p3.Hstar_function(S3) # optional - pynormaliz - sage: Hlin = p3.Hstar_function(S3, # optional - pynormaliz + sage: Hstar = p3.Hstar_function(S3) + sage: Hlin = p3.Hstar_function(S3, ....: output='Hstar_as_lin_comb') - sage: p3.is_effective(Hstar, Hlin) # optional - pynormaliz + sage: p3.is_effective(Hstar, Hlin) True If the `H^*`-series is not polynomial, then it is not effective:: - sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], ....: [-1,0,-1], [0,1,1], ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], ....: backend='normaliz') - sage: G = P.restricted_automorphism_group( # optional - pynormaliz + sage: G = P.restricted_automorphism_group( ....: output='permutation') - sage: H = G.subgroup(gens=[G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz + sage: H = G.subgroup(gens=[G([(0,2),(1,3),(4,6),(5,7)])]) + sage: Hstar = P.Hstar_function(H); Hstar (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) - sage: Hstar_lin = P.Hstar_function(H, # optional - pynormaliz + sage: Hstar_lin = P.Hstar_function(H, ....: output='Hstar_as_lin_comb') - sage: P.is_effective(Hstar, Hstar_lin) # optional - pynormaliz + sage: P.is_effective(Hstar, Hstar_lin) False """ if self.is_empty(): diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index b9b36bd6a48..7e360658341 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -79,7 +79,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field False TESTS: @@ -163,25 +163,26 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: p(1) # optional - latte_int 6 - sage: len(P.integral_points()) # optional - latte_int + sage: len(P.integral_points()) 6 sage: p(2) # optional - latte_int 36 - sage: len((2*P).integral_points()) # optional - latte_int + sage: len((2*P).integral_points()) 36 The unit hypercubes:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) - sage: hypercube(3)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(3)._ehrhart_polynomial_latte() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(4)._ehrhart_polynomial_latte() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(5)._ehrhart_polynomial_latte() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(6)._ehrhart_polynomial_latte() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 TESTS: @@ -281,7 +282,7 @@ def _ehrhart_polynomial_normaliz(self, variable='t'): Receive a type error if the backend is not normaliz:: sage: c = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]) - sage: c._ehrhart_polynomial_normaliz() # optional - pynormaliz + sage: c._ehrhart_polynomial_normaliz() Traceback (most recent call last): ... TypeError: The polyhedron's backend should be 'normaliz' @@ -367,11 +368,11 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: poly(1) # optional - latte_int 6 - sage: len(simplex.integral_points()) # optional - latte_int + sage: len(simplex.integral_points()) 6 sage: poly(2) # optional - latte_int 36 - sage: len((2*simplex).integral_points()) # optional - latte_int + sage: len((2*simplex).integral_points()) 36 Now we find the same Ehrhart polynomial, this time using @@ -387,7 +388,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None it returns an error:: sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) - sage: simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The polyhedron's backend should be 'normaliz' @@ -399,27 +400,29 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None hypercube, and the coefficient of the leading monomial equals the volume of the unit hypercube:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) - sage: hypercube(3).ehrhart_polynomial() # optional - latte_int + sage: hypercube(3).ehrhart_polynomial() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4).ehrhart_polynomial() # optional - latte_int + sage: hypercube(4).ehrhart_polynomial() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5).ehrhart_polynomial() # optional - latte_int + sage: hypercube(5).ehrhart_polynomial() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6).ehrhart_polynomial() # optional - latte_int + sage: hypercube(6).ehrhart_polynomial() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 + sage: # optional - pynormaliz sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d)),backend='normaliz') - sage: hypercube(3).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(3).ehrhart_polynomial(engine='normaliz') t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(4).ehrhart_polynomial(engine='normaliz') t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(5).ehrhart_polynomial(engine='normaliz') t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(6).ehrhart_polynomial(engine='normaliz') t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 An empty polyhedron:: @@ -626,8 +629,8 @@ def fibration_generator(self, dim): EXAMPLES:: - sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ) # optional - palp - sage: list(P.fibration_generator(2)) # optional - palp + sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ) # needs palp sage.graphs + sage: list(P.fibration_generator(2)) # needs palp sage.graphs [A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices] """ from sage.combinat.combination import Combinations diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 40b9017dc53..9491fce4e75 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -32,12 +32,12 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds EXAMPLES:: - sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field + sage: rt2 = AA(sqrt(2)); rt2 # needs sage.rings.number_field sage.symbolic 1.414213562373095? - sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field + sage: rt3 = AA(sqrt(3)); rt3 # needs sage.rings.number_field sage.symbolic 1.732050807568878? sage: from sage.geometry.polyhedron.base_number_field import _number_field_elements_from_algebraics_list_of_lists_of_lists - sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field + sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # needs sage.rings.number_field sage.symbolic [[[-a^3 + 3*a], [1]], [[a^2 - 2]], [[1], []]] """ from sage.rings.qqbar import number_field_elements_from_algebraics @@ -58,28 +58,29 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], ....: base_ring=AA, backend='normaliz') - sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz + sage: def convert_QQ(ieqs, eqs): ....: return [[1000*x for x in ieq] for ieq in ieqs], \ ....: [[1000*x for x in eq] for eq in eqs] - sage: def convert_NF(ieqs, eqs): # optional - pynormaliz + sage: def convert_NF(ieqs, eqs): ....: return ieqs, eqs - sage: p._compute_data_lists_and_internal_base_ring( # optional - pynormaliz + sage: p._compute_data_lists_and_internal_base_ring( ....: [[[1]], [[1/2]]], convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_data_lists_and_internal_base_ring( # optional - pynormaliz + sage: p._compute_data_lists_and_internal_base_ring( ....: [[[AA(1)]], [[1/2]]], convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_data_lists_and_internal_base_ring( # optional - pynormaliz sage.rings.number_field + sage: p._compute_data_lists_and_internal_base_ring( ....: [[[AA(sqrt(2))]], [[1/2]]], convert_QQ, convert_NF) ([[[a]], [[1/2]]], Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) TESTS:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: p = Polyhedron(base_ring=K, # indirect doctest # optional - pynormaliz sage.rings.number_field + sage: K. = QuadraticField(-5) # needs sage.rings.number_field + sage: p = Polyhedron(base_ring=K, # indirect doctest # optional - pynormaliz, needs sage.rings.number_field ....: backend='normaliz', ....: vertices=[(a,1/2), (2,0), (4,5/6)]) Traceback (most recent call last): @@ -88,11 +89,11 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con Checks that :trac:`30248` is fixed:: - sage: q = Polyhedron(base_ring=AA, # indirect doctest # optional - pynormaliz sage.rings.number_field + sage: q = Polyhedron(base_ring=AA, # indirect doctest # optional - pynormaliz, needs sage.rings.number_field ....: backend='normaliz', ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - sage: -q # optional - pynormaliz sage.rings.number_field + sage: -q # optional - pynormaliz, needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ from sage.categories.number_fields import NumberFields diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index d25ca1ceebf..5a07abb2408 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -49,14 +49,14 @@ Obtaining edges and ridges:: Vertex-graph and facet-graph:: - sage: C.vertex_graph() # optional - sage.graphs + sage: C.vertex_graph() # needs sage.graphs Graph on 16 vertices - sage: C.facet_graph() # optional - sage.graphs + sage: C.facet_graph() # needs sage.graphs Graph on 8 vertices Face lattice:: - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 82 elements Face iterator:: @@ -328,7 +328,7 @@ cdef class CombinatorialPolyhedron(SageObject): Traceback (most recent call last): ... ValueError: the combinatorial polyhedron was not initialized - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Traceback (most recent call last): ... ValueError: the combinatorial polyhedron was not initialized @@ -640,16 +640,17 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C1 = loads(C.dumps()) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: it1 = C1.face_generator() # optional - sage.combinat - sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C1 = loads(C.dumps()) + sage: it = C.face_generator() + sage: it1 = C1.face_generator() + sage: tup = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it) - sage: tup1 = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: tup1 = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it1) - sage: tup == tup1 # optional - sage.combinat + sage: tup == tup1 True sage: P = polytopes.cyclic_polytope(4,10) @@ -747,9 +748,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(3) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.Hrepresentation() # optional - sage.combinat + sage: P = polytopes.permutahedron(3) + sage: C = CombinatorialPolyhedron(P) + sage: C.Hrepresentation() (An inequality (1, 1, 0) x - 3 >= 0, An inequality (-1, -1, 0) x + 5 >= 0, An inequality (0, 1, 0) x - 1 >= 0, @@ -1104,10 +1105,11 @@ cdef class CombinatorialPolyhedron(SageObject): :: - sage: P = polytopes.permutahedron(5, backend='field') # optional - sage.combinat - sage: C = P.combinatorial_polyhedron() # optional - sage.combinat - sage: C.incidence_matrix.clear_cache() # optional - sage.combinat - sage: C.incidence_matrix() == P.incidence_matrix() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5, backend='field') + sage: C = P.combinatorial_polyhedron() + sage: C.incidence_matrix.clear_cache() + sage: C.incidence_matrix() == P.incidence_matrix() True The incidence matrix is consistent with @@ -1284,14 +1286,14 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cyclic_polytope(3,5) sage: C = CombinatorialPolyhedron(P) - sage: G = C.vertex_graph(); G # optional - sage.graphs + sage: G = C.vertex_graph(); G # needs sage.graphs Graph on 5 vertices - sage: sorted(G.degree()) # optional - sage.graphs + sage: sorted(G.degree()) # needs sage.graphs [3, 3, 4, 4, 4] sage: P = Polyhedron(rays=[[1]]) sage: C = CombinatorialPolyhedron(P) - sage: C.graph() # optional - sage.graphs + sage: C.graph() # needs sage.graphs Graph on 1 vertex """ vertices = self.vertices(names=names) @@ -1392,11 +1394,12 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(2) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.ridges() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(2) + sage: C = CombinatorialPolyhedron(P) + sage: C.ridges() ((An inequality (1, 0) x - 1 >= 0, An inequality (-1, 0) x + 2 >= 0),) - sage: C.ridges(add_equations=True) # optional - sage.combinat + sage: C.ridges(add_equations=True) (((An inequality (1, 0) x - 1 >= 0, An equation (1, 1) x - 3 == 0), (An inequality (-1, 0) x + 2 >= 0, An equation (1, 1) x - 3 == 0)),) @@ -1565,25 +1568,25 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cyclic_polytope(4,6) sage: C = CombinatorialPolyhedron(P) - sage: C.facet_graph() # optional - sage.graphs + sage: C.facet_graph() # needs sage.graphs Graph on 9 vertices TESTS:: sage: P = Polyhedron(ieqs=[[1,-1,0],[1,1,0]]) - sage: CombinatorialPolyhedron(P).facet_graph() # optional - sage.graphs + sage: CombinatorialPolyhedron(P).facet_graph() # needs sage.graphs Graph on 2 vertices Checking that :trac:`28604` is fixed:: sage: C = CombinatorialPolyhedron(polytopes.cube()); C A 3-dimensional combinatorial polyhedron with 6 facets - sage: C.facet_graph(names=False) # optional - sage.graphs + sage: C.facet_graph(names=False) # needs sage.graphs Graph on 6 vertices - sage: C = CombinatorialPolyhedron(polytopes.hypersimplex(5,2)); C # optional - sage.combinat + sage: C = CombinatorialPolyhedron(polytopes.hypersimplex(5,2)); C A 4-dimensional combinatorial polyhedron with 10 facets - sage: C.facet_graph() # optional - sage.graphs sage.combinat + sage: C.facet_graph() # needs sage.combinat sage.graphs Graph on 10 vertices """ face_iter = self.face_iter(self.dimension() - 1, algorithm='primal') @@ -1621,7 +1624,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.hypercube(2).pyramid() sage: C = CombinatorialPolyhedron(P) - sage: G = C.vertex_facet_graph(); G # optional - sage.graphs + sage: G = C.vertex_facet_graph(); G # needs sage.graphs Digraph on 10 vertices sage: C.Vrepresentation() (A vertex at (0, -1, -1), @@ -1629,7 +1632,7 @@ cdef class CombinatorialPolyhedron(SageObject): A vertex at (0, 1, -1), A vertex at (0, 1, 1), A vertex at (1, 0, 0)) - sage: sorted(G.neighbors_out(C.Vrepresentation()[4])) # optional - sage.graphs + sage: sorted(G.neighbors_out(C.Vrepresentation()[4])) # needs sage.graphs [An inequality (-1, -1, 0) x + 1 >= 0, An inequality (-1, 0, -1) x + 1 >= 0, An inequality (-1, 0, 1) x + 1 >= 0, @@ -1642,7 +1645,7 @@ cdef class CombinatorialPolyhedron(SageObject): with a string 'H' or 'V':: sage: C = CombinatorialPolyhedron(P.incidence_matrix()) - sage: C.vertex_facet_graph().vertices(sort=True) # optional - sage.graphs + sage: C.vertex_facet_graph().vertices(sort=True) # needs sage.graphs [('H', 0), ('H', 1), ('H', 2), @@ -1656,18 +1659,18 @@ cdef class CombinatorialPolyhedron(SageObject): If ``names`` is ``False`` then the vertices of the graph are given by integers:: - sage: C.vertex_facet_graph(names=False).vertices(sort=True) # optional - sage.graphs + sage: C.vertex_facet_graph(names=False).vertices(sort=True) # needs sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] TESTS: Test that :trac:`29898` is fixed:: - sage: Polyhedron().vertex_facet_graph() # optional - sage.graphs + sage: Polyhedron().vertex_facet_graph() # needs sage.graphs Digraph on 0 vertices - sage: Polyhedron([[0]]).vertex_facet_graph() # optional - sage.graphs + sage: Polyhedron([[0]]).vertex_facet_graph() # needs sage.graphs Digraph on 1 vertex - sage: Polyhedron([[0]]).vertex_facet_graph(False) # optional - sage.graphs + sage: Polyhedron([[0]]).vertex_facet_graph(False) # needs sage.graphs Digraph on 1 vertex """ from sage.graphs.digraph import DiGraph @@ -1736,9 +1739,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.f_vector() # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.f_vector() (1, 120, 240, 150, 30, 1) sage: P = polytopes.cyclic_polytope(6,10) @@ -1748,9 +1751,9 @@ cdef class CombinatorialPolyhedron(SageObject): Using two threads:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.f_vector(num_threads=2) # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.f_vector(num_threads=2) (1, 120, 240, 150, 30, 1) TESTS:: @@ -1808,7 +1811,7 @@ cdef class CombinatorialPolyhedron(SageObject): Obtain the entire flag-f-vector:: sage: C = polytopes.hypercube(4).combinatorial_polyhedron() - sage: C.flag_f_vector() # optional - sage.combinat + sage: C.flag_f_vector() # needs sage.combinat {(-1,): 1, (0,): 16, (0, 1): 64, @@ -1829,38 +1832,38 @@ cdef class CombinatorialPolyhedron(SageObject): Specify an entry:: - sage: C.flag_f_vector(0,3) # optional - sage.combinat + sage: C.flag_f_vector(0,3) # needs sage.combinat 64 - sage: C.flag_f_vector(2) # optional - sage.combinat + sage: C.flag_f_vector(2) # needs sage.combinat 24 Leading ``-1`` and trailing entry of dimension are allowed:: - sage: C.flag_f_vector(-1,0,3) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3) # needs sage.combinat 64 - sage: C.flag_f_vector(-1,0,3,4) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3,4) # needs sage.combinat 64 One can get the number of trivial faces:: - sage: C.flag_f_vector(-1) # optional - sage.combinat + sage: C.flag_f_vector(-1) # needs sage.combinat 1 - sage: C.flag_f_vector(4) # optional - sage.combinat + sage: C.flag_f_vector(4) # needs sage.combinat 1 Polyhedra with lines, have ``0`` entries accordingly:: sage: C = (Polyhedron(lines=[[1]]) * polytopes.hypercube(2)).combinatorial_polyhedron() - sage: C.flag_f_vector() # optional - sage.combinat + sage: C.flag_f_vector() # needs sage.combinat {(-1,): 1, (0, 1): 0, (0, 2): 0, (0,): 0, (1, 2): 8, (1,): 4, (2,): 4, 3: 1} If the arguments are not stricly increasing or out of range, a key error is raised:: - sage: C.flag_f_vector(-1,0,3,5) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3,5) # needs sage.combinat Traceback (most recent call last): ... KeyError: (0, 3, 5) - sage: C.flag_f_vector(-1,3,0) # optional - sage.combinat + sage: C.flag_f_vector(-1,3,0) # needs sage.combinat Traceback (most recent call last): ... KeyError: (3, 0) @@ -1888,7 +1891,7 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: sage: C = CombinatorialPolyhedron(3) - sage: C._flag_f_vector() # optional - sage.combinat + sage: C._flag_f_vector() # needs sage.combinat {(-1,): 1, (0, 1): 0, (0, 2): 0, (0,): 0, (1, 2): 0, (1,): 0, (2,): 0, 3: 1} """ poly = self.face_lattice().flag_f_polynomial() @@ -2086,8 +2089,8 @@ cdef class CombinatorialPolyhedron(SageObject): sage: CombinatorialPolyhedron(cyclic).simpliciality() 3 - sage: hypersimplex = polytopes.hypersimplex(5,2) # optional - sage.combinat - sage: CombinatorialPolyhedron(hypersimplex).simpliciality() # optional - sage.combinat + sage: hypersimplex = polytopes.hypersimplex(5,2) + sage: CombinatorialPolyhedron(hypersimplex).simpliciality() 2 sage: cross = polytopes.cross_polytope(4) @@ -2194,16 +2197,16 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: hyper4 = polytopes.hypersimplex(4,2) # optional - sage.combinat - sage: CombinatorialPolyhedron(hyper4).simplicity() # optional - sage.combinat + sage: hyper4 = polytopes.hypersimplex(4,2) + sage: CombinatorialPolyhedron(hyper4).simplicity() 1 - sage: hyper5 = polytopes.hypersimplex(5,2) # optional - sage.combinat - sage: CombinatorialPolyhedron(hyper5).simplicity() # optional - sage.combinat + sage: hyper5 = polytopes.hypersimplex(5,2) + sage: CombinatorialPolyhedron(hyper5).simplicity() 2 - sage: hyper6 = polytopes.hypersimplex(6,2) # optional - sage.combinat - sage: CombinatorialPolyhedron(hyper6).simplicity() # optional - sage.combinat + sage: hyper6 = polytopes.hypersimplex(6,2) + sage: CombinatorialPolyhedron(hyper6).simplicity() 3 sage: P = polytopes.simplex(3) @@ -2631,15 +2634,16 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.join_of_Vrep(0,1) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C.join_of_Vrep(0,1) A 1-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.join_of_Vrep(0,11).ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep(0,11).ambient_V_indices() (0, 1, 10, 11, 12, 13) - sage: C.join_of_Vrep(8).ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep(8).ambient_V_indices() (8,) - sage: C.join_of_Vrep().ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep().ambient_V_indices() () """ return self.face_generator().join_of_Vrep(*indices) @@ -2654,19 +2658,20 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field - sage: C.meet_of_Hrep(0) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: C = CombinatorialPolyhedron(P) + sage: C.meet_of_Hrep(0) A 2-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.meet_of_Hrep(0).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0).ambient_H_indices() (0,) - sage: C.meet_of_Hrep(0,1).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,1).ambient_H_indices() (0, 1) - sage: C.meet_of_Hrep(0,2).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,2).ambient_H_indices() (0, 2) - sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) - sage: C.meet_of_Hrep().ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep().ambient_H_indices() () """ return self.face_generator().meet_of_Hrep(*indices) @@ -2697,38 +2702,39 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it); face # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it); face # optional - sage.combinat + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), A vertex at (1, 3, 4, 5, 2), A vertex at (1, 2, 4, 5, 3), A vertex at (2, 3, 4, 5, 1)) - sage: face.ambient_Hrepresentation() # optional - sage.combinat + sage: face.ambient_Hrepresentation() (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: face.ambient_H_indices() # optional - sage.combinat + sage: face.ambient_H_indices() (25, 29, 30) - sage: face = next(it); face # optional - sage.combinat + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_H_indices() # optional - sage.combinat + sage: face.ambient_H_indices() (24, 29, 30) - sage: face.ambient_V_indices() # optional - sage.combinat + sage: face.ambient_V_indices() (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -2840,31 +2846,31 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron(rays=[[1,0],[0,1]]) sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 5 elements sage: P = Polyhedron(rays=[[1,0,0], [-1,0,0], [0,-1,0], [0,1,0]]) sage: C = CombinatorialPolyhedron(P) sage: P1 = Polyhedron(rays=[[1,0], [-1,0]]) sage: C1 = CombinatorialPolyhedron(P1) - sage: C.face_lattice().is_isomorphic(C1.face_lattice()) # optional - sage.combinat + sage: C.face_lattice().is_isomorphic(C1.face_lattice()) # needs sage.combinat True - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_lattice() # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 542 elements TESTS:: sage: P = polytopes.cyclic_polytope(4,10) sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice().is_isomorphic(P.face_lattice()) # optional - sage.combinat + sage: C.face_lattice().is_isomorphic(P.face_lattice()) # needs sage.combinat True - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_lattice().is_isomorphic(P.face_lattice()) # optional - sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C.face_lattice().is_isomorphic(P.face_lattice()) # needs sage.combinat True """ from sage.combinat.posets.lattices import FiniteLatticePoset @@ -2894,20 +2900,21 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field - sage: D = C.hasse_diagram(); D # optional - sage.graphs sage.rings.number_field + sage: # needs sage.graphs sage.rings.number_field + sage: P = polytopes.regular_polygon(4).pyramid() + sage: C = CombinatorialPolyhedron(P) + sage: D = C.hasse_diagram(); D Digraph on 20 vertices - sage: D.average_degree() # optional - sage.graphs sage.rings.number_field + sage: D.average_degree() 21/5 - sage: D.relabel(C.face_by_face_lattice_index) # optional - sage.graphs sage.rings.number_field - sage: dim_0_vert = D.vertices(sort=True)[1:6]; dim_0_vert # optional - sage.graphs sage.rings.number_field + sage: D.relabel(C.face_by_face_lattice_index) + sage: dim_0_vert = D.vertices(sort=True)[1:6]; dim_0_vert [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: sorted(D.out_degree(vertices=dim_0_vert)) # optional - sage.graphs sage.rings.number_field + sage: sorted(D.out_degree(vertices=dim_0_vert)) [3, 3, 3, 3, 4] """ if not self._face_lattice_incidences: @@ -2936,12 +2943,12 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat sage: def f(i): ....: return (i, C._face_lattice_dimension(i)) ....: - sage: G = F.relabel(f) # optional - sage.combinat - sage: set(G._elements) # optional - sage.combinat + sage: G = F.relabel(f) # needs sage.combinat + sage: set(G._elements) # needs sage.combinat {(0, -1), (1, 0), (2, 0), @@ -2990,15 +2997,16 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: + sage: # needs sage.combinat sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: F # optional - sage.combinat + sage: F = C.face_lattice() + sage: F Finite lattice containing 28 elements - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat - sage: G.level_sets()[0] # optional - sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) + sage: G.level_sets()[0] [A -1-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: G.level_sets()[3] # optional - sage.combinat + sage: G.level_sets()[3] [A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, @@ -3008,9 +3016,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron(rays=[[0,1], [1,0]]) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat - sage: G._elements # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # needs sage.combinat + sage: G._elements # needs sage.combinat (A -1-dimensional face of a 2-dimensional combinatorial polyhedron, A 0-dimensional face of a 2-dimensional combinatorial polyhedron, A 1-dimensional face of a 2-dimensional combinatorial polyhedron, @@ -3018,8 +3026,8 @@ cdef class CombinatorialPolyhedron(SageObject): A 2-dimensional face of a 2-dimensional combinatorial polyhedron) sage: def f(i): return C.face_by_face_lattice_index(i).ambient_V_indices() - sage: G = F.relabel(f) # optional - sage.combinat - sage: G._elements # optional - sage.combinat + sage: G = F.relabel(f) # needs sage.combinat + sage: G._elements # needs sage.combinat ((), (0,), (0, 1), (0, 2), (0, 1, 2)) """ self._record_all_faces() # Initialize ``_all_faces``, if not done yet. @@ -3064,13 +3072,14 @@ cdef class CombinatorialPolyhedron(SageObject): sage: [face.ambient_V_indices() for face in chain] [(15,), (6, 15), (5, 6, 14, 15), (0, 5, 6, 7, 8, 9, 14, 15)] - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = P.combinatorial_polyhedron() # optional - sage.combinat - sage: chain = C.a_maximal_chain(); chain # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = P.combinatorial_polyhedron() + sage: chain = C.a_maximal_chain(); chain [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 1-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: [face.ambient_V_indices() for face in chain] # optional - sage.combinat + sage: [face.ambient_V_indices() for face in chain] [(16,), (15, 16), (8, 9, 14, 15, 16, 17)] sage: P = Polyhedron(rays=[[1,0]], lines=[[0,1]]) @@ -3366,7 +3375,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: D.f_vector() (1, 6, 12, 8, 1) sage: D1 = P.polar().combinatorial_polyhedron() - sage: D1.face_lattice().is_isomorphic(D.face_lattice()) # optional - sage.combinat + sage: D1.face_lattice().is_isomorphic(D.face_lattice()) # needs sage.combinat True Polar is an alias to be consistent with :class:`~sage.geometry.polyhedron.base.Polyhedron_base`:: @@ -3416,7 +3425,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C1 = C.pyramid() sage: P1 = P.pyramid() sage: C2 = P1.combinatorial_polyhedron() - sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) # optional - sage.combinat + sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) # needs sage.combinat True One can specify a name for the new vertex:: @@ -3435,10 +3444,11 @@ cdef class CombinatorialPolyhedron(SageObject): One can specify a name for the new facets:: - sage: P = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: C = P.combinatorial_polyhedron() # optional - sage.rings.number_field - sage: C1 = C.pyramid(new_facet='base') # optional - sage.rings.number_field - sage: C1.Hrepresentation() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.regular_polygon(4) + sage: C = P.combinatorial_polyhedron() + sage: C1 = C.pyramid(new_facet='base') + sage: C1.Hrepresentation() (An inequality (-1/2, 1/2) x + 1/2 >= 0, An inequality (-1/2, -1/2) x + 1/2 >= 0, An inequality (1/2, 0.50000000000000000?) x + 1/2 >= 0, @@ -3823,17 +3833,18 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() + sage: tup = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it) - sage: rg = range(1,sum(C.f_vector()) - 1) # optional - sage.combinat - sage: tup2 = tuple( # optional - sage.combinat + sage: rg = range(1,sum(C.f_vector()) - 1) + sage: tup2 = tuple( ....: (C.face_by_face_lattice_index(i).ambient_Vrepresentation(), ....: C.face_by_face_lattice_index(i).ambient_Hrepresentation()) ....: for i in rg) - sage: sorted(tup) == sorted(tup2) # optional - sage.combinat + sage: sorted(tup) == sorted(tup2) True sage: P = polytopes.cyclic_polytope(4,10) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index e499afcbc1c..bf01025707f 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -22,9 +22,9 @@ Obtain a face from a face lattice index:: sage: P = polytopes.simplex(2) sage: C = CombinatorialPolyhedron(P) - sage: sorted(C.face_lattice()._elements) # optional - sage.combinat + sage: sorted(C.face_lattice()._elements) # needs sage.combinat [0, 1, 2, 3, 4, 5, 6, 7] - sage: face = C.face_by_face_lattice_index(0); face # optional - sage.combinat + sage: face = C.face_by_face_lattice_index(0); face A -1-dimensional face of a 2-dimensional combinatorial polyhedron Obtain further information regarding a face:: @@ -97,10 +97,10 @@ cdef class CombinatorialFace(SageObject): Obtain a combinatorial face from an index of the face lattice:: - sage: F = C.face_lattice() # optional - sage.combinat - sage: F._elements[3] # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: F._elements[3] # needs sage.combinat 34 - sage: C.face_by_face_lattice_index(29) # optional - sage.combinat + sage: C.face_by_face_lattice_index(29) A 1-dimensional face of a 5-dimensional combinatorial polyhedron Obtain the dimension of a combinatorial face:: @@ -260,15 +260,16 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(6) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=3, algorithm='primal') # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.__repr__() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(6) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=3, algorithm='primal') + sage: face = next(it) + sage: face.__repr__() 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' - sage: it = C.face_generator(dimension=3, algorithm='dual') # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.__repr__() # optional - sage.combinat + sage: it = C.face_generator(dimension=3, algorithm='dual') + sage: face = next(it) + sage: face.__repr__() 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' """ return "A {}-dimensional face of a {}-dimensional combinatorial polyhedron"\ @@ -318,15 +319,16 @@ cdef class CombinatorialFace(SageObject): TESTS:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: F = C.face_lattice() + sage: G = F.relabel(C.face_by_face_lattice_index) sage: P = polytopes.cyclic_polytope(4,10) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # needs sage.combinat """ return self._hash_index @@ -349,7 +351,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat + sage: for i,j in Combinations(range(28), 2): ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -361,7 +363,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat + sage: for i,j in Combinations(range(28), 2): ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -501,16 +503,17 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.associahedron(['A', 3]) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.dimension() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.associahedron(['A', 3]) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() + sage: face = next(it) + sage: face.dimension() 2 ``dim`` is an alias:: - sage: face.dim() # optional - sage.combinat + sage: face.dim() # needs sage.combinat 2 """ if self._dual: @@ -545,19 +548,20 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it) + sage: face.ambient_Vrepresentation() (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face = next(it) + sage: face.ambient_Vrepresentation() (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), @@ -609,13 +613,14 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: next(it).ambient_V_indices() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it) + sage: next(it).ambient_V_indices() (32, 91, 92, 93, 94, 95) - sage: next(it).ambient_V_indices() # optional - sage.combinat + sage: next(it).ambient_V_indices() (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -688,14 +693,15 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: next(it).ambient_Hrepresentation() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: next(it).ambient_Hrepresentation() (An inequality (1, 1, 1, 0, 0) x - 6 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: next(it).ambient_Hrepresentation() # optional - sage.combinat + sage: next(it).ambient_Hrepresentation() (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) @@ -748,21 +754,22 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_H_indices(add_equations=False) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: face = next(it) + sage: face.ambient_H_indices(add_equations=False) (28, 29) - sage: face2 = next(it) # optional - sage.combinat - sage: face2.ambient_H_indices(add_equations=False) # optional - sage.combinat + sage: face2 = next(it) + sage: face2.ambient_H_indices(add_equations=False) (25, 29) Add the indices of the equation:: - sage: face.ambient_H_indices(add_equations=True) # optional - sage.combinat + sage: face.ambient_H_indices(add_equations=True) # needs sage.combinat (28, 29, 30) - sage: face2.ambient_H_indices(add_equations=True) # optional - sage.combinat + sage: face2.ambient_H_indices(add_equations=True) # needs sage.combinat (25, 29, 30) Another example:: @@ -828,13 +835,14 @@ cdef class CombinatorialFace(SageObject): Specifying whether to count the equations or not:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: f = next(it) # optional - sage.combinat - sage: f.n_ambient_Hrepresentation(add_equations=True) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: f = next(it) + sage: f.n_ambient_Hrepresentation(add_equations=True) 3 - sage: f.n_ambient_Hrepresentation(add_equations=False) # optional - sage.combinat + sage: f.n_ambient_Hrepresentation(add_equations=False) 2 TESTS:: @@ -877,7 +885,7 @@ cdef class CombinatorialFace(SageObject): sage: F.f_vector() (1, 5, 10, 10, 5, 1) sage: F_alt = polytopes.cyclic_polytope(4,5).combinatorial_polyhedron() - sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) # optional - sage.graphs + sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) # needs sage.graphs True Obtaining the quotient:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx index b670ad2e53f..baeb8fc4855 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx @@ -31,11 +31,12 @@ Obtain the facets of a polyhedron as :class:`~sage.geometry.polyhedron.combinato Obtain the Vrepresentation of a polyhedron as facet-incidences stored in :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',4]) # optional - sage.combinat - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat - sage: face_list.compute_dimension() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',4]) + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) + sage: face_list.compute_dimension() 4 Obtain the facets of a polyhedron as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces` from a facet list:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index cd24dd5be66..f0ac1e774a7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -207,13 +207,13 @@ cdef class FaceIterator_base(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # indirect doctest # optional - sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() # indirect doctest sage: f_vector = [1, 0, 0, 0, 1] - sage: for face in it: f_vector[face.dimension()+1] += 1 # optional - sage.combinat - sage: print ('f_vector of permutahedron(4): ', f_vector) # optional - sage.combinat + sage: for face in it: f_vector[face.dimension()+1] += 1 + sage: print ('f_vector of permutahedron(4): ', f_vector) f_vector of permutahedron(4): [1, 24, 36, 14, 1] sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator).run() @@ -637,17 +637,18 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it.meet_of_Hrep(9,11) # optional - sage.rings.number_field + sage: it.meet_of_Hrep(9,11) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it.meet_of_Hrep(9,11).ambient_H_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it.meet_of_Hrep(9,11).ambient_H_indices() (9, 11) TESTS: @@ -722,17 +723,18 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it.join_of_Vrep(1,10) # optional - sage.rings.number_field + sage: it.join_of_Vrep(1,10) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it.join_of_Vrep(1,10).ambient_V_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it.join_of_Vrep(1,10).ambient_V_indices() (1, 10) In the case of an unbounded polyhedron, we try to make sense of the input:: @@ -846,9 +848,10 @@ cdef class FaceIterator_base(SageObject): The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator(2) # optional - sage.rings.number_field - sage: it._meet_of_coatoms(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator(2) + sage: it._meet_of_coatoms(1,2) Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -955,24 +958,26 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it._join_of_atoms(1,10) # optional - sage.rings.number_field + sage: it._join_of_atoms(1,10) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it._join_of_atoms(1,10).ambient_V_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it._join_of_atoms(1,10).ambient_V_indices() (1, 10) The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator(2) # optional - sage.rings.number_field - sage: it._join_of_atoms(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator(2) + sage: it._join_of_atoms(1,2) Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -1574,12 +1579,12 @@ cdef class FaceIterator(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_generator() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) # needs sage.combinat + sage: C = CombinatorialPolyhedron(P) # needs sage.combinat + sage: C.face_generator() # needs sage.combinat Iterator over the proper faces of a 3-dimensional combinatorial polyhedron - sage: C.face_generator(1) # optional - sage.combinat + sage: C.face_generator(1) # needs sage.combinat Iterator over the 1-faces of a 3-dimensional combinatorial polyhedron """ if self.structure.output_dimension != -2: @@ -1845,11 +1850,11 @@ cdef class FaceIterator_geom(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: P.face_generator() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) # needs sage.combinat + sage: P.face_generator() # needs sage.combinat Iterator over the faces of a 3-dimensional polyhedron in QQ^3 - sage: P.face_generator(1) # optional - sage.combinat + sage: P.face_generator(1) # needs sage.combinat Iterator over the 1-faces of a 3-dimensional polyhedron in QQ^3 """ if self._requested_dim is not None: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index d365ee3a24e..dffa76036fa 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -39,11 +39,12 @@ Obtain the facets of a polyhedron:: Obtain the Vrepresentation of a polyhedron as facet-incidences:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat - sage: face_list.compute_dimension() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) + sage: face_list.compute_dimension() 3 Obtain the facets of a polyhedron as :class:`ListOfFaces` from a facet list:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index 0454c9bc19c..be6ffbda794 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -100,7 +100,7 @@ cdef class PolyhedronFaceLattice: sage: P = polytopes.Birkhoff_polytope(3) sage: C = CombinatorialPolyhedron(P) sage: C._record_all_faces() # indirect doctests - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 50 elements ALGORITHM: @@ -215,7 +215,7 @@ cdef class PolyhedronFaceLattice: sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) sage: C._record_all_faces() # indirect doctests - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 28 elements sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_face_lattice.PolyhedronFaceLattice).run() diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 4fd1eadb2d8..f18492f584f 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -176,8 +176,8 @@ exact way to work with roots in Sage is the :mod:`Algebraic Real Field ` :: - sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # optional - sage.rings.number_field sage.symbolic - sage: triangle.Hrepresentation() # optional - sage.rings.number_field sage.symbolic + sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: triangle.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -186,12 +186,12 @@ symbolic ring element and, therefore, the polyhedron defined over the symbolic ring. This is currently not supported as SR is not exact:: - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) # optional - sage.symbolic + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) # needs sage.symbolic Traceback (most recent call last): ... ValueError: no default backend for computations with Symbolic Ring - sage: SR.is_exact() # optional - sage.symbolic + sage: SR.is_exact() # needs sage.symbolic False Even faster than all algebraic real numbers (the field ``AA``) is @@ -199,8 +199,8 @@ triangle, that would be:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) # optional - sage.rings.number_field - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) # needs sage.rings.number_field + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # needs sage.rings.number_field A 2-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 3 vertices @@ -220,7 +220,7 @@ A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex sage: Polyhedron(vertices = [[1.12345678901234, 2.123456789012345]]) A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: Polyhedron(vertices = [[1.123456789012345, 2.123456789012345]]) # optional - sage.rings.real_mpfr + sage: Polyhedron(vertices = [[1.123456789012345, 2.123456789012345]]) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: the only allowed inexact ring is 'RDF' with backend 'cdd' @@ -452,26 +452,28 @@ def Polyhedron(vertices=None, rays=None, lines=None, by the cyclic shifts of `(0, \pm 1, \pm (1+\sqrt(5))/2)`, cf. :wikipedia:`Regular_icosahedron`. It needs a number field:: - sage: R0. = QQ[] # optional - sage.rings.number_field - sage: R1. = NumberField(r0^2-5, embedding=AA(5)**(1/2)) # optional - sage.rings.number_field - sage: gold = (1+r1)/2 # optional - sage.rings.number_field - sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] # optional - sage.rings.number_field - sage: pp = Permutation((1, 2, 3)) # optional - sage.combinat sage.rings.number_field - sage: icosah = Polyhedron( # optional - sage.combinat sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R0. = QQ[] + sage: R1. = NumberField(r0^2-5, embedding=AA(5)**(1/2)) + sage: gold = (1+r1)/2 + sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] + sage: pp = Permutation((1, 2, 3)) + sage: icosah = Polyhedron( # needs sage.combinat ....: [(pp^2).action(w) for w in v] + [pp.action(w) for w in v] + v, ....: base_ring=R1) - sage: len(icosah.faces(2)) # optional - sage.combinat sage.rings.number_field + sage: len(icosah.faces(2)) # needs sage.combinat 20 When the input contains elements of a Number Field, they require an embedding:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K = NumberField(x^2 - 2,'s') # optional - sage.rings.number_field - sage: s = K.0 # optional - sage.rings.number_field - sage: L = NumberField(x^3 - 2,'t') # optional - sage.rings.number_field - sage: t = L.0 # optional - sage.rings.number_field - sage: P = Polyhedron(vertices=[[0,s], [t,0]]) # optional - sage.rings.number_field + sage: K = NumberField(x^2 - 2,'s') + sage: s = K.0 + sage: L = NumberField(x^3 - 2,'t') + sage: t = L.0 + sage: P = Polyhedron(vertices=[[0,s], [t,0]]) Traceback (most recent call last): ... ValueError: invalid base ring @@ -508,12 +510,13 @@ def Polyhedron(vertices=None, rays=None, lines=None, sage: Polyhedron(o, base_ring=QQ) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices - sage: H. = HyperplaneArrangements(QQ) # optional - sage.combinat - sage: h = x + y - 1; h # optional - sage.combinat + sage: # needs sage.combinat + sage: H. = HyperplaneArrangements(QQ) + sage: h = x + y - 1; h Hyperplane x + y - 1 - sage: Polyhedron(h, base_ring=ZZ) # optional - sage.combinat + sage: Polyhedron(h, base_ring=ZZ) A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 1 line - sage: Polyhedron(h) # optional - sage.combinat + sage: Polyhedron(h) A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line .. NOTE:: @@ -567,7 +570,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, Check that input with too many bits of precision returns an error (see :trac:`22552`):: - sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), # optional - sage.rings.real_mpfr + sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), # needs sage.rings.real_mpfr ....: (6.4876921900819049, 4.8435898415984129)]) Traceback (most recent call last): ... @@ -575,11 +578,11 @@ def Polyhedron(vertices=None, rays=None, lines=None, Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`):: - sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) # optional - sage.rings.real_mpfr + sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 40 bits of precision - sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) # optional - sage.rings.real_mpfr + sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index e8aad9bcd29..089580e3146 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -28,10 +28,10 @@ `\RR`, for example:: sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm - sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # optional - sage.rings.number_field + sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # needs sage.rings.number_field ....: (-AA(3).sqrt(),-AA(2).sqrt(),1)]) - sage: alg = StandardAlgorithm(A) # optional - sage.rings.number_field - sage: alg.run().R # optional - sage.rings.number_field + sage: alg = StandardAlgorithm(A) + sage: alg.run().R # needs sage.rings.number_field [(-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?), (-0.2411809548974793?, -0.2411809548974793?, 0.2411809548974793?), (0.07665629029830300?, 0.07665629029830300?, 0.2411809548974793?), @@ -411,10 +411,11 @@ def matrix_space(self, nrows, ncols): sage: DD.matrix_space(3,2) Full MatrixSpace of 3 by 2 dense matrices over Rational Field - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: A = matrix([[1,sqrt2],[2,0]]) # optional - sage.rings.number_field - sage: DD, _ = Problem(A).initial_pair() # optional - sage.rings.number_field - sage: DD.matrix_space(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(2) + sage: A = matrix([[1,sqrt2],[2,0]]) + sage: DD, _ = Problem(A).initial_pair() + sage: DD.matrix_space(1,2) Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? """ @@ -597,9 +598,9 @@ def base_ring(self): EXAMPLES:: - sage: A = matrix(AA, [(1, 1), (-1, 1)]) # optional - sage.rings.number_field + sage: A = matrix(AA, [(1, 1), (-1, 1)]) # needs sage.rings.number_field sage: from sage.geometry.polyhedron.double_description import Problem - sage: Problem(A).base_ring() # optional - sage.rings.number_field + sage: Problem(A).base_ring() # needs sage.rings.number_field Algebraic Real Field """ return self._field diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 64b14e39386..8a1e2dc2969 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -35,7 +35,7 @@ or :meth:`~sage.geometry.polyhedron.base.face_lattice` to get the whole face lattice as a poset:: - sage: P.face_lattice() # optional - sage.combinat + sage: P.face_lattice() # needs sage.combinat Finite lattice containing 28 elements The faces are printed in shorthand notation where each integer is the @@ -404,7 +404,7 @@ def ambient_Hrepresentation(self, index=None): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: for face in square.face_lattice(): # optional - sage.combinat + sage: for face in square.face_lattice(): # needs sage.combinat ....: print(face.ambient_Hrepresentation()) (An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0) @@ -445,7 +445,7 @@ def ambient_Vrepresentation(self, index=None): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: for fl in square.face_lattice(): # optional - sage.combinat + sage: for fl in square.face_lattice(): # needs sage.combinat ....: print(fl.ambient_Vrepresentation()) () (A vertex at (1, -1),) @@ -478,14 +478,14 @@ def n_ambient_Hrepresentation(self): EXAMPLES:: sage: p = polytopes.cross_polytope(4) - sage: face = p.face_lattice()[5]; face # optional - sage.combinat + sage: face = p.face_lattice()[5]; face # needs sage.combinat A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices - sage: face.ambient_Hrepresentation() # optional - sage.combinat + sage: face.ambient_Hrepresentation() # needs sage.combinat (An inequality (1, -1, 1, -1) x + 1 >= 0, An inequality (1, 1, 1, 1) x + 1 >= 0, An inequality (1, 1, 1, -1) x + 1 >= 0, An inequality (1, -1, 1, 1) x + 1 >= 0) - sage: face.n_ambient_Hrepresentation() # optional - sage.combinat + sage: face.n_ambient_Hrepresentation() # needs sage.combinat 4 """ return len(self.ambient_Hrepresentation()) @@ -504,11 +504,11 @@ def n_ambient_Vrepresentation(self): EXAMPLES:: sage: p = polytopes.cross_polytope(4) - sage: face = p.face_lattice()[5]; face # optional - sage.combinat + sage: face = p.face_lattice()[5]; face # needs sage.combinat A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() # needs sage.combinat (A vertex at (-1, 0, 0, 0), A vertex at (0, 0, -1, 0)) - sage: face.n_ambient_Vrepresentation() # optional - sage.combinat + sage: face.n_ambient_Vrepresentation() # needs sage.combinat 2 """ return len(self.ambient_Vrepresentation()) @@ -593,8 +593,8 @@ def dim(self): EXAMPLES:: - sage: fl = polytopes.dodecahedron().face_lattice() # optional - sage.combinat sage.rings.number_field - sage: sorted(x.dim() for x in fl) # optional - sage.combinat sage.rings.number_field + sage: fl = polytopes.dodecahedron().face_lattice() # needs sage.combinat sage.rings.number_field + sage: sorted(x.dim() for x in fl) # needs sage.combinat sage.rings.number_field [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3] @@ -628,8 +628,8 @@ def _repr_(self): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: a_face = list( square.face_lattice() )[8] # optional - sage.combinat - sage: a_face.__repr__() # optional - sage.combinat + sage: a_face = list( square.face_lattice() )[8] # needs sage.combinat + sage: a_face.__repr__() # needs sage.combinat 'A 1-dimensional face of a Polyhedron in ZZ^2 defined as the convex hull of 2 vertices' """ desc = '' @@ -705,7 +705,7 @@ def ambient_vector_space(self, base_field=None): Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line sage: line.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: line.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: line.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.polyhedron().ambient_vector_space(base_field=base_field) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 1c788d2c1bc..a1a59cdfe65 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -117,7 +117,7 @@ def zero_sum_projection(d, base_ring=None): Exact computation in :class:`AA `:: - sage: zero_sum_projection(3, base_ring=AA) # optional - sage.rings.number_field + sage: zero_sum_projection(3, base_ring=AA) # needs sage.rings.number_field [ 0.7071067811865475? -0.7071067811865475? 0] [ 0.4082482904638630? 0.4082482904638630? -0.8164965809277260?] @@ -171,17 +171,17 @@ def project_points(*points, **kwds): Check that it is (almost) an isometry:: - sage: V = list(map(vector, IntegerVectors(n=5, length=3))) # optional - sage.combinat - sage: P = project_points(*V) # optional - sage.combinat - sage: for i in range(21): # optional - sage.combinat + sage: V = list(map(vector, IntegerVectors(n=5, length=3))) + sage: P = project_points(*V) + sage: for i in range(21): # needs sage.combinat ....: for j in range(21): ....: assert abs((V[i]-V[j]).norm() - (P[i]-P[j]).norm()) < 0.00001 Example with exact computation:: - sage: V = [ vector(v) for v in IntegerVectors(n=4, length=2) ] # optional - sage.combinat - sage: P = project_points(*V, base_ring=AA) # optional - sage.combinat sage.rings.number_field - sage: for i in range(len(V)): # optional - sage.combinat sage.rings.number_field + sage: V = [ vector(v) for v in IntegerVectors(n=4, length=2) ] + sage: P = project_points(*V, base_ring=AA) # needs sage.combinat sage.rings.number_field + sage: for i in range(len(V)): # needs sage.combinat sage.rings.number_field ....: for j in range(len(V)): ....: assert (V[i]-V[j]).norm() == (P[i]-P[j]).norm() @@ -515,15 +515,16 @@ def regular_polygon(self, n, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: octagon = polytopes.regular_polygon(8) # optional - sage.rings.number_field - sage: octagon # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: octagon = polytopes.regular_polygon(8) + sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices - sage: octagon.n_vertices() # optional - sage.rings.number_field + sage: octagon.n_vertices() 8 - sage: v = octagon.volume() # optional - sage.rings.number_field - sage: v # optional - sage.rings.number_field + sage: v = octagon.volume() + sage: v 2.828427124746190? - sage: v == 2*QQbar(2).sqrt() # optional - sage.rings.number_field + sage: v == 2*QQbar(2).sqrt() True Its non exact version:: @@ -537,14 +538,16 @@ def regular_polygon(self, n, exact=True, base_ring=None, backend=None): TESTS:: - sage: octagon = polytopes.regular_polygon(8, backend='normaliz') # optional - pynormaliz sage.rings.number_field - sage: octagon # optional - pynormaliz sage.rings.number_field + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: octagon = polytopes.regular_polygon(8, backend='normaliz') + sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices - sage: octagon.n_vertices() # optional - pynormaliz sage.rings.number_field + sage: octagon.n_vertices() 8 - sage: octagon.volume() # optional - pynormaliz sage.rings.number_field + sage: octagon.volume() 2*a - sage: TestSuite(octagon).run() # long time # optional - sage.rings.number_field + sage: TestSuite(octagon).run() # long time + sage: TestSuite(polytopes.regular_polygon(5, exact=False)).run() """ n = ZZ(n) @@ -678,8 +681,8 @@ def simplex(self, dim=3, project=False, base_ring=None, backend=None): Computation in algebraic reals:: - sage: s3 = polytopes.simplex(3, project=True, base_ring=AA) # optional - sage.rings.number_field - sage: s3.volume() == sqrt(3+1) / factorial(3) # optional - sage.rings.number_field + sage: s3 = polytopes.simplex(3, project=True, base_ring=AA) # needs sage.rings.number_field + sage: s3.volume() == sqrt(3+1) / factorial(3) # needs sage.rings.number_field True TESTS:: @@ -716,47 +719,48 @@ def icosahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: ico = polytopes.icosahedron() # optional - sage.rings.number_field - sage: ico.f_vector() # optional - sage.rings.number_field + sage: ico = polytopes.icosahedron() # needs sage.rings.number_field + sage: ico.f_vector() # needs sage.rings.number_field (1, 12, 30, 20, 1) - sage: ico.volume() # optional - sage.rings.number_field + sage: ico.volume() # needs sage.rings.number_field 5/12*sqrt5 + 5/4 Its non exact version:: - sage: ico = polytopes.icosahedron(exact=False) # optional - sage.groups - sage: ico.base_ring() # optional - sage.groups + sage: ico = polytopes.icosahedron(exact=False) # needs sage.groups + sage: ico.base_ring() # needs sage.groups Real Double Field - sage: ico.volume() # known bug (trac 18214) # optional - sage.groups + sage: ico.volume() # known bug # needs sage.groups 2.181694990... A version using `AA `:: - sage: ico = polytopes.icosahedron(base_ring=AA) # long time # optional - sage.rings.number_field sage.groups - sage: ico.base_ring() # long time # optional - sage.rings.number_field sage.groups + sage: ico = polytopes.icosahedron(base_ring=AA) # long time # needs sage.groups sage.rings.number_field + sage: ico.base_ring() # long time # needs sage.groups sage.rings.number_field Algebraic Real Field - sage: ico.volume() # long time # optional - sage.rings.number_field sage.groups + sage: ico.volume() # long time # needs sage.groups sage.rings.number_field 2.181694990624913? Note that if base ring is provided it must contain the square root of `5`. Otherwise you will get an error:: - sage: polytopes.icosahedron(base_ring=QQ) # optional - sage.symbolic + sage: polytopes.icosahedron(base_ring=QQ) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational TESTS:: - sage: ico = polytopes.icosahedron(backend='normaliz') # optional - pynormaliz sage.rings.number_field sage.groups - sage: ico.f_vector() # optional - pynormaliz sage.rings.number_field sage.groups + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: ico = polytopes.icosahedron(backend='normaliz') + sage: ico.f_vector() (1, 12, 30, 20, 1) - sage: ico.volume() # optional - pynormaliz sage.rings.number_field sage.groups + sage: ico.volume() 5/12*sqrt5 + 5/4 - sage: TestSuite(ico).run() # optional - pynormaliz sage.rings.number_field sage.groups + sage: TestSuite(ico).run() - sage: ico = polytopes.icosahedron(exact=False) # optional - sage.groups - sage: TestSuite(ico).run(skip="_test_lawrence") # optional - sage.groups + sage: ico = polytopes.icosahedron(exact=False) # needs sage.groups + sage: TestSuite(ico).run(skip="_test_lawrence") # needs sage.groups """ if base_ring is None and exact: @@ -798,31 +802,32 @@ def dodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: d12 = polytopes.dodecahedron() # optional - sage.rings.number_field sage.groups - sage: d12.f_vector() # optional - sage.rings.number_field sage.groups + sage: # needs sage.groups sage.rings.number_field + sage: d12 = polytopes.dodecahedron() + sage: d12.f_vector() (1, 20, 30, 12, 1) - sage: d12.volume() # optional - sage.rings.number_field sage.groups + sage: d12.volume() -176*sqrt5 + 400 - sage: numerical_approx(_) # optional - sage.rings.number_field sage.groups + sage: numerical_approx(_) 6.45203596003699 - sage: d12 = polytopes.dodecahedron(exact=False) # optional - sage.groups - sage: d12.base_ring() # optional - sage.groups + sage: d12 = polytopes.dodecahedron(exact=False) # needs sage.groups + sage: d12.base_ring() # needs sage.groups Real Double Field Here is an error with a field that does not contain `\sqrt(5)`:: - sage: polytopes.dodecahedron(base_ring=QQ) # optional - sage.symbolic sage.groups + sage: polytopes.dodecahedron(base_ring=QQ) # needs sage.groups sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational TESTS:: - sage: d12 = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz sage.rings.number_field sage.groups - sage: d12.f_vector() # optional - pynormaliz sage.rings.number_field sage.groups + sage: d12 = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: d12.f_vector() # optional - pynormaliz, needs sage.groups sage.rings.number_field (1, 20, 30, 12, 1) - sage: TestSuite(d12).run() # optional - pynormaliz sage.rings.number_field sage.groups + sage: TestSuite(d12).run() # optional - pynormaliz, needs sage.groups sage.rings.number_field """ return self.icosahedron(exact=exact, base_ring=base_ring, backend=backend).polar() @@ -847,17 +852,17 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: sr = polytopes.small_rhombicuboctahedron() # optional - sage.rings.number_field - sage: sr.f_vector() # optional - sage.rings.number_field + sage: sr = polytopes.small_rhombicuboctahedron() # needs sage.rings.number_field + sage: sr.f_vector() # needs sage.rings.number_field (1, 24, 48, 26, 1) - sage: sr.volume() # optional - sage.rings.number_field + sage: sr.volume() # needs sage.rings.number_field 80/3*sqrt2 + 32 The faces are `8` equilateral triangles and `18` squares:: - sage: sum(1 for f in sr.facets() if len(f.vertices()) == 3) # optional - sage.rings.number_field + sage: sum(1 for f in sr.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 8 - sage: sum(1 for f in sr.facets() if len(f.vertices()) == 4) # optional - sage.rings.number_field + sage: sum(1 for f in sr.facets() if len(f.vertices()) == 4) # needs sage.rings.number_field 18 Its non exact version:: @@ -871,12 +876,13 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: sr = polytopes.small_rhombicuboctahedron(backend='normaliz') # optional - sage.rings.number_field pynormaliz - sage: sr.f_vector() # optional - sage.rings.number_field pynormaliz + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: sr = polytopes.small_rhombicuboctahedron(backend='normaliz') + sage: sr.f_vector() (1, 24, 48, 26, 1) - sage: sr.volume() # optional - sage.rings.number_field pynormaliz + sage: sr.volume() 80/3*sqrt2 + 32 - sage: TestSuite(sr).run() # long time # optional - sage.rings.number_field pynormaliz + sage: TestSuite(sr).run() # long time """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField @@ -918,8 +924,8 @@ def great_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: gr = polytopes.great_rhombicuboctahedron() # long time ~ 3sec # optional - sage.rings.number_field - sage: gr.f_vector() # long time # optional - sage.rings.number_field + sage: gr = polytopes.great_rhombicuboctahedron() # long time # needs sage.rings.number_field + sage: gr.f_vector() # long time # needs sage.rings.number_field (1, 48, 72, 26, 1) A faster implementation is obtained by setting ``exact=False``:: @@ -1072,28 +1078,28 @@ def truncated_cube(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: co = polytopes.truncated_cube() # optional - sage.rings.number_field - sage: co.f_vector() # optional - sage.rings.number_field + sage: co = polytopes.truncated_cube() # needs sage.rings.number_field + sage: co.f_vector() # needs sage.rings.number_field (1, 24, 36, 14, 1) Its facets are 8 triangles and 6 octogons:: - sage: sum(1 for f in co.facets() if len(f.vertices()) == 3) # optional - sage.rings.number_field + sage: sum(1 for f in co.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 8 - sage: sum(1 for f in co.facets() if len(f.vertices()) == 8) # optional - sage.rings.number_field + sage: sum(1 for f in co.facets() if len(f.vertices()) == 8) # needs sage.rings.number_field 6 Some more computation:: - sage: co.volume() # optional - sage.rings.number_field + sage: co.volume() # needs sage.rings.number_field 56/3*sqrt2 - 56/3 TESTS:: - sage: co = polytopes.truncated_cube(backend='normaliz') # optional - pynormaliz sage.rings.number_field - sage: co.f_vector() # optional - pynormaliz sage.rings.number_field + sage: co = polytopes.truncated_cube(backend='normaliz') # optional - pynormaliz, needs sage.rings.number_field + sage: co.f_vector() # optional - pynormaliz # needs sage.rings.number_field (1, 24, 36, 14, 1) - sage: TestSuite(co).run() # optional - pynormaliz sage.rings.number_field + sage: TestSuite(co).run() # optional - pynormaliz # needs sage.rings.number_field """ if base_ring is None and exact: @@ -1218,28 +1224,28 @@ def truncated_octahedron(self, backend=None): EXAMPLES:: - sage: co = polytopes.truncated_octahedron() # optional - sage.combinat - sage: co.f_vector() # optional - sage.combinat + sage: co = polytopes.truncated_octahedron() + sage: co.f_vector() (1, 24, 36, 14, 1) Its facets are 6 squares and 8 hexagons:: - sage: sum(1 for f in co.facets() if len(f.vertices()) == 4) # optional - sage.combinat + sage: sum(1 for f in co.facets() if len(f.vertices()) == 4) 6 - sage: sum(1 for f in co.facets() if len(f.vertices()) == 6) # optional - sage.combinat + sage: sum(1 for f in co.facets() if len(f.vertices()) == 6) 8 Some more computation:: - sage: co.volume() # optional - sage.combinat + sage: co.volume() 32 - sage: co.ehrhart_polynomial() # optional - latte_int sage.combinat + sage: co.ehrhart_polynomial() # optional - latte_int # needs sage.combinat 32*t^3 + 18*t^2 + 6*t + 1 TESTS:: - sage: to_norm = polytopes.truncated_octahedron(backend='normaliz') # optional - pynormaliz sage.combinat - sage: TestSuite(to_norm).run() # optional - pynormaliz sage.combinat + sage: to_norm = polytopes.truncated_octahedron(backend='normaliz') # optional - pynormaliz, needs sage.combinat + sage: TestSuite(to_norm).run() # optional - pynormaliz, needs sage.combinat """ v = [(0, e, f) for e in [-1, 1] for f in [-2, 2]] v = [(xyz[sigma(1) - 1], xyz[sigma(2) - 1], xyz[sigma(3) - 1]) @@ -1313,14 +1319,17 @@ def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): EXAMPLES:: - sage: sc_inexact = polytopes.snub_cube(exact=False); sc_inexact # optional - sage.groups + sage: # needs sage.groups + sage: sc_inexact = polytopes.snub_cube(exact=False); sc_inexact A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices - sage: sc_inexact.f_vector() # optional - sage.groups + sage: sc_inexact.f_vector() (1, 24, 60, 38, 1) - sage: sc_exact = polytopes.snub_cube(exact=True) # long time # optional - sage.groups sage.rings.number_field - sage: sc_exact.f_vector() # long time # optional - sage.groups sage.rings.number_field + + sage: # long time, needs sage.groups sage.rings.number_field + sage: sc_exact = polytopes.snub_cube(exact=True) + sage: sc_exact.f_vector() (1, 24, 60, 38, 1) - sage: sorted(sc_exact.vertices()) # long time # optional - sage.groups sage.rings.number_field + sage: sorted(sc_exact.vertices()) [A vertex at (-1, -z, -z^2), A vertex at (-1, -z^2, z), A vertex at (-1, z^2, -z), @@ -1345,13 +1354,13 @@ def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): A vertex at (1, -z^2, -z), A vertex at (1, z^2, z), A vertex at (1, z, -z^2)] - sage: sc_exact.is_combinatorially_isomorphic(sc_inexact) # long time # optional - sage.groups sage.rings.number_field + sage: sc_exact.is_combinatorially_isomorphic(sc_inexact) True TESTS:: - sage: sc = polytopes.snub_cube(exact=True, backend='normaliz') # optional - pynormaliz sage.groups sage.rings.number_field - sage: sc.f_vector() # optional - pynormaliz sage.groups sage.rings.number_field + sage: sc = polytopes.snub_cube(exact=True, backend='normaliz') # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: sc.f_vector() # optional - pynormaliz, needs sage.groups sage.rings.number_field (1, 24, 60, 38, 1) """ @@ -1416,34 +1425,35 @@ def buckyball(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: bb = polytopes.buckyball() # long time - 6secs # optional - sage.groups sage.rings.number_field - sage: bb.f_vector() # long time # optional - sage.groups sage.rings.number_field + sage: bb = polytopes.buckyball() # long time # needs sage.groups sage.rings.number_field + sage: bb.f_vector() # long time # needs sage.groups sage.rings.number_field (1, 60, 90, 32, 1) - sage: bb.base_ring() # long time # optional - sage.groups sage.rings.number_field + sage: bb.base_ring() # long time # needs sage.groups sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? A much faster implementation using floating point approximations:: - sage: bb = polytopes.buckyball(exact=False) # optional - sage.groups - sage: bb.f_vector() # optional - sage.groups + sage: bb = polytopes.buckyball(exact=False) # needs sage.groups + sage: bb.f_vector() # needs sage.groups (1, 60, 90, 32, 1) - sage: bb.base_ring() # optional - sage.groups + sage: bb.base_ring() # needs sage.groups Real Double Field Its facets are 5 regular pentagons and 6 regular hexagons:: - sage: sum(1 for f in bb.facets() if len(f.vertices()) == 5) # optional - sage.groups + sage: sum(1 for f in bb.facets() if len(f.vertices()) == 5) # needs sage.groups 12 - sage: sum(1 for f in bb.facets() if len(f.vertices()) == 6) # optional - sage.groups + sage: sum(1 for f in bb.facets() if len(f.vertices()) == 6) # needs sage.groups 20 TESTS:: - sage: bb = polytopes.buckyball(backend='normaliz') # optional - pynormaliz sage.groups sage.rings.number_field - sage: bb.f_vector() # optional - pynormaliz sage.groups sage.rings.number_field + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: bb = polytopes.buckyball(backend='normaliz') + sage: bb.f_vector() (1, 60, 90, 32, 1) - sage: bb.base_ring() # optional - pynormaliz sage.groups sage.rings.number_field + sage: bb.base_ring() Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? @@ -1467,26 +1477,27 @@ def icosidodecahedron(self, exact=True, backend=None): EXAMPLES:: - sage: id = polytopes.icosidodecahedron() # optional - sage.rings.number_field sage.groups - sage: id.f_vector() # optional - sage.rings.number_field sage.groups + sage: id = polytopes.icosidodecahedron() # needs sage.groups sage.rings.number_field + sage: id.f_vector() # needs sage.groups sage.rings.number_field (1, 30, 60, 32, 1) TESTS:: - sage: id = polytopes.icosidodecahedron(exact=False); id # optional - sage.rings.number_field sage.groups + sage: id = polytopes.icosidodecahedron(exact=False); id # needs sage.groups sage.rings.number_field A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 30 vertices - sage: TestSuite(id).run(skip=["_test_is_combinatorially_isomorphic", # optional - sage.rings.number_field sage.groups + sage: TestSuite(id).run(skip=["_test_is_combinatorially_isomorphic", # needs sage.groups sage.rings.number_field ....: "_test_product", ....: "_test_pyramid", ....: "_test_lawrence"]) - sage: id = polytopes.icosidodecahedron(backend='normaliz') # optional - pynormaliz sage.rings.number_field sage.groups - sage: id.f_vector() # optional - pynormaliz sage.rings.number_field sage.groups + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: id = polytopes.icosidodecahedron(backend='normaliz') + sage: id.f_vector() (1, 30, 60, 32, 1) - sage: id.base_ring() # optional - pynormaliz sage.rings.number_field sage.groups + sage: id.base_ring() Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: TestSuite(id).run() # long time # optional - pynormaliz sage.rings.number_field sage.groups + sage: TestSuite(id).run() # long time """ from sage.rings.number_field.number_field import QuadraticField from itertools import product @@ -1556,13 +1567,14 @@ def icosidodecahedron_V2(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: id = polytopes.icosidodecahedron_V2(backend='normaliz') # optional - pynormaliz - sage: id.f_vector() # optional - pynormaliz + sage: # optional - pynormaliz + sage: id = polytopes.icosidodecahedron_V2(backend='normaliz') + sage: id.f_vector() (1, 30, 60, 32, 1) - sage: id.base_ring() # optional - pynormaliz + sage: id.base_ring() Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: TestSuite(id).run() # long time # optional - pynormaliz + sage: TestSuite(id).run() # long time """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField @@ -1605,18 +1617,18 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: td = polytopes.truncated_dodecahedron() # optional - sage.rings.number_field - sage: td.f_vector() # optional - sage.rings.number_field + sage: td = polytopes.truncated_dodecahedron() # needs sage.rings.number_field + sage: td.f_vector() # needs sage.rings.number_field (1, 60, 90, 32, 1) - sage: td.base_ring() # optional - sage.rings.number_field + sage: td.base_ring() # needs sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? Its facets are 20 triangles and 12 regular decagons:: - sage: sum(1 for f in td.facets() if len(f.vertices()) == 3) # optional - sage.rings.number_field + sage: sum(1 for f in td.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 20 - sage: sum(1 for f in td.facets() if len(f.vertices()) == 10) # optional - sage.rings.number_field + sage: sum(1 for f in td.facets() if len(f.vertices()) == 10) # needs sage.rings.number_field 12 The faster implementation using floating point approximations does not @@ -1639,10 +1651,11 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: td = polytopes.truncated_dodecahedron(backend='normaliz') # optional - pynormaliz sage.rings.number_field - sage: td.f_vector() # optional - pynormaliz sage.rings.number_field + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: td = polytopes.truncated_dodecahedron(backend='normaliz') + sage: td.f_vector() (1, 60, 90, 32, 1) - sage: td.base_ring() # optional - pynormaliz sage.rings.number_field + sage: td.base_ring() Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? @@ -1701,15 +1714,15 @@ def pentakis_dodecahedron(self, exact=True, base_ring=None, backend=None): A much faster implementation is obtained when setting ``exact=False``:: - sage: pd = polytopes.pentakis_dodecahedron(exact=False) # optional - sage.groups - sage: pd.n_vertices() # optional - sage.groups + sage: pd = polytopes.pentakis_dodecahedron(exact=False) # needs sage.groups + sage: pd.n_vertices() # needs sage.groups 32 - sage: pd.n_inequalities() # optional - sage.groups + sage: pd.n_inequalities() # needs sage.groups 60 The 60 are triangles:: - sage: all(len(f.vertices()) == 3 for f in pd.facets()) # optional - sage.groups + sage: all(len(f.vertices()) == 3 for f in pd.facets()) # needs sage.groups True """ return self.buckyball(exact=exact, base_ring=base_ring, backend=backend).polar() @@ -1775,7 +1788,7 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: rid = polytopes.rhombicosidodecahedron() # long time - 6secs + sage: rid = polytopes.rhombicosidodecahedron() # long time (6secs) sage: rid.f_vector() # long time (1, 60, 120, 62, 1) sage: rid.base_ring() # long time @@ -1801,10 +1814,11 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: rid = polytopes.rhombicosidodecahedron(backend='normaliz') # optional - pynormaliz - sage: rid.f_vector() # optional - pynormaliz + sage: # optional - pynormaliz + sage: rid = polytopes.rhombicosidodecahedron(backend='normaliz') + sage: rid.f_vector() (1, 60, 120, 62, 1) - sage: rid.base_ring() # optional - pynormaliz + sage: rid.base_ring() Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? @@ -1881,7 +1895,7 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: sage: ti = polytopes.truncated_icosidodecahedron(backend='normaliz') # optional - pynormaliz - sage: ti.f_vector() # optional - pynormaliz + sage: ti.f_vector() (1, 120, 180, 62, 1) sage: ti.base_ring() # optional - pynormaliz Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? @@ -2242,22 +2256,23 @@ def six_hundred_cell(self, exact=False, backend=None): EXAMPLES:: - sage: p600 = polytopes.six_hundred_cell(); p600 # optional - sage.groups + sage: p600 = polytopes.six_hundred_cell(); p600 # needs sage.groups A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 120 vertices - sage: p600.f_vector() # long time ~2sec # optional - sage.groups + sage: p600.f_vector() # long time (~2sec) # needs sage.groups (1, 120, 720, 1200, 600, 1) Computation with exact coordinates is currently too long to be useful:: - sage: p600 = polytopes.six_hundred_cell(exact=True) # not tested - very long time, optional - sage.groups - sage: len(list(p600.bounded_edges())) # not tested - very long time, optional - sage.groups + sage: p600 = polytopes.six_hundred_cell(exact=True) # long time, not tested, needs sage.groups + sage: len(list(p600.bounded_edges())) # long time, not tested, needs sage.groups 720 TESTS:: - sage: p600 = polytopes.six_hundred_cell(exact=True, # optional - pynormaliz sage.groups sage.rings.number_field + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: p600 = polytopes.six_hundred_cell(exact=True, ....: backend='normaliz') - sage: len(list(p600.bounded_edges())) # long time # optional - pynormaliz sage.groups sage.rings.number_field + sage: len(list(p600.bounded_edges())) # long time 720 """ if exact: @@ -2313,8 +2328,8 @@ def grand_antiprism(self, exact=True, backend=None, verbose=False): Computation with the backend ``'normaliz'`` is instantaneous:: - sage: gap_norm = polytopes.grand_antiprism(backend='normaliz') # optional - pynormaliz sage.rings.number_field - sage: gap_norm # optional - pynormaliz sage.rings.number_field + sage: gap_norm = polytopes.grand_antiprism(backend='normaliz') # optional - pynormaliz, needs sage.rings.number_field + sage: gap_norm # optional - pynormaliz, needs sage.rings.number_field A 4-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as the convex hull of 100 vertices @@ -2470,21 +2485,23 @@ def hypersimplex(self, dim, k, project=False, backend=None): EXAMPLES:: - sage: h_4_2 = polytopes.hypersimplex(4, 2) # optional - sage.combinat - sage: h_4_2 # optional - sage.combinat + sage: # needs sage.combinat + sage: h_4_2 = polytopes.hypersimplex(4, 2) + sage: h_4_2 A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices - sage: h_4_2.f_vector() # optional - sage.combinat + sage: h_4_2.f_vector() (1, 6, 12, 8, 1) - sage: h_4_2.ehrhart_polynomial() # optional - latte_int sage.combinat + sage: h_4_2.ehrhart_polynomial() # optional - latte_int 2/3*t^3 + 2*t^2 + 7/3*t + 1 - sage: TestSuite(h_4_2).run() # optional - sage.combinat + sage: TestSuite(h_4_2).run() - sage: h_7_3 = polytopes.hypersimplex(7, 3, project=True) # optional - sage.combinat - sage: h_7_3 # optional - sage.combinat + sage: # needs sage.combinat + sage: h_7_3 = polytopes.hypersimplex(7, 3, project=True) + sage: h_7_3 A 6-dimensional polyhedron in RDF^6 defined as the convex hull of 35 vertices - sage: h_7_3.f_vector() # optional - sage.combinat + sage: h_7_3.f_vector() (1, 35, 210, 350, 245, 84, 14, 1) - sage: TestSuite(h_7_3).run(skip=["_test_pyramid", "_test_lawrence"]) # optional - sage.combinat + sage: TestSuite(h_7_3).run(skip=["_test_pyramid", "_test_lawrence"]) """ verts = Permutations([0] * (dim - k) + [1] * k).list() if project: @@ -2530,9 +2547,9 @@ def permutahedron(self, n, project=False, backend=None): sage: perm4 = polytopes.permutahedron(4, project=True) sage: perm4 A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices - sage: perm4.plot() # optional - sage.plot + sage: perm4.plot() # needs sage.plot Graphics3d Object - sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) # optional - sage.graphs + sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) # needs sage.graphs True As both Hrepresentation an Vrepresentation are known, the permutahedron can be set @@ -2610,35 +2627,36 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula EXAMPLES:: - sage: perm_a3 = polytopes.generalized_permutahedron(['A',3]); perm_a3 # optional - sage.combinat + sage: perm_a3 = polytopes.generalized_permutahedron(['A',3]); perm_a3 # needs sage.combinat A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices You can put the starting point along the hyperplane of the first generator:: - sage: perm_a3_011 = polytopes.generalized_permutahedron(['A',3], [0,1,1]) # optional - sage.combinat + sage: # needs sage.combinat + sage: perm_a3_011 = polytopes.generalized_permutahedron(['A',3], [0,1,1]) sage: perm_a3_011 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices - sage: perm_a3_110 = polytopes.generalized_permutahedron(['A',3], [1,1,0]) # optional - sage.combinat + sage: perm_a3_110 = polytopes.generalized_permutahedron(['A',3], [1,1,0]) sage: perm_a3_110 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices - sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_011) # optional - sage.combinat + sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_011) True - sage: perm_a3_101 = polytopes.generalized_permutahedron(['A',3], [1,0,1]) # optional - sage.combinat + sage: perm_a3_101 = polytopes.generalized_permutahedron(['A',3], [1,0,1]) sage: perm_a3_101 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices - sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_101) # optional - sage.combinat + sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_101) False - sage: perm_a3_011.f_vector() # optional - sage.combinat + sage: perm_a3_011.f_vector() (1, 12, 18, 8, 1) - sage: perm_a3_101.f_vector() # optional - sage.combinat + sage: perm_a3_101.f_vector() (1, 12, 24, 14, 1) The usual output does not necessarily give a polyhedron with isometric vertex figures:: - sage: perm_a2 = polytopes.generalized_permutahedron(['A',2]) # optional - sage.combinat - sage: perm_a2.vertices() # optional - sage.combinat + sage: perm_a2 = polytopes.generalized_permutahedron(['A',2]) # needs sage.combinat + sage: perm_a2.vertices() # needs sage.combinat (A vertex at (-1, -1), A vertex at (-1, 0), A vertex at (0, -1), @@ -2648,8 +2666,8 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula It works also with Coxeter types that lead to non-rational coordinates:: - sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]) # long time # optional - sage.combinat sage.rings.number_field - sage: perm_b3 # long time # optional - sage.combinat sage.rings.number_field + sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]) # long time, needs sage.combinat sage.rings.number_field + sage: perm_b3 # long time, needs sage.combinat sage.rings.number_field A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 defined as the convex hull of 48 vertices @@ -2659,9 +2677,9 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula rational coordinates. We first do the computations using floating point approximations (``RDF``):: - sage: perm_a2_inexact = polytopes.generalized_permutahedron( # optional - sage.combinat + sage: perm_a2_inexact = polytopes.generalized_permutahedron( # needs sage.combinat ....: ['A',2], exact=False) - sage: sorted(perm_a2_inexact.vertices()) # optional - sage.combinat + sage: sorted(perm_a2_inexact.vertices()) # needs sage.combinat [A vertex at (-1.0, -1.0), A vertex at (-1.0, 0.0), A vertex at (0.0, -1.0), @@ -2669,9 +2687,9 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1.0, 0.0), A vertex at (1.0, 1.0)] - sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron( # optional - sage.combinat + sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron( # needs sage.combinat ....: ['A',2], exact=False, regular=True) - sage: sorted(perm_a2_inexact_reg.vertices()) # optional - sage.combinat + sage: sorted(perm_a2_inexact_reg.vertices()) # needs sage.combinat [A vertex at (-1.0, 0.0), A vertex at (-0.5, -0.8660254038), A vertex at (-0.5, 0.8660254038), @@ -2681,9 +2699,9 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula We can do the same computation using exact arithmetic with the field ``AA``:: - sage: perm_a2_reg = polytopes.generalized_permutahedron( # optional - sage.combinat sage.rings.number_field + sage: perm_a2_reg = polytopes.generalized_permutahedron( # needs sage.combinat sage.rings.number_field ....: ['A',2], regular=True) - sage: V = sorted(perm_a2_reg.vertices()); V # random # optional - sage.combinat sage.rings.number_field + sage: V = sorted(perm_a2_reg.vertices()); V # random # needs sage.combinat sage.rings.number_field [A vertex at (-1, 0), A vertex at (-1/2, -0.866025403784439?), A vertex at (-1/2, 0.866025403784439?), @@ -2694,61 +2712,65 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula Even though the numbers look like floating point approximations, the computation is actually exact. We can clean up the display a bit using ``exactify``:: - sage: for v in V: # optional - sage.combinat sage.rings.number_field + sage: for v in V: # needs sage.combinat sage.rings.number_field ....: for x in v: ....: x.exactify() - sage: V # optional - sage.combinat sage.rings.number_field + sage: V # needs sage.combinat sage.rings.number_field [A vertex at (-1, 0), A vertex at (-1/2, -0.866025403784439?), A vertex at (-1/2, 0.866025403784439?), A vertex at (1/2, -0.866025403784439?), A vertex at (1/2, 0.866025403784439?), A vertex at (1, 0)] - sage: perm_a2_reg.is_inscribed() # optional - sage.combinat sage.rings.number_field + sage: perm_a2_reg.is_inscribed() # needs sage.combinat sage.rings.number_field True Larger examples take longer:: - sage: perm_a3_reg = polytopes.generalized_permutahedron( # long time # optional - sage.rings.number_field sage.combinat + sage: # needs sage.combinat sage.rings.number_field + sage: perm_a3_reg = polytopes.generalized_permutahedron( # long time ....: ['A',3], regular=True); perm_a3_reg A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg.is_inscribed() # long time # optional - sage.rings.number_field sage.combinat + sage: perm_a3_reg.is_inscribed() # long time True - sage: perm_b3_reg = polytopes.generalized_permutahedron( # not tested # optional - sage.rings.number_field sage.combinat # long time (12sec on 64 bits) + sage: perm_b3_reg = polytopes.generalized_permutahedron( # long time (12sec on 64 bits), not tested ....: ['B',3], regular=True); perm_b3_reg A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices It is faster with the backend ``'number_field'``, which internally uses an embedded number field instead of doing the computations directly with the base ring (``AA``):: - sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( # optional - sage.rings.number_field sage.combinat + sage: # needs sage.combinat sage.rings.number_field + sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( ....: ['A',3], regular=True, backend='number_field'); perm_a3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg_nf.is_inscribed() # optional - sage.rings.number_field sage.combinat + sage: perm_a3_reg_nf.is_inscribed() True - sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time # optional - sage.rings.number_field sage.combinat + sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time ....: ['B',3], regular=True, backend='number_field'); perm_b3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices It is even faster with the backend ``'normaliz'``:: - sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz sage.rings.number_field sage.combinat + sage: # optional - pynormaliz, needs sage.combinat sage.rings.number_field + sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( ....: ['A',3], regular=True, backend='normaliz'); perm_a3_reg_norm A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg_norm.is_inscribed() # optional - pynormaliz sage.rings.number_field sage.combinat + sage: perm_a3_reg_norm.is_inscribed() True - sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz sage.rings.number_field sage.combinat + sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( ....: ['B',3], regular=True, backend='normaliz'); perm_b3_reg_norm A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices The speedups from using backend ``'normaliz'`` allow us to go even further:: - sage: perm_h3 = polytopes.generalized_permutahedron( # optional - pynormaliz sage.rings.number_field sage.combinat + sage: # optional - pynormaliz, needs sage.combinat sage.rings.number_field + sage: perm_h3 = polytopes.generalized_permutahedron( ....: ['H',3], backend='normaliz'); perm_h3 A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 defined as the convex hull of 120 vertices - sage: perm_f4 = polytopes.generalized_permutahedron( # long time, optional - pynormaliz sage.rings.number_field sage.combinat + sage: perm_f4 = polytopes.generalized_permutahedron( # long time ....: ['F',4], backend='normaliz'); perm_f4 A 4-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 @@ -2761,7 +2783,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula TESTS:: - sage: TestSuite(perm_h3).run() # optional - pynormaliz sage.rings.number_field sage.combinat + sage: TestSuite(perm_h3).run() # optional - pynormaliz # needs sage.combinat sage.rings.number_field """ from sage.combinat.root_system.coxeter_group import CoxeterGroup try: @@ -3247,15 +3269,15 @@ def hypercube(self, dim, intervals=None, backend=None): sage: ls = [randint(-100,100) for _ in range(4)] sage: intervals = [[x, x+randint(1,50)] for x in ls] sage: P = polytopes.hypercube(4, intervals, backend='field') - sage: P1 = polytopes.hypercube(4, intervals, backend='ppl') # optional - pplpy - sage: assert P == P1 + sage: P1 = polytopes.hypercube(4, intervals, backend='ppl') # needs pplpy + sage: assert P == P1 # needs pplpy Check that coercion for input invervals is handled correctly:: sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1]]) sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]]) - sage: P = polytopes.hypercube(2, [[1/2, 2], [0, AA(2).sqrt()]]) # optional - sage.rings.number_field - sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]], backend='ppl') # optional - pplpy + sage: P = polytopes.hypercube(2, [[1/2, 2], [0, AA(2).sqrt()]]) # needs sage.rings.number_field + sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]], backend='ppl') # needs pplpy Traceback (most recent call last): ... ValueError: specified backend ppl cannot handle the intervals @@ -3357,7 +3379,7 @@ def cube(self, intervals=None, backend=None): (1, 8, 12, 6, 1) sage: c.volume() 8 - sage: c.plot() # optional - sage.plot + sage: c.plot() # needs sage.plot Graphics3d Object Return the `0/1`-cube:: @@ -3441,16 +3463,16 @@ def parallelotope(self, generators, backend=None): sage: polytopes.parallelotope([[1,2,3,4], [0,1,0,7], [3,1,0,2], [0,0,1,0]]) A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 16 vertices - sage: K = QuadraticField(2, 'sqrt2') # optional - sage.rings.number_field - sage: sqrt2 = K.gen() # optional - sage.rings.number_field - sage: P = polytopes.parallelotope([(1, sqrt2), (1, -1)]); P # optional - sage.rings.number_field + sage: K = QuadraticField(2, 'sqrt2') # needs sage.rings.number_field + sage: sqrt2 = K.gen() # needs sage.rings.number_field + sage: P = polytopes.parallelotope([(1, sqrt2), (1, -1)]); P # needs sage.rings.number_field A 2-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 4 vertices TESTS:: - sage: TestSuite(P).run() # optional - sage.rings.number_field + sage: TestSuite(P).run() # needs sage.rings.number_field """ from sage.modules.free_module_element import vector generators = [vector(v) for v in generators] diff --git a/src/sage/geometry/polyhedron/misc.py b/src/sage/geometry/polyhedron/misc.py index ad0ad961bf1..b47e51f79b8 100644 --- a/src/sage/geometry/polyhedron/misc.py +++ b/src/sage/geometry/polyhedron/misc.py @@ -30,7 +30,7 @@ def _to_space_separated_string(l, base_ring=None): sage: import sage.geometry.polyhedron.misc as P sage: P._to_space_separated_string([2,3]) '2 3' - sage: P._to_space_separated_string([2, 1/5], RDF) # optional - sage.rings.real_double + sage: P._to_space_separated_string([2, 1/5], RDF) # needs sage.rings.real_double '2.0 0.2' """ if base_ring: diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 70864270966..29b729cec18 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -5,7 +5,7 @@ EXAMPLES:: sage: from sage.geometry.polyhedron.palp_database import PALPreader - sage: for lp in PALPreader(2): + sage: for lp in PALPreader(2): # needs sage.graphs ....: cone = Cone([(1,r[0],r[1]) for r in lp.vertices()]) ....: fan = Fan([cone]) ....: X = ToricVariety(fan) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 739a4e3edbb..92691fab081 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -64,7 +64,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(AA, 3) # optional - sage.rings.number_field + sage: Polyhedra(AA, 3) # needs sage.rings.number_field Polyhedra in AA^3 sage: Polyhedra(ZZ, 3) Polyhedra in ZZ^3 @@ -96,34 +96,34 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * TESTS:: - sage: Polyhedra(RR, 3, backend='field') # optional - sage.rings.real_mpfr + sage: Polyhedra(RR, 3, backend='field') # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: the 'field' backend for polyhedron cannot be used with non-exact fields - sage: Polyhedra(RR, 3) # optional - sage.rings.real_mpfr + sage: Polyhedra(RR, 3) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision - sage: Polyhedra(QQ[I], 2) # optional - sage.rings.number_field + sage: Polyhedra(QQ[I], 2) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: invalid base ring: Number Field in I with defining polynomial x^2 + 1 with I = 1*I cannot be coerced to a real field - sage: Polyhedra(AA, 3, backend='polymake') # optional - jupymake sage.rings.number_field + sage: Polyhedra(AA, 3, backend='polymake') # optional - jupymake # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the 'polymake' backend for polyhedron cannot be used with Algebraic Real Field - sage: Polyhedra(QQ, 2, backend='normaliz') # optional - pynormaliz + sage: Polyhedra(QQ, 2, backend='normaliz') Polyhedra in QQ^2 - sage: Polyhedra(SR, 2, backend='normaliz') # optional - pynormaliz sage.symbolic + sage: Polyhedra(SR, 2, backend='normaliz') # optional - pynormaliz # needs sage.symbolic Polyhedra in (Symbolic Ring)^2 - sage: SCR = SR.subring(no_variables=True) # optional - sage.symbolic - sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz sage.symbolic + sage: SCR = SR.subring(no_variables=True) # needs sage.symbolic + sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz # needs sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 - sage: Polyhedra(SCR, 2, backend='number_field') # optional - sage.symbolic + sage: Polyhedra(SCR, 2, backend='number_field') # needs sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 """ @@ -272,13 +272,14 @@ def list(self): sage: P.cardinality() +Infinity - sage: P = Polyhedra(AA, 0) # optional - sage.rings.number_field - sage: P.category() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = Polyhedra(AA, 0) + sage: P.category() Category of finite enumerated polyhedral sets over Algebraic Real Field - sage: P.list() # optional - sage.rings.number_field + sage: P.list() [The empty polyhedron in AA^0, A 0-dimensional polyhedron in AA^0 defined as the convex hull of 1 vertex] - sage: P.cardinality() # optional - sage.rings.number_field + sage: P.cardinality() 2 """ if self.ambient_dim(): @@ -516,8 +517,8 @@ def _repr_base_ring(self): sage: Polyhedra(QQ, 3)._repr_base_ring() 'QQ' sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field - sage: Polyhedra(K, 4)._repr_base_ring() # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # needs sage.rings.number_field + sage: Polyhedra(K, 4)._repr_base_ring() # needs sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)' """ @@ -551,8 +552,8 @@ def _repr_ambient_module(self): sage: Polyhedra(QQ, 3)._repr_ambient_module() 'QQ^3' sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field - sage: Polyhedra(K, 4)._repr_ambient_module() # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # needs sage.rings.number_field + sage: Polyhedra(K, 4)._repr_ambient_module() # needs sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^4' """ s = self._repr_base_ring() @@ -607,13 +608,14 @@ def _element_constructor_(self, *args, **kwds): Check that :trac:`21270` is fixed:: - sage: poly = polytopes.regular_polygon(7) # optional - sage.rings.number_field - sage: lp, x = poly.to_linear_program(solver='InteractiveLP', # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: poly = polytopes.regular_polygon(7) + sage: lp, x = poly.to_linear_program(solver='InteractiveLP', ....: return_variable=True) - sage: lp.set_objective(x[0] + x[1]) # optional - sage.rings.number_field - sage: b = lp.get_backend() # optional - sage.rings.number_field - sage: P = b.interactive_lp_problem() # optional - sage.rings.number_field - sage: p = P.plot() # optional - sage.plot sage.rings.number_field + sage: lp.set_objective(x[0] + x[1]) + sage: b = lp.get_backend() + sage: P = b.interactive_lp_problem() + sage: p = P.plot() # needs sage.plot sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]]) sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF) @@ -635,11 +637,12 @@ def _element_constructor_(self, *args, **kwds): When the parent of the object is not ``self``, the default is not to copy:: - sage: Q = P.base_extend(AA) # optional - sage.rings.number_field - sage: q = Q._element_constructor_(p) # optional - sage.rings.number_field - sage: q is p # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Q = P.base_extend(AA) + sage: q = Q._element_constructor_(p) + sage: q is p False - sage: q = Q._element_constructor_(p, copy=False) # optional - sage.rings.number_field + sage: q = Q._element_constructor_(p, copy=False) Traceback (most recent call last): ... ValueError: you need to make a copy when changing the parent @@ -726,10 +729,10 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): sage: P(p) A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: P = Polyhedra(AA, 3, backend='field') # optional - sage.rings.number_field + sage: P = Polyhedra(AA, 3, backend='field') # needs sage.rings.number_field sage: vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)] - sage: p = Polyhedron(vertices=vertices) # optional - sage.rings.number_field - sage: P(p) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=vertices) + sage: P(p) # needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices """ Vrep = None @@ -866,15 +869,15 @@ def _coerce_base_ring(self, other): Test that :trac:`28770` is fixed:: sage: z = QQ['z'].0 - sage: K = NumberField(z^2 - 2, 's') # optional - sage.rings.number_field - sage: triangle_QQ._coerce_base_ring(K) # optional - sage.rings.number_field + sage: K = NumberField(z^2 - 2, 's') # needs sage.rings.number_field + sage: triangle_QQ._coerce_base_ring(K) # needs sage.rings.number_field Number Field in s with defining polynomial z^2 - 2 - sage: triangle_QQ._coerce_base_ring(K.gen()) # optional - sage.rings.number_field + sage: triangle_QQ._coerce_base_ring(K.gen()) # needs sage.rings.number_field Number Field in s with defining polynomial z^2 - 2 sage: z = QQ['z'].0 - sage: K = NumberField(z^2 - 2, 's') # optional - sage.rings.number_field - sage: K.gen() * polytopes.simplex(backend='field') # optional - sage.rings.number_field + sage: K = NumberField(z^2 - 2, 's') # needs sage.rings.number_field + sage: K.gen() * polytopes.simplex(backend='field') # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in s with defining polynomial z^2 - 2)^4 defined as the convex hull of 4 vertices @@ -1286,9 +1289,9 @@ def does_backend_handle_base_ring(base_ring, backend): sage: from sage.geometry.polyhedron.parent import does_backend_handle_base_ring sage: does_backend_handle_base_ring(QQ, 'ppl') True - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') # optional - sage.rings.number_field sage.symbolic + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') # needs sage.rings.number_field sage.symbolic False - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') # optional - sage.rings.number_field sage.symbolic + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') # needs sage.rings.number_field sage.symbolic True """ try: diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 472ab1cf8c2..b6bb235b711 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -346,23 +346,24 @@ def __init__(self, polyhedron, proj=projection_func_identity): EXAMPLES:: - sage: p = polytopes.icosahedron(exact=False) # optional - sage.groups + sage: # needs sage.groups + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection - sage: Projection(p) # optional - sage.groups + sage: Projection(p) The projection of a polyhedron into 3 dimensions sage: def pr_12(x): return [x[1],x[2]] - sage: Projection(p, pr_12) # optional - sage.groups + sage: Projection(p, pr_12) The projection of a polyhedron into 2 dimensions - sage: Projection(p, lambda x: [x[1],x[2]] ) # another way of doing the same projection # optional - sage.groups + sage: Projection(p, lambda x: [x[1],x[2]] ) # another way of doing the same projection The projection of a polyhedron into 2 dimensions - sage: _.plot() # plot of the projected icosahedron in 2d # optional - sage.plot # optional - sage.groups + sage: _.plot() # plot of the projected icosahedron in 2d # needs sage.plot Graphics object consisting of 51 graphics primitives - sage: proj = Projection(p) # optional - sage.groups - sage: proj.stereographic([1,2,3]) # optional - sage.groups + sage: proj = Projection(p) + sage: proj.stereographic([1,2,3]) The projection of a polyhedron into 2 dimensions - sage: proj.plot() # optional - sage.plot # optional - sage.groups + sage: proj.plot() # needs sage.plot Graphics object consisting of 51 graphics primitives - sage: TestSuite(proj).run(skip='_test_pickling') # optional - sage.groups + sage: TestSuite(proj).run(skip='_test_pickling') """ self.parent_polyhedron = polyhedron self.coords = Sequence([]) @@ -411,12 +412,13 @@ def __call__(self, proj=projection_func_identity): EXAMPLES:: - sage: p = polytopes.icosahedron(exact=False) # optional - sage.groups + sage: # needs sage.groups + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection - sage: pproj = Projection(p) # optional - sage.groups + sage: pproj = Projection(p) sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic - sage: pproj_stereo = pproj.__call__(proj=ProjectionFuncStereographic([1, 2, 3])) # optional - sage.groups - sage: sorted(pproj_stereo.polygons) # optional - sage.groups + sage: pproj_stereo = pproj.__call__(proj=ProjectionFuncStereographic([1, 2, 3])) + sage: sorted(pproj_stereo.polygons) [[2, 0, 9], [3, 1, 10], [4, 0, 8], @@ -435,11 +437,12 @@ def identity(self): EXAMPLES:: - sage: p = polytopes.icosahedron(exact=False) # optional - sage.groups + sage: # needs sage.groups + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection - sage: pproj = Projection(p) # optional - sage.groups - sage: ppid = pproj.identity() # optional - sage.groups - sage: ppid.dimension # optional - sage.groups + sage: pproj = Projection(p) + sage: ppid = pproj.identity() + sage: ppid.dimension 3 """ return self(projection_func_identity) @@ -458,7 +461,7 @@ def stereographic(self, projection_point=None): sage: from sage.geometry.polyhedron.plot import Projection sage: proj = Projection(polytopes.buckyball()); proj # long time The projection of a polyhedron into 3 dimensions - sage: proj.stereographic([5,2,3]).plot() # long time # optional - sage.plot + sage: proj.stereographic([5,2,3]).plot() # long time # needs sage.plot Graphics object consisting of 123 graphics primitives sage: Projection(polytopes.twenty_four_cell()).stereographic([2,0,0,0]) The projection of a polyhedron into 3 dimensions @@ -495,7 +498,7 @@ def schlegel(self, facet=None, position=None): sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(cube4).schlegel() The projection of a polyhedron into 3 dimensions - sage: _.plot() # optional - sage.plot + sage: _.plot() # needs sage.plot Graphics3d Object The 4-cube with a truncated vertex seen into the resulting tetrahedron @@ -504,14 +507,14 @@ def schlegel(self, facet=None, position=None): sage: tcube4 = cube4.face_truncation(cube4.faces(0)[0]) sage: tcube4.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices - sage: into_tetra = Projection(tcube4).schlegel(tcube4.facets()[4]) # optional - sage.symbolic - sage: into_tetra.plot() # optional - sage.plot sage.symbolic + sage: into_tetra = Projection(tcube4).schlegel(tcube4.facets()[4]) # needs sage.symbolic + sage: into_tetra.plot() # needs sage.plot sage.symbolic Graphics3d Object Taking a larger value for the position changes the image:: - sage: into_tetra_far = Projection(tcube4).schlegel(tcube4.facets()[4], 4) # optional - sage.symbolic - sage: into_tetra_far.plot() # optional - sage.plot sage.symbolic + sage: into_tetra_far = Projection(tcube4).schlegel(tcube4.facets()[4], 4) # needs sage.symbolic + sage: into_tetra_far.plot() # needs sage.plot sage.symbolic Graphics3d Object A value which is too large or negative give a projection point that @@ -917,8 +920,8 @@ def render_points_1d(self, **kwds): sage: cube1 = polytopes.hypercube(1) sage: proj = cube1.projection() - sage: points = proj.render_points_1d() # optional - sage.plot - sage: points._objects # optional - sage.plot + sage: points = proj.render_points_1d() # needs sage.plot + sage: points._objects # needs sage.plot [Point set defined by 2 point(s)] """ return point2d([c + [0] for c in self.coordinates_of(self.points)], **kwds) @@ -938,8 +941,8 @@ def render_line_1d(self, **kwds): EXAMPLES:: - sage: outline = polytopes.hypercube(1).projection().render_line_1d() # optional - sage.plot - sage: outline._objects[0] # optional - sage.plot + sage: outline = polytopes.hypercube(1).projection().render_line_1d() # needs sage.plot + sage: outline._objects[0] # needs sage.plot Line defined by 2 points """ if len(self.lines) == 0: @@ -956,10 +959,11 @@ def render_points_2d(self, **kwds): EXAMPLES:: - sage: hex = polytopes.regular_polygon(6) # optional - sage.rings.number_field - sage: proj = hex.projection() # optional - sage.rings.number_field - sage: hex_points = proj.render_points_2d() # optional - sage.plot sage.rings.number_field - sage: hex_points._objects # optional - sage.plot sage.rings.number_field + sage: # needs sage.rings.number_field + sage: hex = polytopes.regular_polygon(6) + sage: proj = hex.projection() + sage: hex_points = proj.render_points_2d() # needs sage.plot + sage: hex_points._objects # needs sage.plot [Point set defined by 6 point(s)] """ return point2d(self.coordinates_of(self.points), **kwds) @@ -970,9 +974,9 @@ def render_outline_2d(self, **kwds): EXAMPLES:: - sage: penta = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: outline = penta.projection().render_outline_2d() # optional - sage.plot sage.rings.number_field - sage: outline._objects[0] # optional - sage.plot sage.rings.number_field + sage: penta = polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: outline = penta.projection().render_outline_2d() # needs sage.plot sage.rings.number_field + sage: outline._objects[0] # needs sage.plot sage.rings.number_field Line defined by 2 points """ wireframe = [] @@ -993,8 +997,8 @@ def render_fill_2d(self, **kwds): sage: cps = [i^3 for i in srange(-2, 2, 1/5)] sage: p = Polyhedron(vertices=[[(t^2-1)/(t^2+1), 2*t/(t^2+1)] for t in cps]) sage: proj = p.projection() - sage: filled_poly = proj.render_fill_2d() # optional - sage.plot - sage: filled_poly.axes_width() # optional - sage.plot + sage: filled_poly = proj.render_fill_2d() # needs sage.plot + sage: filled_poly.axes_width() # needs sage.plot 0.8 """ poly = [polygon2d(self.coordinates_of(p), **kwds) @@ -1009,8 +1013,8 @@ def render_vertices_3d(self, **kwds): sage: p = polytopes.cross_polytope(3) sage: proj = p.projection() - sage: verts = proj.render_vertices_3d() # optional - sage.plot - sage: verts.bounding_box() # optional - sage.plot + sage: verts = proj.render_vertices_3d() # needs sage.plot + sage: verts.bounding_box() # needs sage.plot ((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0)) """ return point3d(self.coordinates_of(self.points), **kwds) @@ -1023,8 +1027,8 @@ def render_wireframe_3d(self, **kwds): sage: cube = polytopes.hypercube(3) sage: cube_proj = cube.projection() - sage: wire = cube_proj.render_wireframe_3d() # optional - sage.plot - sage: print(wire.tachyon().split('\n')[77]) # for testing # optional - sage.plot + sage: wire = cube_proj.render_wireframe_3d() # needs sage.plot + sage: print(wire.tachyon().split('\n')[77]) # for testing # needs sage.plot FCylinder base 1.0 1.0 -1.0 apex -1.0 1.0 -1.0 rad 0.005 texture... """ wireframe = [] @@ -1043,8 +1047,8 @@ def render_solid_3d(self, **kwds): EXAMPLES:: sage: p = polytopes.hypercube(3).projection() - sage: p_solid = p.render_solid_3d(opacity=.7) # optional - sage.plot - sage: type(p_solid) # optional - sage.plot + sage: p_solid = p.render_solid_3d(opacity=.7) # needs sage.plot + sage: type(p_solid) # needs sage.plot """ polys = self.polygons @@ -1074,10 +1078,10 @@ def render_0d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: print(Polyhedron([]).projection().render_0d().description()) # optional - sage.plot + sage: print(Polyhedron([]).projection().render_0d().description()) # needs sage.plot sage: P = Polyhedron(ieqs=[(1,)]) - sage: print(P.projection().render_0d().description()) # optional - sage.plot + sage: print(P.projection().render_0d().description()) # needs sage.plot Point set defined by 1 point(s): [(0.0, 0.0)] """ if point_opts is None: @@ -1106,7 +1110,7 @@ def render_1d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: Polyhedron([(0,), (1,)]).projection().render_1d() # optional - sage.plot + sage: Polyhedron([(0,), (1,)]).projection().render_1d() # needs sage.plot Graphics object consisting of 2 graphics primitives """ plt = Graphics() @@ -1138,7 +1142,7 @@ def render_2d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: q3 = p3.projection() sage: p4 = Polyhedron(vertices=[[2,0]], rays=[[1,-1]], lines=[[1,1]]) sage: q4 = p4.projection() - sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() # optional - sage.plot + sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() # needs sage.plot Graphics object consisting of 18 graphics primitives """ plt = Graphics() @@ -1171,31 +1175,32 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: p2 = Polyhedron(vertices=[[2,0,0], [0,2,0], [0,0,2]]) sage: p3 = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], ....: rays=[[-1,-1,-1]]) - sage: (p1.projection().plot() + p2.projection().plot() # optional - sage.plot + sage: (p1.projection().plot() + p2.projection().plot() # needs sage.plot ....: + p3.projection().plot()) Graphics3d Object It correctly handles various degenerate cases:: - sage: Polyhedron(lines=[[1,0,0], [0,1,0], [0,0,1]]).plot() # whole space # optional - sage.plot + sage: # needs sage.plot + sage: Polyhedron(lines=[[1,0,0], [0,1,0], [0,0,1]]).plot() # whole space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], # optional - sage.plot + sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], ....: lines=[[0,1,0], [0,0,1]]).plot() # half space Graphics3d Object - sage: Polyhedron(lines=[[0,1,0], [0,0,1]], # optional - sage.plot + sage: Polyhedron(lines=[[0,1,0], [0,0,1]], ....: vertices=[[1,1,1]]).plot() # R^2 in R^3 Graphics3d Object - sage: Polyhedron(rays=[[0,1,0], [0,0,1]], # quadrant wedge in R^2 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0], [0,0,1]], # quadrant wedge in R^2 ....: lines=[[1,0,0]]).plot() Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]], # upper half plane in R^3 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0]], # upper half plane in R^3 ....: lines=[[1,0,0]]).plot() Graphics3d Object - sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 # optional - sage.plot + sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 # optional - sage.plot + sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 Graphics3d Object The origin is not included, if it is not in the polyhedron (:trac:`23555`):: @@ -1203,13 +1208,13 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: Q = Polyhedron([[100],[101]]) sage: P = Q*Q*Q; P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices - sage: p = P.plot() # optional - sage.plot - sage: p.bounding_box() # optional - sage.plot + sage: p = P.plot() # needs sage.plot + sage: p.bounding_box() # needs sage.plot ((100.0, 100.0, 100.0), (101.0, 101.0, 101.0)) Plot 3d polytope with rainbow colors:: - sage: polytopes.hypercube(3).plot(polygon='rainbow', alpha=0.4) # optional - sage.plot + sage: polytopes.hypercube(3).plot(polygon='rainbow', alpha=0.4) # needs sage.plot Graphics3d Object """ pplt = None @@ -1300,12 +1305,13 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: - sage: P1 = polytopes.small_rhombicuboctahedron() # optional - sage.rings.number_field - sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4, # optional - sage.rings.number_field + sage: # needs sage.plot sage.rings.number_field + sage: P1 = polytopes.small_rhombicuboctahedron() + sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4, ....: output_type='TikzPicture') - sage: type(Image1) # optional - sage.rings.number_field + sage: type(Image1) - sage: Image1 # optional - sage.rings.number_field + sage: Image1 \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -1322,10 +1328,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: _ = Image1.tex('polytope-tikz1.tex') # not tested # optional - sage.rings.number_field - sage: _ = Image1.png('polytope-tikz1.png') # not tested # optional - sage.rings.number_field - sage: _ = Image1.pdf('polytope-tikz1.pdf') # not tested # optional - sage.rings.number_field - sage: _ = Image1.svg('polytope-tikz1.svg') # not tested # optional - sage.rings.number_field + sage: _ = Image1.tex('polytope-tikz1.tex') # not tested + sage: _ = Image1.png('polytope-tikz1.png') # not tested + sage: _ = Image1.pdf('polytope-tikz1.pdf') # not tested + sage: _ = Image1.svg('polytope-tikz1.svg') # not tested A second example:: @@ -1354,6 +1360,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, The second example using a LatexExpr as output type:: + sage: # needs sage.plot sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', ....: facet_color='orange!95!black', opacity=0.4, ....: vertex_color='yellow', axis=True, @@ -1365,19 +1372,20 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, [scale=3.000000, back/.style={loosely dotted, thin}, edge/.style={color=blue!95!black, thick}, - sage: with open('polytope-tikz2.tex', 'w') as f: # not tested + sage: with open('polytope-tikz2.tex', 'w') as f: # not tested ....: _ = f.write(Image2) A third example:: + sage: # needs sage.plot sage: P3 = Polyhedron(vertices=[[-1, -1, 2], [-1, 2, -1], [2, -1, -1]]); P3 A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: Image3 = P3.projection().tikz([0.5, -1, -0.1], 55, scale=3, # optional - sage.plot + sage: Image3 = P3.projection().tikz([0.5, -1, -0.1], 55, scale=3, ....: edge_color='blue!95!black', ....: facet_color='orange!95!black', opacity=0.7, ....: vertex_color='yellow', axis=True, ....: output_type='TikzPicture') - sage: Image3 # optional - sage.plot + sage: Image3 \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -1394,10 +1402,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: _ = Image3.tex('polytope-tikz3.tex') # not tested # optional - sage.plot - sage: _ = Image3.png('polytope-tikz3.png') # not tested # optional - sage.plot - sage: _ = Image3.pdf('polytope-tikz3.pdf') # not tested # optional - sage.plot - sage: _ = Image3.svg('polytope-tikz3.svg') # not tested # optional - sage.plot + sage: _ = Image3.tex('polytope-tikz3.tex') # not tested + sage: _ = Image3.png('polytope-tikz3.png') # not tested + sage: _ = Image3.pdf('polytope-tikz3.pdf') # not tested + sage: _ = Image3.svg('polytope-tikz3.svg') # not tested A fourth example:: @@ -1618,26 +1626,26 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, EXAMPLES:: - sage: P = Polyhedron(vertices=[[-1, -1, 2], [-1, 2, -1], [2, -1, -1]]) - sage: P + sage: # needs sage.plot + sage: P = Polyhedron(vertices=[[-1, -1, 2], [-1, 2, -1], [2, -1, -1]]); P A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: Image = P.projection()._tikz_2d_in_3d(view=[0.5, -1, -0.5], angle=55, scale=3, # optional - sage.plot + sage: Image = P.projection()._tikz_2d_in_3d(view=[0.5, -1, -0.5], angle=55, scale=3, ....: edge_color='blue!95!black', facet_color='orange', ....: opacity=0.5, vertex_color='yellow', axis=True) - sage: print('\n'.join(Image.splitlines()[:4])) # optional - sage.plot + sage: print('\n'.join(Image.splitlines()[:4])) \begin{tikzpicture}% [x={(0.644647cm, -0.476559cm)}, y={(0.192276cm, 0.857859cm)}, z={(-0.739905cm, -0.192276cm)}, - sage: with open('polytope-tikz3.tex', 'w') as f: # not tested # optional - sage.plot + sage: with open('polytope-tikz3.tex', 'w') as f: # not tested ....: _ = f.write(Image) :: sage: p = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) sage: proj = p.projection() - sage: Img = proj.tikz([1, 1, 1], 130, axis=True, output_type='LatexExpr') # optional - sage.plot - sage: print('\n'.join(Img.splitlines()[12:21])) # optional - sage.plot + sage: Img = proj.tikz([1, 1, 1], 130, axis=True, output_type='LatexExpr') # needs sage.plot + sage: print('\n'.join(Img.splitlines()[12:21])) # needs sage.plot %% with the command: ._tikz_2d_in_3d and parameters: %% view = [1, 1, 1] %% angle = 130 @@ -1772,28 +1780,30 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, EXAMPLES:: - sage: P = polytopes.small_rhombicuboctahedron() # optional - sage.rings.number_field - sage: Image = P.projection()._tikz_3d_in_3d([3, 7, 5], 100, scale=3, # optional - sage.rings.number_field + sage: # needs sage.plot sage.rings.number_field + sage: P = polytopes.small_rhombicuboctahedron() + sage: Image = P.projection()._tikz_3d_in_3d([3, 7, 5], 100, scale=3, ....: edge_color='blue', facet_color='orange', ....: opacity=0.5, vertex_color='green', axis=True) - sage: type(Image) # optional - sage.rings.number_field + sage: type(Image) - sage: print('\n'.join(Image.splitlines()[:4])) # optional - sage.rings.number_field + sage: print('\n'.join(Image.splitlines()[:4])) \begin{tikzpicture}% [x={(-0.046385cm, 0.837431cm)}, y={(-0.243536cm, 0.519228cm)}, z={(0.968782cm, 0.170622cm)}, - sage: with open('polytope-tikz1.tex', 'w') as f: # not tested # optional - sage.rings.number_field + sage: with open('polytope-tikz1.tex', 'w') as f: # not tested ....: _ = f.write(Image) :: + sage: # needs sage.plot sage: Associahedron = Polyhedron(vertices=[[1, 0, 1], [1, 0, 0], [1, 1, 0], ....: [0, 0, -1], [0, 1, 0], [-1, 0, 0], ....: [0, 1, 1], [0, 0, 1], [0, -1, 0]]).polar() - sage: ImageAsso = Associahedron.projection().tikz([-15, -755, -655], 116, scale=1, # optional - sage.plot + sage: ImageAsso = Associahedron.projection().tikz([-15, -755, -655], 116, scale=1, ....: output_type='LatexExpr') - sage: print('\n'.join(ImageAsso.splitlines()[12:30])) # optional - sage.plot + sage: print('\n'.join(ImageAsso.splitlines()[12:30])) %% with the command: ._tikz_3d_in_3d and parameters: %% view = [-15, -755, -655] %% angle = 116 diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index c7eac168fad..933275357d8 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -407,11 +407,11 @@ def plot(self): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0), (0,1), (0,0), (2,2)) - sage: P.plot() # optional - sage.plot + sage: P.plot() # needs sage.plot Graphics object consisting of 6 graphics primitives - sage: LatticePolytope_PPL([0], [1]).plot() # optional - sage.plot + sage: LatticePolytope_PPL([0], [1]).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: LatticePolytope_PPL([0]).plot() # optional - sage.plot + sage: LatticePolytope_PPL([0]).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 6cd4cd457f0..91e4d4de82f 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -48,7 +48,7 @@ sage: square = LatticePolytope_PPL((-1,-1), (-1,1), (1,-1), (1,1)) sage: fibers = [ f.vertices() for f in square.fibration_generator(1) ]; fibers [((1, 0), (-1, 0)), ((0, 1), (0, -1)), ((-1, -1), (1, 1)), ((-1, 1), (1, -1))] - sage: square.pointsets_mod_automorphism(fibers) # optional - sage.groups + sage: square.pointsets_mod_automorphism(fibers) # needs sage.groups (frozenset({(-1, -1), (1, 1)}), frozenset({(-1, 0), (1, 0)})) AUTHORS: @@ -118,36 +118,36 @@ def LatticePolytope_PPL(*args): sage: LatticePolytope_PPL((0,0), (1,0), (0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices - sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # optional - pplpy - sage: p = point(Linear_Expression([2,3],0)); p # optional - pplpy + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # needs pplpy + sage: p = point(Linear_Expression([2,3],0)); p # needs pplpy point(2/1, 3/1) - sage: LatticePolytope_PPL(p) # optional - pplpy + sage: LatticePolytope_PPL(p) # needs pplpy A 0-dimensional lattice polytope in ZZ^2 with 1 vertex - sage: P = C_Polyhedron(Generator_System(p)); P # optional - pplpy + sage: P = C_Polyhedron(Generator_System(p)); P # needs pplpy A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point - sage: LatticePolytope_PPL(P) # optional - pplpy + sage: LatticePolytope_PPL(P) # needs pplpy A 0-dimensional lattice polytope in ZZ^2 with 1 vertex A ``TypeError`` is raised if the arguments do not specify a lattice polytope:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0), (1/2,1)) # optional - pplpy + sage: LatticePolytope_PPL((0,0), (1/2,1)) # needs pplpy Traceback (most recent call last): ... TypeError: unable to convert rational 1/2 to an integer - sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # optional - pplpy - sage: p = point(Linear_Expression([2,3],0), 5); p # optional - pplpy + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # needs pplpy + sage: p = point(Linear_Expression([2,3],0), 5); p # needs pplpy point(2/5, 3/5) - sage: LatticePolytope_PPL(p) # optional - pplpy + sage: LatticePolytope_PPL(p) # needs pplpy Traceback (most recent call last): ... TypeError: generator is not a lattice polytope generator - sage: P = C_Polyhedron(Generator_System(p)); P # optional - pplpy + sage: P = C_Polyhedron(Generator_System(p)); P # needs pplpy A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point - sage: LatticePolytope_PPL(P) # optional - pplpy + sage: LatticePolytope_PPL(P) # needs pplpy Traceback (most recent call last): ... TypeError: polyhedron has non-integral generators @@ -386,14 +386,14 @@ def integral_points(self): ....: (-1,2,-1), (-1,2,-2), (-1,1,-2), (-1,-1,2), (-1,-3,2)] sage: P = LatticePolytope_PPL(*v) sage: pts1 = P.integral_points() # Sage's own code - sage: pts2 = LatticePolytope(v).points() # optional - palp + sage: pts2 = LatticePolytope(v).points() # needs palp sage: for p in pts1: p.set_immutable() - sage: set(pts1) == set(pts2) # optional - palp + sage: set(pts1) == set(pts2) # needs palp True sage: len(Polyhedron(v).integral_points()) # takes about 1 ms 23 - sage: len(LatticePolytope(v).points()) # takes about 13 ms # optional - palp + sage: len(LatticePolytope(v).points()) # takes about 13 ms # needs palp 23 sage: len(LatticePolytope_PPL(*v).integral_points()) # takes about 0.5 ms 23 @@ -648,7 +648,7 @@ def pointsets_mod_automorphism(self, pointsets): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: square = LatticePolytope_PPL((-1,-1), (-1,1), (1,-1), (1,1)) sage: fibers = [f.vertices() for f in square.fibration_generator(1)] - sage: square.pointsets_mod_automorphism(fibers) # optional - sage.groups sage.graphs + sage: square.pointsets_mod_automorphism(fibers) # needs sage.graphs sage.groups (frozenset({(-1, -1), (1, 1)}), frozenset({(-1, 0), (1, 0)})) sage: cell24 = LatticePolytope_PPL( @@ -657,7 +657,7 @@ def pointsets_mod_automorphism(self, pointsets): ....: (1,-1,-1,0), (0,0,-1,0), (0,-1,0,0), (-1,0,0,0), (1,-1,0,0), (1,0,-1,0), ....: (0,1,1,-1), (-1,1,1,0), (-1,1,0,0), (-1,0,1,0), (0,-1,-1,1), (0,0,0,-1)) sage: fibers = [f.vertices() for f in cell24.fibration_generator(2)] - sage: cell24.pointsets_mod_automorphism(fibers) # long time # optional - sage.groups sage.graphs + sage: cell24.pointsets_mod_automorphism(fibers) # long time # needs sage.graphs sage.groups (frozenset({(-1, 0, 0, 0), (-1, 0, 0, 1), (0, 0, 0, -1), @@ -975,19 +975,20 @@ def restricted_automorphism_group(self, vertex_labels=None): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) - sage: G1234 = Z3square.restricted_automorphism_group( # optional - sage.groups sage.graphs + sage: G1234 = Z3square.restricted_automorphism_group( ....: vertex_labels=(1,2,3,4)) - sage: G1234 == PermutationGroup([[(2,3)], [(1,2),(3,4)]]) # optional - sage.groups sage.graphs + sage: G1234 == PermutationGroup([[(2,3)], [(1,2),(3,4)]]) True - sage: G = Z3square.restricted_automorphism_group() # optional - sage.groups sage.graphs - sage: G == PermutationGroup([[((1,2),(2,1))], [((0,0),(1,2)), # optional - sage.groups sage.graphs + sage: G = Z3square.restricted_automorphism_group() + sage: G == PermutationGroup([[((1,2),(2,1))], [((0,0),(1,2)), ....: ((2,1),(3,3))], [((0,0),(3,3))]]) True - sage: set(G.domain()) == set(Z3square.vertices()) # optional - sage.groups sage.graphs + sage: set(G.domain()) == set(Z3square.vertices()) True - sage: (set(tuple(x) for x in G.orbit(Z3square.vertices()[0])) # optional - sage.groups sage.graphs + sage: (set(tuple(x) for x in G.orbit(Z3square.vertices()[0])) ....: == set([(0, 0), (1, 2), (3, 3), (2, 1)])) True sage: cell24 = LatticePolytope_PPL( @@ -995,7 +996,7 @@ def restricted_automorphism_group(self, vertex_labels=None): ....: (0,-1,0,1), (-1,0,0,1), (1,0,0,-1), (0,1,0,-1), (0,0,1,-1), (-1,1,1,-1), ....: (1,-1,-1,0), (0,0,-1,0), (0,-1,0,0), (-1,0,0,0), (1,-1,0,0), (1,0,-1,0), ....: (0,1,1,-1), (-1,1,1,0), (-1,1,0,0), (-1,0,1,0), (0,-1,-1,1), (0,0,0,-1)) - sage: cell24.restricted_automorphism_group().cardinality() # optional - sage.groups sage.graphs + sage: cell24.restricted_automorphism_group().cardinality() 1152 """ if not self.is_full_dimensional(): @@ -1048,25 +1049,25 @@ def lattice_automorphism_group(self, points=None, point_labels=None): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) - sage: Z3square.lattice_automorphism_group() # optional - sage.groups sage.graphs + sage: Z3square.lattice_automorphism_group() # needs sage.graphs sage.groups Permutation Group with generators [(), ((1,2),(2,1)), ((0,0),(3,3)), ((0,0),(3,3))((1,2),(2,1))] - sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4)) # optional - sage.groups sage.graphs - sage: G1 + sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4)) # needs sage.graphs sage.groups + sage: G1 # needs sage.graphs sage.groups Permutation Group with generators [(), (2,3), (1,4), (1,4)(2,3)] - sage: G1.cardinality() # optional - sage.groups sage.graphs + sage: G1.cardinality() # needs sage.graphs sage.groups 4 - sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) # optional - sage.groups sage.graphs - sage: G2 == PermutationGroup([[(2,3)], [(1,2),(3,4)], [(1,4)]]) # optional - sage.groups sage.graphs + sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) # needs sage.graphs sage.groups + sage: G2 == PermutationGroup([[(2,3)], [(1,2),(3,4)], [(1,4)]]) # needs sage.graphs sage.groups True - sage: G2.cardinality() # optional - sage.groups sage.graphs + sage: G2.cardinality() # needs sage.graphs sage.groups 8 sage: points = Z3square.integral_points(); points ((0, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 3)) - sage: Z3square.lattice_automorphism_group(points, # optional - sage.groups sage.graphs + sage: Z3square.lattice_automorphism_group(points, # needs sage.graphs sage.groups ....: point_labels=(1,2,3,4,5,6)) Permutation Group with generators [(), (3,4), (1,6)(2,5), (1,6)(2,5)(3,4)] @@ -1075,7 +1076,7 @@ def lattice_automorphism_group(self, points=None, point_labels=None): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: lp = LatticePolytope_PPL((1,0,0), (0,1,0), (-1,-1,0)) - sage: lp.lattice_automorphism_group(point_labels=(0,1,2)) # optional - sage.groups sage.graphs + sage: lp.lattice_automorphism_group(point_labels=(0,1,2)) # needs sage.graphs sage.groups Permutation Group with generators [(), (1,2), (0,1), (0,1,2), (0,2,1), (0,2)] """ if not self.is_full_dimensional(): diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index bab34f3481d..554e36ec239 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -799,8 +799,8 @@ def is_facet_defining_inequality(self, other): sage: Q = Polyhedron(ieqs=[[0,2,0,3]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) True - sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) # optional - sage.rings.number_field - sage: Q.inequalities()[0].is_facet_defining_inequality(P) # optional - sage.rings.number_field + sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) # needs sage.rings.number_field + sage: Q.inequalities()[0].is_facet_defining_inequality(P) True sage: Q = Polyhedron(ieqs=[[1,1,0,0]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) @@ -902,9 +902,9 @@ def _repr_(self): Test that :trac:`21105` has been fixed:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 2, 'a', embedding=1.26) # optional - sage.rings.number_field - sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) # optional - sage.rings.number_field - sage: P.inequalities() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2, 'a', embedding=1.26) # needs sage.rings.number_field + sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) # needs sage.rings.number_field + sage: P.inequalities() # needs sage.rings.number_field (An inequality (-cbrt2^2 - cbrt2 - 1, 0, 0) x + cbrt2^2 + cbrt2 + 2 >= 0, An inequality (cbrt2^2 + cbrt2 + 1, 0, 0) x - cbrt2^2 + cbrt2 + 1 >= 0) """ @@ -994,7 +994,7 @@ def outer_normal(self): EXAMPLES:: - sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]]) + sage: p = Polyhedron(vertices=[[0,0,0],[1,1,0],[1,2,0]]) sage: a = next(p.inequality_generator()) sage: a.outer_normal() (1, -1, 0) diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 4bb8d6ac8c9..8ce4496c65a 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -49,7 +49,7 @@ sage: p = PseudolineArrangement(permutations) sage: p Arrangement of pseudolines of size 4 - sage: p.show() # optional - sage.plot + sage: p.show() # needs sage.plot **Sequence of transpositions** @@ -67,7 +67,7 @@ sage: p = PseudolineArrangement(transpositions) sage: p Arrangement of pseudolines of size 4 - sage: p.show() # optional - sage.plot + sage: p.show() # needs sage.plot Note that this ordering is not necessarily unique. @@ -129,9 +129,9 @@ avoid a common crossing of three lines by adding a random noise to `b`:: sage: n = 20 - sage: l = sorted(zip(Subsets(20*n, n).random_element(), # optional - sage.combinat + sage: l = sorted(zip(Subsets(20*n, n).random_element(), ....: [randint(0, 20*n) + random() for i in range(n)])) - sage: print(l[:5]) # not tested # optional - sage.combinat + sage: print(l[:5]) # not tested # needs sage.combinat [(96, 278.0130613051349), (74, 332.92512282478714), (13, 155.65820951249867), (209, 34.753946221755307), (147, 193.51376457741441)] @@ -140,16 +140,16 @@ sage: permutations = [[0..i-1] + [i+1..n-1] for i in range(n)] sage: def a(x): return l[x][0] sage: def b(x): return l[x][1] - sage: for i, perm in enumerate(permutations): # optional - sage.combinat + sage: for i, perm in enumerate(permutations): ....: perm.sort(key=lambda j: (b(j)-b(i))/(a(i)-a(j))) And finally build the line arrangement:: sage: from sage.geometry.pseudolines import PseudolineArrangement - sage: p = PseudolineArrangement(permutations) # optional - sage.combinat - sage: print(p) # optional - sage.combinat + sage: p = PseudolineArrangement(permutations) + sage: print(p) Arrangement of pseudolines of size 20 - sage: p.show(figsize=[20,8]) # optional - sage.combinat sage.plot + sage: p.show(figsize=[20,8]) # needs sage.combinat sage.plot Author ^^^^^^ @@ -419,14 +419,14 @@ def show(self, **args): sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolineArrangement(permutations) - sage: p.show(figsize=[7,5]) # optional - sage.plot + sage: p.show(figsize=[7,5]) # needs sage.plot TESTS:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] sage: p = PseudolineArrangement(permutations) - sage: p.show() # optional - sage.plot + sage: p.show() # needs sage.plot Traceback (most recent call last): ... ValueError: There has been a problem while plotting the figure... diff --git a/src/sage/geometry/relative_interior.py b/src/sage/geometry/relative_interior.py index d9ba65bbff5..8f4a63a8a14 100644 --- a/src/sage/geometry/relative_interior.py +++ b/src/sage/geometry/relative_interior.py @@ -324,11 +324,11 @@ def __eq__(self, other): sage: ri_segment = segment.relative_interior(); ri_segment Relative interior of a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # optional - sage.rings.number_field - sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # optional - sage.rings.number_field + sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # needs sage.rings.number_field + sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # needs sage.rings.number_field Relative interior of a 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: ri_segment == ri_segment2 # optional - sage.rings.number_field + sage: ri_segment == ri_segment2 # needs sage.rings.number_field True TESTS:: @@ -337,7 +337,7 @@ def __eq__(self, other): sage: ri_segment == empty False """ - if type(self) != type(other): + if type(self) is not type(other): return False return self._polyhedron == other._polyhedron @@ -355,11 +355,11 @@ def __ne__(self, other): sage: ri_segment = segment.relative_interior(); ri_segment Relative interior of a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # optional - sage.rings.number_field - sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # optional - sage.rings.number_field + sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # needs sage.rings.number_field + sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # needs sage.rings.number_field Relative interior of a 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: ri_segment != ri_segment2 # optional - sage.rings.number_field + sage: ri_segment != ri_segment2 # needs sage.rings.number_field False """ return not (self == other) diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index 0253cdc1888..c0161ab0c4f 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -99,7 +99,7 @@ class ParametrizedSurface3D(SageObject): sage: ellipsoid = ParametrizedSurface3D(ellipsoid_eq, coords, 'ellipsoid'); ellipsoid Parametrized surface ('ellipsoid') with equation (cos(u1)*cos(u2), 2*cos(u2)*sin(u1), 3*sin(u2)) - sage: ellipsoid.plot() # optional - sage.plot + sage: ellipsoid.plot() # needs sage.plot Graphics3d Object Standard surfaces can be constructed using the ``surfaces`` generator:: @@ -127,7 +127,7 @@ class ParametrizedSurface3D(SageObject): sage: enneper = surfaces.Enneper(); enneper Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enneper.plot(aspect_ratio='automatic') # optional - sage.plot + sage: enneper.plot(aspect_ratio='automatic') # needs sage.plot Graphics3d Object We construct an ellipsoid whose axes are given by symbolic variables `a`, @@ -255,6 +255,7 @@ class ParametrizedSurface3D(SageObject): We can easily generate a color plot of the Gaussian curvature of a surface. Here we deal with the ellipsoid:: + sage: # needs numpy sage: u1, u2 = var('u1,u2', domain='real') sage: u = [u1,u2] sage: ellipsoid_equation(u1,u2) = [2*cos(u1)*cos(u2),1.5*cos(u1)*sin(u2),sin(u1)] @@ -264,27 +265,27 @@ class ParametrizedSurface3D(SageObject): sage: u2min, u2max = 0, 6.28 sage: u1num, u2num = 10, 20 sage: # make the arguments array - sage: from numpy import linspace # optional - numpy - sage: u1_array = linspace(u1min, u1max, u1num) # optional - numpy - sage: u2_array = linspace(u2min, u2max, u2num) # optional - numpy - sage: u_array = [(uu1,uu2) for uu1 in u1_array for uu2 in u2_array] # optional - numpy + sage: from numpy import linspace + sage: u1_array = linspace(u1min, u1max, u1num) + sage: u2_array = linspace(u2min, u2max, u2num) + sage: u_array = [(uu1,uu2) for uu1 in u1_array for uu2 in u2_array] sage: # Find the gaussian curvature - sage: K(u1,u2) = ellipsoid.gauss_curvature() # optional - numpy - sage: # Make array of K values # optional - numpy - sage: K_array = [K(uu[0],uu[1]) for uu in u_array] # optional - numpy + sage: K(u1,u2) = ellipsoid.gauss_curvature() + sage: # Make array of K values + sage: K_array = [K(uu[0],uu[1]) for uu in u_array] sage: # Find minimum and max of the Gauss curvature - sage: K_max = max(K_array) # optional - numpy - sage: K_min = min(K_array) # optional - numpy + sage: K_max = max(K_array) + sage: K_min = min(K_array) sage: # Make the array of color coefficients - sage: cc_array = [(ccc - K_min)/(K_max - K_min) for ccc in K_array] # optional - numpy - sage: points_array = [ellipsoid_equation(u_array[counter][0], # optional - numpy + sage: cc_array = [(ccc - K_min)/(K_max - K_min) for ccc in K_array] + sage: points_array = [ellipsoid_equation(u_array[counter][0], ....: u_array[counter][1]) ....: for counter in range(0,len(u_array))] - sage: curvature_ellipsoid_plot = sum(point([xx # optional - numpy sage.plot + sage: curvature_ellipsoid_plot = sum(point([xx # needs sage.plot ....: for xx in points_array[counter]], ....: color=hue(cc_array[counter]/2)) ....: for counter in range(0,len(u_array))) - sage: curvature_ellipsoid_plot.show(aspect_ratio=1) # optional - numpy sage.plot + sage: curvature_ellipsoid_plot.show(aspect_ratio=1) # needs sage.plot We can find the principal curvatures and principal directions of the elliptic paraboloid:: @@ -341,7 +342,7 @@ class ParametrizedSurface3D(SageObject): sage: g3 = [c[-1] for c in S.geodesics_numerical((0,0), ....: (cos(2*pi/3),sin(2*pi/3)), ....: (0,2*pi,100))] - sage: (S.plot(opacity=0.3) + line3d(g1, color='red') # optional - sage.plot + sage: (S.plot(opacity=0.3) + line3d(g1, color='red') # needs sage.plot ....: + line3d(g2, color='red') + line3d(g3, color='red')).show() """ @@ -514,7 +515,7 @@ def plot(self, urange=None, vrange=None, **kwds): sage: u, v = var('u, v', domain='real') sage: eq = (3*u + 3*u*v^2 - u^3, 3*v + 3*u^2*v - v^3, 3*(u^2-v^2)) sage: enneper = ParametrizedSurface3D(eq, (u, v), 'Enneper Surface') - sage: enneper.plot((-5, 5), (-5, 5)) # optional - sage.plot + sage: enneper.plot((-5, 5), (-5, 5)) # needs sage.plot Graphics3d Object """ diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 3619c6c2952..ba8eff2ed2a 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -53,7 +53,7 @@ def Catenoid(c=1, name="Catenoid"): sage: cat = surfaces.Catenoid(); cat Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v) - sage: cat.plot() # optional - sage.plot + sage: cat.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -86,7 +86,7 @@ def Crosscap(r=1, name="Crosscap"): sage: crosscap = surfaces.Crosscap(); crosscap Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u)) - sage: crosscap.plot() # optional - sage.plot + sage: crosscap.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -120,7 +120,7 @@ def Dini(a=1, b=1, name="Dini's surface"): sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) - sage: dini.plot() # optional - sage.plot + sage: dini.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -158,7 +158,7 @@ def Ellipsoid(center=(0, 0, 0), axes=(1, 1, 1), name="Ellipsoid"): sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v)) - sage: ell.plot() # optional - sage.plot + sage: ell.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -193,7 +193,7 @@ def Enneper(name="Enneper's surface"): sage: enn = surfaces.Enneper(); enn Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enn.plot() # optional - sage.plot + sage: enn.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -227,7 +227,7 @@ def Helicoid(h=1, name="Helicoid"): sage: helicoid = surfaces.Helicoid(h=2); helicoid Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi) - sage: helicoid.plot() # optional - sage.plot + sage: helicoid.plot() # needs sage.plot Graphics3d Object """ rho, theta = var('rho, theta') @@ -260,7 +260,7 @@ def Klein(r=1, name="Klein bottle"): sage: klein = surfaces.Klein(); klein Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) - sage: klein.plot() # optional - sage.plot + sage: klein.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -291,7 +291,7 @@ def MonkeySaddle(name="Monkey saddle"): sage: saddle = surfaces.MonkeySaddle(); saddle Parametrized surface ('Monkey saddle') with equation (u, v, u^3 - 3*u*v^2) - sage: saddle.plot() # optional - sage.plot + sage: saddle.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -327,12 +327,12 @@ def Paraboloid(a=1, b=1, c=1, elliptic=True, name=None): sage: epar = surfaces.Paraboloid(1, 3, 2); epar Parametrized surface ('Elliptic paraboloid') with equation (u, v, 2*u^2 + 2/9*v^2) - sage: epar.plot() # optional - sage.plot + sage: epar.plot() # needs sage.plot Graphics3d Object sage: hpar = surfaces.Paraboloid(2, 3, 1, elliptic=False); hpar Parametrized surface ('Hyperbolic paraboloid') with equation (u, v, -1/4*u^2 + 1/9*v^2) - sage: hpar.plot() # optional - sage.plot + sage: hpar.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -372,7 +372,7 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: sphere = surfaces.Sphere(center=(0, 1, -1), R=2); sphere Parametrized surface ('Sphere') with equation (2*cos(u)*cos(v), 2*cos(v)*sin(u) + 1, 2*sin(v) - 1) - sage: sphere.plot() # optional - sage.plot + sage: sphere.plot() # needs sage.plot Graphics3d Object Note that the radius of the sphere can be negative. The surface thus @@ -382,14 +382,14 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: octant1 = surfaces.Sphere(R=1); octant1 Parametrized surface ('Sphere') with equation (cos(u)*cos(v), cos(v)*sin(u), sin(v)) - sage: octant1.plot((0, pi/2), (0, pi/2)) # optional - sage.plot + sage: octant1.plot((0, pi/2), (0, pi/2)) # needs sage.plot Graphics3d Object with the first octant of the unit sphere with negative radius:: sage: octant2 = surfaces.Sphere(R=-1); octant2 Parametrized surface ('Sphere') with equation (-cos(u)*cos(v), -cos(v)*sin(u), -sin(v)) - sage: octant2.plot((0, pi/2), (0, pi/2)) # optional - sage.plot + sage: octant2.plot((0, pi/2), (0, pi/2)) # needs sage.plot Graphics3d Object """ return SurfaceGenerators.Ellipsoid(center, (R, R, R), name) @@ -421,7 +421,7 @@ def Torus(r=2, R=3, name="Torus"): sage: torus = surfaces.Torus(); torus Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v)) - sage: torus.plot() # optional - sage.plot + sage: torus.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -448,7 +448,7 @@ def WhitneyUmbrella(name="Whitney's umbrella"): sage: whitney = surfaces.WhitneyUmbrella(); whitney Parametrized surface ('Whitney's umbrella') with equation (u*v, u, v^2) - sage: whitney.plot() # optional - sage.plot + sage: whitney.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index a8a2ad38ba6..c5d35bb2002 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -951,7 +951,7 @@ def __richcmp__(self, right, op): """ if self is right: return rich_to_bool(op, 0) - if type(self) != type(right): + if type(self) is not type(right): return NotImplemented lx = self.rank() @@ -1068,7 +1068,7 @@ def plot(self, **options): EXAMPLES:: sage: N = ToricLattice(3) - sage: N.plot() # optional - sage.plot + sage: N.plot() # needs sage.plot Graphics3d Object """ if "show_lattice" not in options: @@ -1215,12 +1215,12 @@ def plot(self, **options): sage: N = ToricLattice(3) sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)]) - sage: sublattice.plot() # optional - sage.plot + sage: sublattice.plot() # needs sage.plot Graphics3d Object Now we plot both the ambient lattice and its sublattice:: - sage: N.plot() + sublattice.plot(point_color="red") # optional - sage.plot + sage: N.plot() + sublattice.plot(point_color="red") # needs sage.plot Graphics3d Object """ if "show_lattice" not in options: diff --git a/src/sage/geometry/toric_lattice_element.pyx b/src/sage/geometry/toric_lattice_element.pyx index 6c6d28800b9..40897c019f5 100644 --- a/src/sage/geometry/toric_lattice_element.pyx +++ b/src/sage/geometry/toric_lattice_element.pyx @@ -394,7 +394,7 @@ cdef class ToricLatticeElement(Vector_integer_dense): sage: N = ToricLattice(3) sage: n = N(1,2,3) - sage: n.plot() # optional - sage.plot + sage: n.plot() # needs sage.plot Graphics3d Object """ tp = ToricPlotter(options, self.parent().degree()) diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 9a14918a2ab..50b4008eb0f 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -14,8 +14,8 @@ In most cases, this module is used indirectly, e.g. :: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - palp sage.plot + sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives You may change default plotting options as follows:: @@ -25,12 +25,12 @@ sage: toric_plotter.options(show_rays=False) sage: toric_plotter.options("show_rays") False - sage: fan.plot() # optional - palp sage.plot + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 19 graphics primitives sage: toric_plotter.reset_options() sage: toric_plotter.options("show_rays") True - sage: fan.plot() # optional - palp sage.plot + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives """ @@ -134,10 +134,10 @@ class ToricPlotter(SageObject): directly. Instead, use plotting method of the object which you want to plot, e.g. :: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - palp sage.plot + sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives - sage: print(fan.plot()) # optional - palp sage.plot + sage: print(fan.plot()) # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives If you do want to create your own plotting function for some toric @@ -163,24 +163,25 @@ class ToricPlotter(SageObject): For example, the plot from the previous example can be obtained as follows:: + sage: # needs palp sage.graphs sage.plot sage: from sage.geometry.toric_plotter import ToricPlotter sage: options = dict() # use default for everything - sage: tp = ToricPlotter(options, fan.lattice().degree()) # optional - palp - sage: tp.include_points(fan.rays()) # optional - palp - sage: tp.adjust_options() # optional - palp - sage: tp.set_rays(fan.rays()) # optional - palp - sage: result = tp.plot_lattice() # optional - palp sage.plot - sage: result += tp.plot_rays() # optional - palp sage.plot - sage: result += tp.plot_generators() # optional - palp sage.plot - sage: result += tp.plot_walls(fan(2)) # optional - palp sage.plot - sage: result # optional - palp sage.plot + sage: tp = ToricPlotter(options, fan.lattice().degree()) + sage: tp.include_points(fan.rays()) + sage: tp.adjust_options() + sage: tp.set_rays(fan.rays()) + sage: result = tp.plot_lattice() + sage: result += tp.plot_rays() + sage: result += tp.plot_generators() + sage: result += tp.plot_walls(fan(2)) + sage: result Graphics object consisting of 31 graphics primitives In most situations it is only necessary to include generators of rays, in this case they can be passed to the constructor as an optional argument. In the example above, the toric plotter can be completely set up using :: - sage: tp = ToricPlotter(options, fan.lattice().degree(), fan.rays()) # optional - palp + sage: tp = ToricPlotter(options, fan.lattice().degree(), fan.rays()) # needs palp sage.graphs sage.plot All options are exposed as attributes of toric plotters and can be modified after constructions, however you will have to manually call @@ -389,7 +390,7 @@ def plot_generators(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_generators() # optional - sage.plot + sage: tp.plot_generators() # needs sage.plot Graphics object consisting of 1 graphics primitive """ generators = self.generators @@ -440,7 +441,7 @@ def plot_labels(self, labels, positions): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) - sage: tp.plot_labels("u", [(1.5,0)]) # optional - sage.plot + sage: tp.plot_labels("u", [(1.5,0)]) # needs sage.plot Graphics object consisting of 1 graphics primitive """ result = Graphics() @@ -474,7 +475,7 @@ def plot_lattice(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_lattice() # optional - sage.plot + sage: tp.plot_lattice() # needs sage.plot Graphics object consisting of 1 graphics primitive """ if not self.show_lattice: @@ -518,7 +519,7 @@ def plot_points(self, points): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_points([(1,0), (0,1)]) # optional - sage.plot + sage: tp.plot_points([(1,0), (0,1)]) # needs sage.plot Graphics object consisting of 1 graphics primitive """ return point(points, color=self.point_color, size=self.point_size, @@ -542,7 +543,7 @@ def plot_ray_labels(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_ray_labels() # optional - sage.plot + sage: tp.plot_ray_labels() # needs sage.plot Graphics object consisting of 1 graphics primitive """ return self.plot_labels(self.ray_label, @@ -563,7 +564,7 @@ def plot_rays(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_rays() # optional - sage.plot + sage: tp.plot_rays() # needs sage.plot Graphics object consisting of 2 graphics primitives """ result = Graphics() @@ -605,14 +606,14 @@ def plot_walls(self, walls): sage: quadrant = Cone([(1,0), (0,1)]) sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, quadrant.rays()) - sage: tp.plot_walls([quadrant]) # optional - sage.plot + sage: tp.plot_walls([quadrant]) # needs sage.plot Graphics object consisting of 2 graphics primitives Let's also check that the truncating polyhedron is functioning correctly:: sage: tp = ToricPlotter({"mode": "box"}, 2, quadrant.rays()) - sage: tp.plot_walls([quadrant]) # optional - sage.plot + sage: tp.plot_walls([quadrant]) # needs sage.plot Graphics object consisting of 2 graphics primitives """ result = Graphics() @@ -702,12 +703,12 @@ def set_rays(self, generators): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_rays() # optional - sage.plot + sage: tp.plot_rays() # needs sage.plot Traceback (most recent call last): ... AttributeError: 'ToricPlotter' object has no attribute 'rays' sage: tp.set_rays([(0,1)]) - sage: tp.plot_rays() # optional - sage.plot + sage: tp.plot_rays() # needs sage.plot Graphics object consisting of 2 graphics primitives """ d = self.dimension @@ -781,21 +782,22 @@ def color_list(color, n): EXAMPLES:: + sage: # needs sage.plot sage: from sage.geometry.toric_plotter import color_list - sage: color_list("grey", 1) # optional - sage.plot + sage: color_list("grey", 1) [RGB color (0.5019607843137255, 0.5019607843137255, 0.5019607843137255)] - sage: len(color_list("grey", 3)) # optional - sage.plot + sage: len(color_list("grey", 3)) 3 - sage: L = color_list("rainbow", 3) # optional - sage.plot - sage: L # optional - sage.plot + sage: L = color_list("rainbow", 3) + sage: L [RGB color (1.0, 0.0, 0.0), RGB color (0.0, 1.0, 0.0), RGB color (0.0, 0.0, 1.0)] - sage: color_list(L, 3) # optional - sage.plot + sage: color_list(L, 3) [RGB color (1.0, 0.0, 0.0), RGB color (0.0, 1.0, 0.0), RGB color (0.0, 0.0, 1.0)] - sage: color_list(L, 4) # optional - sage.plot + sage: color_list(L, 4) Traceback (most recent call last): ... ValueError: expected 4 colors, got 3! @@ -1106,9 +1108,9 @@ def sector(ray1, ray2, **extra_options): EXAMPLES:: sage: from sage.geometry.toric_plotter import sector - sage: sector((1,0), (0,1)) + sage: sector((1,0), (0,1)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: sector((3,2,1), (1,2,3)) + sage: sector((3,2,1), (1,2,3)) # needs sage.plot Graphics3d Object """ ray1 = vector(RDF, ray1) diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index 8fa5b82e213..d66186db098 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -18,7 +18,7 @@ AUTHORS: # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.misc.fast_methods cimport hash_by_id @@ -76,7 +76,6 @@ cdef class Point(SageObject): cdef object _point_configuration cdef object _reduced_affine_vector, _reduced_projective_vector - def __init__(self, point_configuration, i, projective, affine, reduced): r""" Construct a :class:`Point`. @@ -129,7 +128,6 @@ cdef class Point(SageObject): """ return self._point_configuration - def __iter__(self): r""" Iterate through the affine ambient space coordinates of the point. @@ -160,7 +158,6 @@ cdef class Point(SageObject): """ return len(self._affine) - cpdef index(self): """ Return the index of the point in the point configuration. @@ -175,7 +172,6 @@ cdef class Point(SageObject): """ return self._index - cpdef projective(self): r""" Return the projective coordinates of the point in the ambient space. @@ -202,7 +198,6 @@ cdef class Point(SageObject): """ return self._projective - cpdef affine(self): r""" Return the affine coordinates of the point in the ambient space. @@ -229,7 +224,6 @@ cdef class Point(SageObject): """ return self._affine - cpdef reduced_affine(self): r""" Return the affine coordinates of the point on the hyperplane @@ -257,7 +251,6 @@ cdef class Point(SageObject): """ return self._reduced_affine - cpdef reduced_projective(self): r""" Return the projective coordinates of the point on the hyperplane @@ -285,7 +278,6 @@ cdef class Point(SageObject): """ return tuple(self._reduced_affine)+(1,) - cpdef reduced_affine_vector(self): """ Return the affine coordinates of the point on the hyperplane @@ -313,7 +305,6 @@ cdef class Point(SageObject): """ return self._reduced_affine_vector - cpdef reduced_projective_vector(self): """ Return the affine coordinates of the point on the hyperplane @@ -359,7 +350,7 @@ cdef class Point(SageObject): sage: p._repr_() 'P(0, 0)' """ - return 'P'+str(self._affine) + return 'P' + str(self._affine) ######################################################################## @@ -398,7 +389,6 @@ cdef class PointConfiguration_base(Parent): self._init_points(points) self._is_affine = defined_affine - cdef tuple _pts cdef int _ambient_dim cdef int _dim @@ -406,7 +396,6 @@ cdef class PointConfiguration_base(Parent): cdef bint _is_affine cdef object _reduced_affine_vector_space, _reduced_projective_vector_space - cdef _init_points(self, tuple projective_points): """ Internal method to determine coordinates of points. @@ -449,20 +438,20 @@ cdef class PointConfiguration_base(Parent): else: raise NotImplementedError # TODO - if n>1: + if n > 1: # shift first point to origin - red = matrix([ aff.column(i)-aff.column(0) for i in range(n) ]).transpose() + red = matrix([aff.column(i)-aff.column(0) for i in range(n)]).transpose() # pick linearly independent rows - red = matrix([ red.row(i) for i in red.pivot_rows()]) + red = matrix([red.row(i) for i in red.pivot_rows()]) else: - red = matrix(0,1) + red = matrix(0, 1) self._dim = red.nrows() from sage.modules.free_module import VectorSpace self._reduced_affine_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim) self._reduced_projective_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim+1) self._pts = tuple([Point(self, i, proj.column(i), - aff.column(i), red.column(i)) + aff.column(i), red.column(i)) for i in range(n)]) def __hash__(self): @@ -497,7 +486,6 @@ cdef class PointConfiguration_base(Parent): """ return self._reduced_affine_vector_space - cpdef reduced_projective_vector_space(self): """ Return the vector space that is spanned by the homogeneous @@ -519,7 +507,6 @@ cdef class PointConfiguration_base(Parent): """ return self._reduced_projective_vector_space - cpdef ambient_dim(self): """ Return the dimension of the ambient space of the point @@ -537,11 +524,9 @@ cdef class PointConfiguration_base(Parent): """ return self._ambient_dim - cpdef dim(self): """ - Return the actual dimension of the point - configuration. + Return the actual dimension of the point configuration. See also :meth:`ambient_dim` @@ -555,7 +540,6 @@ cdef class PointConfiguration_base(Parent): """ return self._dim - cpdef base_ring(self): r""" Return the base ring, that is, the ring containing the @@ -581,10 +565,9 @@ cdef class PointConfiguration_base(Parent): """ return self._base_ring - cpdef bint is_affine(self): """ - Whether the configuration is defined by affine points. + Return whether the configuration is defined by affine points. OUTPUT: @@ -603,7 +586,6 @@ cdef class PointConfiguration_base(Parent): """ return self._is_affine - def _assert_is_affine(self): """ Raise a ``ValueError`` if the point configuration is not @@ -622,7 +604,6 @@ cdef class PointConfiguration_base(Parent): if not self.is_affine(): raise ValueError('The point configuration contains projective points.') - def __getitem__(self, i): """ Return the ``i``-th point. @@ -651,7 +632,6 @@ cdef class PointConfiguration_base(Parent): """ return self._pts[i] - cpdef n_points(self): """ Return the number of points. @@ -673,14 +653,13 @@ cdef class PointConfiguration_base(Parent): """ return len(self._pts) - cpdef points(self): """ Return a list of the points. OUTPUT: - Returns a list of the points. See also the :meth:`__iter__` + A list of the points. See also the :meth:`__iter__` method, which returns the corresponding generator. EXAMPLES:: @@ -699,7 +678,6 @@ cdef class PointConfiguration_base(Parent): """ return self._pts - def point(self, i): """ Return the i-th point of the configuration. @@ -753,10 +731,9 @@ cdef class PointConfiguration_base(Parent): """ return len(self._pts) - cpdef simplex_to_int(self, simplex): r""" - Returns an integer that uniquely identifies the given simplex. + Return an integer that uniquely identifies the given simplex. See also the inverse method :meth:`int_to_simplex`. @@ -790,19 +767,18 @@ cdef class PointConfiguration_base(Parent): cdef int k = 1 cdef int n = self.n_points() cdef int d = len(simplex) - assert d==self.dim()+1 + assert d == self.dim()+1 cdef int i, j - for i in range(1,d+1): + for i in range(1, d+1): l = simplex[i-1]+1 - for j in range(k,l): - s += binomial(n-j,d-i) + for j in range(k, l): + s += binomial(n-j, d-i) k = l+1 return s - cpdef int_to_simplex(self, int s): r""" - Reverses the enumeration of possible simplices in + Reverse the enumeration of possible simplices in :meth:`simplex_to_int`. The enumeration is compatible with [PUNTOS]_. @@ -930,7 +906,6 @@ cdef class ConnectedTriangulationsIterator(SageObject): cdef triangulations_ptr _tp - def __cinit__(self): """ The Cython constructor. @@ -944,7 +919,6 @@ cdef class ConnectedTriangulationsIterator(SageObject): """ self._tp = NULL - def __init__(self, point_configuration, seed=None, star=None, fine=False): r""" The Python constructor. @@ -978,14 +952,12 @@ cdef class ConnectedTriangulationsIterator(SageObject): enumerated_simplices_seed, point_configuration.bistellar_flips()) - def __dealloc__(self): r""" The Cython destructor. """ delete_triangulations(self._tp) - def __iter__(self): r""" The iterator interface: Start iterating. diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 793b383f9dc..7486488adb1 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -23,7 +23,7 @@ sage: points = PointConfiguration(p) sage: triang = points.triangulate(); triang (<0,1,2,5>, <0,1,3,5>, <1,3,4,5>) - sage: triang.plot(axes=False) # optional - sage.plot + sage: triang.plot(axes=False) # needs sage.plot Graphics3d Object See :mod:`sage.geometry.triangulation.point_configuration` for more details. @@ -68,7 +68,7 @@ def triangulation_render_2d(triangulation, **kwds): sage: points = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) sage: triang = points.triangulate() - sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest # optional - sage.plot + sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest # needs sage.plot Graphics object consisting of 12 graphics primitives """ from sage.plot.all import point2d, line2d, polygon2d @@ -130,7 +130,7 @@ def triangulation_render_3d(triangulation, **kwds): sage: p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) # indirect doctest # optional - sage.plot + sage: triang.plot(axes=False) # indirect doctest # needs sage.plot Graphics3d Object """ from sage.plot.plot3d.all import point3d, line3d, polygon3d @@ -407,7 +407,7 @@ def plot(self, **kwds): sage: triangulation = p.triangulate() sage: triangulation (<1,3,4>, <2,3,4>) - sage: triangulation.plot(axes=False) # optional - sage.plot + sage: triangulation.plot(axes=False) # needs sage.plot Graphics object consisting of 12 graphics primitives """ dim = self.point_configuration().dim() @@ -524,7 +524,7 @@ def fan(self, origin=None): sage: triangulation = pc.triangulate() sage: fan = triangulation.fan(); fan Rational polyhedral fan in 2-d lattice N - sage: fan.is_equivalent(toric_varieties.P2().fan()) # optional - palp + sage: fan.is_equivalent(toric_varieties.P2().fan()) # needs palp sage.graphs True Toric diagrams (the `\ZZ_5` hyperconifold):: @@ -567,12 +567,12 @@ def simplicial_complex(self): EXAMPLES:: sage: p = polytopes.cuboctahedron() - sage: sc = p.triangulate(engine='internal').simplicial_complex(); sc # optional - sage.graphs + sage: sc = p.triangulate(engine='internal').simplicial_complex(); sc # needs sage.graphs Simplicial complex with 12 vertices and 16 facets Any convex set is contractable, so its reduced homology groups vanish:: - sage: sc.homology() # optional - sage.graphs + sage: sc.homology() # needs sage.graphs {0: 0, 1: 0, 2: 0, 3: 0} """ from sage.topology.simplicial_complex import SimplicialComplex @@ -670,19 +670,19 @@ def boundary_simplicial_complex(self): sage: p = polytopes.cuboctahedron() sage: triangulation = p.triangulate(engine='internal') - sage: bd_sc = triangulation.boundary_simplicial_complex(); bd_sc # optional - sage.graphs + sage: bd_sc = triangulation.boundary_simplicial_complex(); bd_sc # needs sage.graphs Simplicial complex with 12 vertices and 20 facets The boundary of every convex set is a topological sphere, so it has spherical homology:: - sage: bd_sc.homology() # optional - sage.graphs + sage: bd_sc.homology() # needs sage.graphs {0: 0, 1: 0, 2: Z} It is a subcomplex of ``self`` as a :meth:`simplicial_complex`:: - sage: sc = triangulation.simplicial_complex() # optional - sage.graphs - sage: all(f in sc for f in bd_sc.maximal_faces()) # optional - sage.graphs + sage: sc = triangulation.simplicial_complex() # needs sage.graphs + sage: all(f in sc for f in bd_sc.maximal_faces()) # needs sage.graphs True """ from sage.topology.simplicial_complex import SimplicialComplex @@ -739,9 +739,9 @@ def polyhedral_complex(self, **kwds): sage: pc = PointConfiguration(P.vertices()) sage: T = pc.placing_triangulation(); T (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) - sage: C = T.polyhedral_complex(); C # optional - sage.graphs + sage: C = T.polyhedral_complex(); C # needs sage.graphs Polyhedral complex with 6 maximal cells - sage: [P.vertices_list() for P in C.maximal_cells_sorted()] # optional - sage.graphs + sage: [P.vertices_list() for P in C.maximal_cells_sorted()] # needs sage.graphs [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [1, -1, -1]], [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1], [1, 1, -1]], [[-1, -1, -1], [-1, 1, 1], [1, -1, -1], [1, 1, -1]], @@ -775,9 +775,9 @@ def boundary_polyhedral_complex(self, **kwds): sage: pc = PointConfiguration(P.vertices()) sage: T = pc.placing_triangulation(); T (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) - sage: bd_C = T.boundary_polyhedral_complex(); bd_C # optional - sage.graphs + sage: bd_C = T.boundary_polyhedral_complex(); bd_C # needs sage.graphs Polyhedral complex with 12 maximal cells - sage: [P.vertices_list() for P in bd_C.maximal_cells_sorted()] # optional - sage.graphs + sage: [P.vertices_list() for P in bd_C.maximal_cells_sorted()] # needs sage.graphs [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1]], [[-1, -1, -1], [-1, -1, 1], [1, -1, -1]], [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1]], @@ -793,8 +793,8 @@ def boundary_polyhedral_complex(self, **kwds): It is a subcomplex of ``self`` as a :meth:`polyhedral_complex`:: - sage: C = T.polyhedral_complex() # optional - sage.graphs - sage: bd_C.is_subcomplex(C) # optional - sage.graphs + sage: C = T.polyhedral_complex() # needs sage.graphs + sage: bd_C.is_subcomplex(C) # needs sage.graphs True """ from sage.geometry.polyhedral_complex import PolyhedralComplex @@ -918,7 +918,7 @@ def adjacency_graph(self): sage: p = PointConfiguration([[1,0,0], [0,1,0], [0,0,1], [-1,0,1], ....: [1,0,-1], [-1,0,0], [0,-1,0], [0,0,-1]]) sage: t = p.triangulate() - sage: t.adjacency_graph() # optional - sage.graphs + sage: t.adjacency_graph() # needs sage.graphs Graph on 8 vertices """ diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 4f1bbde16d7..d75af2af4ce 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -65,7 +65,7 @@ (2, 3, 4) sage: list(t) [(1, 3, 4), (2, 3, 4)] - sage: t.plot(axes=False) # optional - sage.plot + sage: t.plot(axes=False) # needs sage.plot Graphics object consisting of 12 graphics primitives .. PLOT:: @@ -95,7 +95,7 @@ sage: p = [[0,-1,-1], [0,0,1], [0,1,0], [1,-1,-1], [1,0,1], [1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) # optional - sage.plot + sage: triang.plot(axes=False) # needs sage.plot Graphics3d Object .. PLOT:: @@ -108,18 +108,19 @@ The standard example of a non-regular triangulation (requires TOPCOM):: - sage: PointConfiguration.set_engine('topcom') # optional - topcom + sage: # optional - topcom + sage: PointConfiguration.set_engine('topcom') sage: p = PointConfiguration([[-1,-5/9], [0,10/9], [1,-5/9], ....: [-2,-10/9], [0,20/9], [2,-10/9]]) - sage: p_regular = p.restrict_to_regular_triangulations(True) # optional - topcom - sage: regular = p_regular.triangulations_list() # optional - topcom - sage: p_nonregular = p.restrict_to_regular_triangulations(False) # optional - topcom - sage: nonregular = p_nonregular.triangulations_list() # optional - topcom - sage: len(regular) # optional - topcom + sage: p_regular = p.restrict_to_regular_triangulations(True) + sage: regular = p_regular.triangulations_list() + sage: p_nonregular = p.restrict_to_regular_triangulations(False) + sage: nonregular = p_nonregular.triangulations_list() + sage: len(regular) 16 - sage: len(nonregular) # optional - topcom + sage: len(nonregular) 2 - sage: nonregular[0].plot(aspect_ratio=1, axes=False) # optional - topcom sage.plot + sage: nonregular[0].plot(aspect_ratio=1, axes=False) # needs sage.plot Graphics object consisting of 25 graphics primitives sage: PointConfiguration.set_engine('internal') # to make doctests independent of TOPCOM @@ -375,14 +376,15 @@ def set_engine(cls, engine='auto'): EXAMPLES:: + sage: # optional - topcom sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: p.set_engine('internal') # to make doctests independent of TOPCOM sage: p.triangulate() (<1,3,4>, <2,3,4>) - sage: p.set_engine('topcom') # optional - topcom - sage: p.triangulate() # optional - topcom + sage: p.set_engine('topcom') + sage: p.triangulate() (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ engine = engine.lower() if engine not in ['auto', 'topcom', 'internal']: @@ -738,13 +740,14 @@ def _TOPCOM_triangulate(self, verbose=True): EXAMPLES:: + sage: # optional - topcom sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) - sage: p.set_engine('topcom') # optional - topcom - sage: p._TOPCOM_triangulate(verbose=False) # optional - topcom + sage: p.set_engine('topcom') + sage: p._TOPCOM_triangulate(verbose=False) (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: list( p.triangulate() ) # optional - topcom + sage: list( p.triangulate() ) [(0, 1, 2), (0, 1, 4), (0, 2, 4), (1, 2, 3)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ assert self._regular is not False, \ 'When asked for a single triangulation TOPCOM ' + \ @@ -787,7 +790,7 @@ def restrict_to_regular_triangulations(self, regular=True): fine, not necessarily regular. sage: len(p.triangulations_list()) 4 - sage: PointConfiguration.set_engine('topcom') # optional - topcom + sage: PointConfiguration.set_engine('topcom') sage: p_regular = p.restrict_to_regular_triangulations() # optional - topcom sage: len(p_regular.triangulations_list()) # optional - topcom 4 @@ -831,7 +834,7 @@ def restrict_to_connected_triangulations(self, connected=True): fine, not necessarily regular. sage: len(p.triangulations_list()) 4 - sage: PointConfiguration.set_engine('topcom') # optional - topcom + sage: PointConfiguration.set_engine('topcom') sage: p_all = p.restrict_to_connected_triangulations(connected=False) # optional - topcom sage: len(p_all.triangulations_list()) # optional - topcom 4 @@ -961,27 +964,28 @@ def triangulations(self, verbose=False): compute the triangulations. Using TOPCOM, we obtain the same triangulations but in a different order:: - sage: p.set_engine('topcom') # optional - topcom - sage: iter = p.triangulations() # optional - topcom - sage: next(iter) # optional - topcom + sage: # optional - topcom + sage: p.set_engine('topcom') + sage: iter = p.triangulations() + sage: next(iter) (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: next(iter) # optional - topcom + sage: next(iter) (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>) - sage: next(iter) # optional - topcom + sage: next(iter) (<1,2,3>, <1,2,4>) - sage: next(iter) # optional - topcom + sage: next(iter) (<1,3,4>, <2,3,4>) - sage: p.triangulations_list() # optional - topcom + sage: p.triangulations_list() [(<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>), (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>), (<1,2,3>, <1,2,4>), (<1,3,4>, <2,3,4>)] - sage: p_fine = p.restrict_to_fine_triangulations() # optional - topcom - sage: p_fine.set_engine('topcom') # optional - topcom - sage: p_fine.triangulations_list() # optional - topcom + sage: p_fine = p.restrict_to_fine_triangulations() + sage: p_fine.set_engine('topcom') + sage: p_fine.triangulations_list() [(<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>), (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ if self._use_TOPCOM: for triangulation in self._TOPCOM_triangulations(verbose): @@ -1017,10 +1021,10 @@ def triangulations_list(self, verbose=False): [(<0,1,2>, <1,2,3>), (<0,1,3>, <0,2,3>)] sage: list(map(list, p.triangulations_list())) [[(0, 1, 2), (1, 2, 3)], [(0, 1, 3), (0, 2, 3)]] - sage: p.set_engine('topcom') # optional - topcom + sage: p.set_engine('topcom') sage: p.triangulations_list() # optional - topcom [(<0,1,2>, <1,2,3>), (<0,1,3>, <0,2,3>)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ return list(self.triangulations(verbose)) @@ -1049,12 +1053,13 @@ def triangulate(self, verbose=False): Using TOPCOM yields a different, but equally good, triangulation:: - sage: p.set_engine('topcom') # optional - topcom - sage: p.triangulate() # optional - topcom + sage: # optional - topcom + sage: p.set_engine('topcom') + sage: p.triangulate() (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: list(p.triangulate()) # optional - topcom + sage: list(p.triangulate()) [(0, 1, 2), (0, 1, 4), (0, 2, 4), (1, 2, 3)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ if self._use_TOPCOM and self._regular is not False: try: @@ -1127,10 +1132,10 @@ def restricted_automorphism_group(self): sage: pyramid = PointConfiguration([[1,0,0], [0,1,1], [0,1,-1], ....: [0,-1,-1], [0,-1,1]]) - sage: G = pyramid.restricted_automorphism_group() # optional - sage.graphs sage.groups - sage: G == PermutationGroup([[(3,5)], [(2,3),(4,5)], [(2,4)]]) # optional - sage.graphs sage.groups + sage: G = pyramid.restricted_automorphism_group() # needs sage.graphs sage.groups + sage: G == PermutationGroup([[(3,5)], [(2,3),(4,5)], [(2,4)]]) # needs sage.graphs sage.groups True - sage: DihedralGroup(4).is_isomorphic(G) # optional - sage.graphs sage.groups + sage: DihedralGroup(4).is_isomorphic(G) # needs sage.graphs sage.groups True The square with an off-center point in the middle. Note that @@ -1138,9 +1143,9 @@ def restricted_automorphism_group(self): `D_4` of the convex hull:: sage: square = PointConfiguration([(3/4,3/4), (1,1), (1,-1), (-1,-1), (-1,1)]) - sage: square.restricted_automorphism_group() # optional - sage.graphs sage.groups + sage: square.restricted_automorphism_group() # needs sage.graphs sage.groups Permutation Group with generators [(3,5)] - sage: DihedralGroup(1).is_isomorphic(_) # optional - sage.graphs sage.groups + sage: DihedralGroup(1).is_isomorphic(_) # needs sage.graphs sage.groups True """ v_list = [ vector(p.projective()) for p in self ] @@ -1530,9 +1535,9 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) # optional - sage.plot + sage: Tpos.plot(axes=False) # needs sage.plot Graphics object consisting of 11 graphics primitives - sage: Tneg.plot(axes=False) # optional - sage.plot + sage: Tneg.plot(axes=False) # needs sage.plot Graphics object consisting of 11 graphics primitives The 3d analog:: @@ -1547,7 +1552,7 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) # optional - sage.plot + sage: Tpos.plot(axes=False) # needs sage.plot Graphics3d Object """ flips = [] @@ -2085,7 +2090,7 @@ def plot(self, **kwds): EXAMPLES:: sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) - sage: p.plot(axes=False) # optional - sage.plot + sage: p.plot(axes=False) # needs sage.plot Graphics object consisting of 5 graphics primitives .. PLOT:: diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1e9629aa646..0cea1e91377 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -51,18 +51,19 @@ class VoronoiDiagram(SageObject): Get the Voronoi diagram of a regular pentagon in ``AA^2``. All cells meet at the origin:: - sage: DV = VoronoiDiagram([[AA(c) for c in v] for v in polytopes.regular_polygon(5).vertices_list()]); DV # optional - sage.rings.number_field + sage: DV = VoronoiDiagram([[AA(c) for c in v] # needs sage.rings.number_field + ....: for v in polytopes.regular_polygon(5).vertices_list()]); DV The Voronoi diagram of 5 points of dimension 2 in the Algebraic Real Field - sage: all(P.contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field + sage: all(P.contains([0, 0]) for P in DV.regions().values()) # needs sage.rings.number_field True - sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field + sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) # needs sage.rings.number_field False If the vertices are not converted to ``AA`` before, the method throws an error:: - sage: polytopes.dodecahedron().vertices_list()[0][0].parent() # optional - sage.rings.number_field + sage: polytopes.dodecahedron().vertices_list()[0][0].parent() # needs sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) # optional - sage.rings.number_field + sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: Base ring of the Voronoi diagram must be @@ -230,9 +231,9 @@ def _repr_(self): EXAMPLES:: - sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V # optional - sage.rings.number_field + sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V # needs sage.rings.number_field The Voronoi diagram of 3 points of dimension 2 in the Algebraic Real Field - sage: VoronoiDiagram([]) # optional - sage.rings.number_field + sage: VoronoiDiagram([]) The empty Voronoi diagram. """ if self._n: @@ -260,18 +261,17 @@ def plot(self, cell_colors=None, **kwds): EXAMPLES:: - sage: P = [[0.671, 0.650], [0.258, 0.767], [0.562, 0.406], [0.254, 0.709], [0.493, 0.879]] - - sage: V = VoronoiDiagram(P); S=V.plot() # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors={0:'red', 1:'blue', 2:'green', 3:'white', 4:'yellow'}) # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors=['red','blue','red','white', 'white']) # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors='something else') # optional - sage.plot + sage: # needs sage.plot + sage: P = [[0.671, 0.650], [0.258, 0.767], [0.562, 0.406], + ....: [0.254, 0.709], [0.493, 0.879]] + sage: V = VoronoiDiagram(P); S=V.plot() + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors={0: 'red', 1: 'blue', 2: 'green', + ....: 3: 'white', 4: 'yellow'}) + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors=['red', 'blue', 'red', 'white', 'white']) + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors='something else') Traceback (most recent call last): ... AssertionError: 'cell_colors' must be a list or a dictionary @@ -280,7 +280,7 @@ def plot(self, cell_colors=None, **kwds): Trying to plot a Voronoi diagram of dimension other than 2 gives an error:: - sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() # optional - sage.plot + sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() # needs sage.plot Traceback (most recent call last): ... NotImplementedError: Plotting of 3-dimensional Voronoi diagrams not diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index d6508f172f8..ff222837117 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -572,7 +572,7 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): from sage.graphs.base.boost_graph import bandwidth_heuristics sage: bandwidth_heuristics(Graph()) (0, []) - sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # optional - networkx + sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # needs networkx (0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ @@ -1964,8 +1964,8 @@ cpdef diameter_DHV(g, weight_function=None, check_weight=True): TESTS:: - sage: G = graphs.RandomBarabasiAlbert(17,6) # optional - networkx - sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(17,6) # needs networkx + sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # needs networkx True sage: G = Graph([(0,1,-1)], weighted=True) sage: diameter_DHV(G) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index a4f2efd6060..79e62e13a33 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1576,12 +1576,13 @@ cdef class CGraphBackend(GenericGraphBackend): We check that the bug described in :trac:`8406` is gone:: + sage: # needs sage.rings.finite_rings sage: G = Graph() - sage: R. = GF(3**3) # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: G.add_vertex(a**2) # optional - sage.rings.finite_rings - sage: G.add_vertex(x) # optional - sage.rings.finite_rings - sage: G.vertices(sort=True) # optional - sage.rings.finite_rings + sage: R. = GF(3**3) + sage: S. = R[] + sage: G.add_vertex(a**2) + sage: G.add_vertex(x) + sage: G.vertices(sort=True) [a^2, x] And that the bug described in :trac:`9610` is gone:: @@ -2107,9 +2108,9 @@ cdef class CGraphBackend(GenericGraphBackend): Ensure that :trac:`13664` is fixed :: - sage: W = WeylGroup(["A",1]) # optional - sage.combinat sage.groups - sage: G = W.cayley_graph() # optional - sage.combinat sage.groups - sage: Graph(G).degree() # optional - sage.combinat sage.groups + sage: W = WeylGroup(["A",1]) # needs sage.combinat sage.groups + sage: G = W.cayley_graph() # needs sage.combinat sage.groups + sage: Graph(G).degree() # needs sage.combinat sage.groups [1, 1] sage: h = Graph() sage: h.add_edge(1,2,"a") @@ -4406,9 +4407,9 @@ cdef class CGraphBackend(GenericGraphBackend): TESTS:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H._backend.is_connected() # optional - sage.modules + sage: P = posets.PentagonPoset() # needs sage.modules + sage: H = P._hasse_diagram # needs sage.modules + sage: H._backend.is_connected() # needs sage.modules True """ cdef int v_int @@ -4548,7 +4549,7 @@ cdef class CGraphBackend(GenericGraphBackend): At first, the following graph is acyclic:: sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] }) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -4589,9 +4590,9 @@ cdef class CGraphBackend(GenericGraphBackend): TESTS:: - sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # optional - sage.modules - sage: g = DiGraph(m) # optional - sage.modules - sage: g.is_directed_acyclic(certificate=True) # optional - sage.modules + sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # needs sage.modules + sage: g = DiGraph(m) # needs sage.modules + sage: g.is_directed_acyclic(certificate=True) # needs sage.modules (True, [0, 2, 1]) """ if not self._directed: diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index a8de583d4db..2eecc1a69d0 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -446,17 +446,18 @@ cdef class StaticSparseBackend(CGraphBackend): :: - sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") # optional - sage.combinat - sage: gi = DiGraph(g, data_structure="static_sparse") # optional - sage.combinat - sage: gi.edges(sort=True)[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") + sage: gi = DiGraph(g, data_structure="static_sparse") + sage: gi.edges(sort=True)[0] ('000', '000', '0') - sage: sorted(gi.edges_incident('111')) # optional - sage.combinat + sage: sorted(gi.edges_incident('111')) [('111', '110', '0'), ('111', '111', '1'), ('111', '112', '2'), ('111', '113', '3')] - sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # optional - sage.combinat + sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # needs sage.combinat True :: @@ -671,10 +672,10 @@ cdef class StaticSparseBackend(CGraphBackend): :: sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend - sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # optional - sage.combinat - sage: g.has_edge('00', '01', '1') # optional - sage.combinat + sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # needs sage.combinat + sage: g.has_edge('00', '01', '1') # needs sage.combinat True - sage: g.has_edge('00', '01', '0') # optional - sage.combinat + sage: g.has_edge('00', '01', '0') # needs sage.combinat False """ try: diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index cfaff95ccde..b5462299058 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -731,8 +731,8 @@ def tarjan_strongly_connected_components(G): Checking against NetworkX:: - sage: import networkx # optional - networkx - sage: for i in range(10): # long time # optional - networkx + sage: import networkx # needs networkx + sage: for i in range(10): # long time # needs networkx ....: g = digraphs.RandomDirectedGNP(100,.05) ....: h = g.networkx_graph() ....: scc1 = g.strongly_connected_components() @@ -1023,8 +1023,8 @@ def spectral_radius(G, prec=1e-10): sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)]) sage: e_min, e_max = spectral_radius(G, 1e-14) - sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) - sage: e_min < e < e_max + sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) # needs sage.modules + sage: e_min < e < e_max # needs sage.modules True sage: G.spectral_radius() # abs tol 1e-9 @@ -1032,6 +1032,7 @@ def spectral_radius(G, prec=1e-10): A larger example:: + sage: # needs sage.modules sage: G = DiGraph() sage: G.add_edges((i,i+1) for i in range(200)) sage: G.add_edge(200,0) @@ -1060,7 +1061,7 @@ def spectral_radius(G, prec=1e-10): sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)]) sage: spectral_radius(G, 1e-14) # abs tol 1e-14 (2.414213562373094, 2.414213562373095) - sage: max(G.adjacency_matrix().eigenvalues(AA)) + sage: max(G.adjacency_matrix().eigenvalues(AA)) # needs sage.modules 2.414213562373095? Some bipartite graphs:: @@ -1091,7 +1092,7 @@ def spectral_radius(G, prec=1e-10): ... ValueError: precision (=1.00000000000000e-20) is too small - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.modules ....: G = digraphs.RandomDirectedGNM(10,35) ....: if not G.is_strongly_connected(): ....: continue diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 635d5554329..f707ee2a968 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -45,7 +45,6 @@ from .generic_graph import GenericGraph from .graph import Graph from sage.rings.integer import Integer -from sage.misc.decorators import rename_keyword from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import @@ -161,7 +160,7 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph(P, partition, check=False) sage: B.left {0, 1, 2, 3, 4} - sage: B.show() # optional - sage.plot + sage: B.show() # needs sage.plot :: @@ -198,16 +197,17 @@ class BipartiteGraph(Graph): #. From a reduced adjacency matrix:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # optional - sage.modules + sage: M [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: H = BipartiteGraph(M); H # optional - sage.modules + sage: H = BipartiteGraph(M); H Bipartite graph on 11 vertices - sage: H.edges(sort=True) # optional - sage.modules + sage: H.edges(sort=True) [(0, 7, None), (0, 8, None), (0, 10, None), @@ -224,9 +224,9 @@ class BipartiteGraph(Graph): :: - sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # optional - sage.modules - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules - sage: B.edges(sort=True) # optional - sage.modules + sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # needs sage.modules + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules + sage: B.edges(sort=True) # needs sage.modules [(0, 5, None), (1, 5, None), (1, 6, None), @@ -244,13 +244,14 @@ class BipartiteGraph(Graph): :: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: B.edges(sort=True) # optional - sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: B.edges(sort=True) [(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)] - sage: B.weighted() # optional - sage.modules sage.rings.finite_rings + sage: B.weighted() True #. From an alist file:: @@ -264,7 +265,7 @@ class BipartiteGraph(Graph): ....: 1 2 4 7 \n") ....: f.flush() ....: B = BipartiteGraph(f.name) - sage: B.is_isomorphic(H) # optional - sage.modules + sage: B.is_isomorphic(H) # needs sage.modules True #. From a ``graph6`` string:: @@ -307,14 +308,15 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph('F?^T_\n', partition=[[0, 1, 2], [3, 4, 5, 6]], check=False) sage: B.left {0, 1, 2} - sage: B.show() # optional - sage.plot + sage: B.show() # needs sage.plot #. From a NetworkX bipartite graph:: - sage: import networkx # optional - networkx - sage: G = graphs.OctahedralGraph() # optional - networkx - sage: N = networkx.make_clique_bipartite(G.networkx_graph()) # optional - networkx - sage: B = BipartiteGraph(N) # optional - networkx + sage: # needs networkx + sage: import networkx + sage: G = graphs.OctahedralGraph() + sage: N = networkx.make_clique_bipartite(G.networkx_graph()) + sage: B = BipartiteGraph(N) TESTS: @@ -328,15 +330,16 @@ class BipartiteGraph(Graph): Ensure that we can construct a ``BipartiteGraph`` with isolated vertices via the reduced adjacency matrix (:trac:`10356`):: - sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) # optional - sage.modules - sage: a # optional - sage.modules + sage: # needs sage.modules + sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) + sage: a Bipartite graph on 4 vertices - sage: a.vertices(sort=True) # optional - sage.modules + sage: a.vertices(sort=True) [0, 1, 2, 3] - sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) # optional - sage.modules - sage: g.vertices(sort=True) # optional - sage.modules + sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) + sage: g.vertices(sort=True) [0, 1, 2, 3, 4, 5, 6, 7] - sage: sorted(g.left.union(g.right)) # optional - sage.modules + sage: sorted(g.left.union(g.right)) [0, 1, 2, 3, 4, 5, 6, 7] Make sure that loops are not allowed (:trac:`23275`):: @@ -1291,10 +1294,10 @@ def is_bipartite(self, certificate=False): EXAMPLES:: - sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # optional - numpy - sage: g.is_bipartite() # optional - numpy + sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # needs numpy + sage: g.is_bipartite() # needs numpy True - sage: g.is_bipartite(certificate=True) # random # optional - numpy + sage: g.is_bipartite(certificate=True) # random # needs numpy (True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1}) TESTS:: @@ -1466,7 +1469,7 @@ def plot(self, *args, **kwds): EXAMPLES:: sage: B = BipartiteGraph(graphs.CycleGraph(20)) - sage: B.plot() # optional - sage.plot + sage: B.plot() # needs sage.plot Graphics object consisting of 41 graphics primitives """ if "pos" not in kwds: @@ -1511,14 +1514,16 @@ def matching_polynomial(self, algorithm="Godsil", name=None): sage: x = polygen(QQ) sage: g = BipartiteGraph(graphs.CompleteBipartiteGraph(16, 16)) - sage: bool(factorial(16) * laguerre(16, x^2) == g.matching_polynomial(algorithm='rook')) # optional - sage.symbolic + sage: bool(factorial(16) * laguerre(16, x^2) # needs sage.symbolic + ....: == g.matching_polynomial(algorithm='rook')) True Compute the matching polynomial of a line with `60` vertices:: - sage: from sage.functions.orthogonal_polys import chebyshev_U # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import chebyshev_U # needs sage.symbolic sage: g = next(graphs.trees(60)) - sage: chebyshev_U(60, x/2) == BipartiteGraph(g).matching_polynomial(algorithm='rook') # optional - sage.symbolic + sage: (chebyshev_U(60, x/2) # needs sage.symbolic + ....: == BipartiteGraph(g).matching_polynomial(algorithm='rook')) True The matching polynomial of a tree is equal to its characteristic @@ -1627,7 +1632,7 @@ def perfect_matchings(self, labels=False): sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(4, 4)) sage: len(list(B.perfect_matchings())) 24 - sage: B.matching_polynomial(algorithm='rook')(0) # optional - sage.modules + sage: B.matching_polynomial(algorithm='rook')(0) # needs sage.modules 24 TESTS:: @@ -1804,26 +1809,27 @@ def save_afile(self, fname): EXAMPLES:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # optional - sage.modules + sage: M [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: b = BipartiteGraph(M) # optional - sage.modules - sage: import tempfile # optional - sage.modules - sage: with tempfile.NamedTemporaryFile() as f: # optional - sage.modules + sage: b = BipartiteGraph(M) + sage: import tempfile + sage: with tempfile.NamedTemporaryFile() as f: ....: b.save_afile(f.name) ....: b2 = BipartiteGraph(f.name) - sage: b.is_isomorphic(b2) # optional - sage.modules + sage: b.is_isomorphic(b2) True TESTS:: sage: import tempfile sage: f = tempfile.NamedTemporaryFile() - sage: for order in range(3, 13, 3): # optional - sage.combinat + sage: for order in range(3, 13, 3): # needs sage.combinat ....: num_chks = int(order / 3) ....: num_vars = order - num_chks ....: partition = (list(range(num_vars)), list(range(num_vars, num_vars+num_chks))) @@ -1921,78 +1927,81 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Bipartite graphs that are not weighted will return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: B = BipartiteGraph(M) # optional - sage.modules - sage: N = B.reduced_adjacency_matrix() # optional - sage.modules - sage: N # optional - sage.modules + sage: B = BipartiteGraph(M) + sage: N = B.reduced_adjacency_matrix(); N [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: N == M # optional - sage.modules + sage: N == M True - sage: N[0,0].parent() # optional - sage.modules + sage: N[0,0].parent() Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 # optional - sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 [1.0 1.0 1.0 0.0 0.0 0.0 0.0] [1.0 0.0 0.0 1.0 1.0 0.0 0.0] [0.0 1.0 0.0 1.0 0.0 1.0 0.0] [1.0 1.0 0.0 1.0 0.0 0.0 1.0] - sage: N2[0, 0].parent() # optional - sage.modules + sage: N2[0, 0].parent() Real Double Field Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) # optional - sage.modules - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules - sage: N = B.reduced_adjacency_matrix() # optional - sage.modules - sage: N == M # optional - sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) + sage: N = B.reduced_adjacency_matrix() + sage: N == M True - sage: N[0,0].parent() # optional - sage.modules + sage: N[0,0].parent() Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules - sage: N2[0, 0].parent() # optional - sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) + sage: N2[0, 0].parent() Real Double Field Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is specified:: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: N = B.reduced_adjacency_matrix(sparse=False) # optional - sage.modules sage.rings.finite_rings - sage: N == M # optional - sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: N = B.reduced_adjacency_matrix(sparse=False) + sage: N == M True - sage: N[0,0].parent() # optional - sage.modules sage.rings.finite_rings + sage: N[0,0].parent() Finite Field in a of size 2^2 - sage: N2 = B.reduced_adjacency_matrix(base_ring=F) # optional - sage.modules sage.rings.finite_rings - sage: N2[0, 0].parent() # optional - sage.modules sage.rings.finite_rings + sage: N2 = B.reduced_adjacency_matrix(base_ring=F) + sage: N2[0, 0].parent() Finite Field in a of size 2^2 TESTS:: sage: B = BipartiteGraph() - sage: B.reduced_adjacency_matrix() # optional - sage.modules + sage: B.reduced_adjacency_matrix() # needs sage.modules [] - sage: M = Matrix([[0,0], [0,0]]) # optional - sage.modules - sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # optional - sage.modules + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # needs sage.modules True - sage: M = Matrix([[10,2/3], [0,0]]) # optional - sage.modules - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules - sage: M == B.reduced_adjacency_matrix() # optional - sage.modules + sage: M = Matrix([[10,2/3], [0,0]]) # needs sage.modules + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules + sage: M == B.reduced_adjacency_matrix() # needs sage.modules True An error is raised if the specified base ring is not compatible with the type of the weights of the bipartite graph:: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: B.reduced_adjacency_matrix(base_ring=RDF) Traceback (most recent call last): ... TypeError: float() argument must be a string or a ...number, not 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement' @@ -2098,14 +2107,14 @@ class :class:`MixedIntegerLinearProgram Maximum matching in a cycle graph:: sage: G = BipartiteGraph(graphs.CycleGraph(10)) - sage: G.matching() # optional - networkx + sage: G.matching() # needs networkx [(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)] The size of a maximum matching in a complete bipartite graph using Eppstein:: sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5)) - sage: G.matching(algorithm="Eppstein", value_only=True) + sage: G.matching(algorithm="Eppstein", value_only=True) # needs networkx 4 TESTS: @@ -2123,11 +2132,11 @@ class :class:`MixedIntegerLinearProgram sage: G = graphs.CycleGraph(4) sage: B = BipartiteGraph([(u,v,2) for u,v in G.edges(sort=True, labels=0)]) - sage: sorted(B.matching(use_edge_labels=True)) + sage: sorted(B.matching(use_edge_labels=True)) # needs networkx [(0, 3, 2), (1, 2, 2)] - sage: B.matching(use_edge_labels=True, value_only=True) # optional - networkx + sage: B.matching(use_edge_labels=True, value_only=True) # needs networkx 4 - sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') # needs networkx 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP') 4 @@ -2139,11 +2148,13 @@ class :class:`MixedIntegerLinearProgram Traceback (most recent call last): ... ValueError: use_edge_labels cannot be used with "Hopcroft-Karp" or "Eppstein" - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Hopcroft-Karp') # optional - networkx + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Hopcroft-Karp') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Eppstein') # optional - networkx + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Eppstein') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') # needs networkx 2 sage: B.matching(use_edge_labels=False, value_only=True, algorithm='LP') 2 @@ -2154,23 +2165,23 @@ class :class:`MixedIntegerLinearProgram sage: for e in G.edges(sort=True): ....: G.set_edge_label(e[0], e[1], int(e[0]) + int(e[1])) sage: G.allow_multiple_edges(True) - sage: G.matching(use_edge_labels=True, value_only=True) + sage: G.matching(use_edge_labels=True, value_only=True) # needs networkx 444 Empty bipartite graph and bipartite graphs without edges:: sage: B = BipartiteGraph() sage: algorithms = ["Hopcroft-Karp", "Eppstein", "Edmonds", "LP"] - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True sage: B.add_vertex(1, left=True) sage: B.add_vertex(2, left=True) sage: B.add_vertex(3, right=True) - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True """ if algorithm is None: @@ -2214,7 +2225,6 @@ class :class:`MixedIntegerLinearProgram raise ValueError('algorithm must be "Hopcroft-Karp", ' '"Eppstein", "Edmonds" or "LP"') - @rename_keyword(deprecation=32238, verbosity='verbose') def vertex_cover(self, algorithm="Konig", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -2285,13 +2295,14 @@ def vertex_cover(self, algorithm="Konig", value_only=False, On the Cycle Graph:: sage: B = BipartiteGraph(graphs.CycleGraph(6)) - sage: len(B.vertex_cover()) # optional - networkx + sage: len(B.vertex_cover()) # needs networkx 3 - sage: B.vertex_cover(value_only=True) # optional - networkx + sage: B.vertex_cover(value_only=True) # needs networkx 3 The two algorithms should return the same result:: + sage: # needs numpy sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) sage: vc1 = g.vertex_cover(algorithm="Konig") sage: vc2 = g.vertex_cover(algorithm="Cliquer") @@ -2303,7 +2314,7 @@ def vertex_cover(self, algorithm="Konig", value_only=False, Giving a non connected bipartite graph:: sage: B = BipartiteGraph(graphs.CycleGraph(4) * 2) - sage: len(B.vertex_cover()) + sage: len(B.vertex_cover()) # needs networkx 4 Empty bipartite graph and bipartite graphs without edges:: diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index d8c50f220e3..3126086babc 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -67,8 +67,8 @@ cdef extern from "bliss_cpp/bliss_find_automorphisms.h": cdef int encoding_numbits(int n): r""" - Return the number of bits needed to encode the ``n`` numbers from ``1`` to ``n``. In - other words, the last bit set in ``n``. + Return the number of bits needed to encode the `n` numbers from `1` to + `n`. In other words, the last bit set in `n`. """ if n <= 0: return 0 @@ -437,12 +437,13 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True sage: g.is_isomorphic(canonical_form(g, return_graph=True)) # optional - bliss True - sage: g1 = graphs.RandomGNP(100, .4) # optional - bliss - sage: r = Permutations(range(100)).random_element() # optional - bliss - sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) # optional - bliss - sage: g1 = canonical_form(g1, return_graph=True) # optional - bliss - sage: g2 = canonical_form(g2, return_graph=True) # optional - bliss - sage: g2 == g2 # optional - bliss + sage: # optional - bliss + sage: g1 = graphs.RandomGNP(100, .4) + sage: r = Permutations(range(100)).random_element() + sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) + sage: g1 = canonical_form(g1, return_graph=True) + sage: g2 = canonical_form(g2, return_graph=True) + sage: g2 == g2 True sage: g = Graph({1: [2]}) @@ -476,11 +477,12 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True Check that it works with non hashable non sortable edge labels (relying on string representations of the labels):: - sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) # optional - sage.modules - sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) # optional - sage.modules - sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss sage.modules - sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss sage.modules - sage: g1can == g2can # optional - bliss sage.modules + sage: # needs sage.modules + sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) + sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) + sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss + sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss + sage: g1can == g2can # optional - bliss True Check that :trac:`32395` is fixed:: @@ -664,12 +666,12 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): - ``G`` -- a Sage graph - - ``partition`` -- ``list``(default: ``None``); a partition of the vertices + - ``partition`` -- ``list`` (default: ``None``); a partition of the vertices of ``G`` into color classes. Defaults to ``None``, which is equivalent to a partition of size 1. - - ``use_edge_labels`` -- boolean (default: ``True``); whether to consider edge - labels + - ``use_edge_labels`` -- boolean (default: ``True``); whether to consider + edge labels EXAMPLES:: @@ -677,44 +679,45 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): Computing the automorphism group of a graph or digraph:: - sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: D = DiGraph(G.edges(sort=True)) # optional - bliss - sage: automorphism_group(D).cardinality() # optional - bliss + sage: D = DiGraph(G.edges(sort=True)) + sage: automorphism_group(D).cardinality() 2 - Observe that the order 12 is given by permuting the first three vertices, or the last two - in the case of a graph, while only the latter two are possible in the case of a directed - graph. + Observe that the order 12 is given by permuting the first three vertices, or + the last two in the case of a graph, while only the latter two are possible + in the case of a directed graph. Partitioning the vertices into classes:: - sage: G = graphs.CompleteMultipartiteGraph([3, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([3, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() 2 - sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() 4 - - sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() 2 Partitioning the edges into classes:: - sage: G = Graph(graphs.CompleteMultipartiteGraph([8, 2]), sparse=True) # optional - bliss - sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss + sage: # optional - bliss + sage: G = Graph(graphs.CompleteMultipartiteGraph([8, 2]), sparse=True) + sage: for i,j in G.edges(labels=False, sort=False): ....: if 0 <= i < 3: ....: G.set_edge_label(i, j, "A") ....: if 3 <= i < 6: ....: G.set_edge_label(i, j, "B") ....: if 6 <= i < 8: ....: G.set_edge_label(i, j, "C") - - sage: factor(automorphism_group(G).cardinality()) # optional - bliss + sage: factor(automorphism_group(G).cardinality()) 2^4 * 3^2 - sage: automorphism_group(G,[[0],[1],[2,3],[4,5],[6,7],[8],[9]]).cardinality() # optional - bliss + sage: automorphism_group(G,[[0],[1],[2,3],[4,5],[6,7],[8],[9]]).cardinality() 4 TESTS:: @@ -724,66 +727,73 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss True - sage: G = graphs.HeawoodGraph() # optional - bliss - sage: p = G.bipartite_sets() # optional - bliss - sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss - sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss + sage: # optional - bliss + sage: G = graphs.HeawoodGraph() + sage: p = G.bipartite_sets() + sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) + sage: automorphism_group(G, partition=p).is_isomorphic(A) True - sage: G = graphs.CompleteMultipartiteGraph([5,7,11]) + sage: G = graphs.CompleteMultipartiteGraph([5, 7, 11]) sage: B = automorphism_group(G) # optional - bliss - sage: B.cardinality() == prod(factorial(n) for n in [5,7,11]) # optional - bliss + sage: B.cardinality() == prod(factorial(n) for n in [5, 7, 11]) # optional - bliss True - sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True)# optional - bliss - sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss + sage: # optional - bliss + sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True) + sage: for i,j in G.edges(labels=False, sort=False): ....: if 0 <= i < 3: ....: G.set_edge_label(i, j, "A") ....: if 3 <= i < 6: ....: G.set_edge_label(i, j, "B") ....: if 6 <= i < 8: ....: G.set_edge_label(i, j, "C") - sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] ) # optional - bliss + sage: card = automorphism_group(G).cardinality() + sage: card == prod(factorial(n) for n in [3, 3, 2, 8, 8, 5, 2]) True - sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] ) # optional - bliss + sage: card = automorphism_group(G, use_edge_labels=False).cardinality() + sage: card == prod(factorial(n) for n in [8, 8, 8, 5, 3]) True - sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] ) # optional - bliss + sage: card = automorphism_group(G, [[0 .. 7], [8 .. 11] ,[12 .. 28]]).cardinality() + sage: card == prod(factorial(n) for n in [3, 3, 2, 4, 4, 8, 5]) True - sage: G = Graph() # optional - bliss - sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss - [(9,13), (18,19), (17,18), (16,17), (15,16), (14,15), (12,9), (11,12), - (10,11), (7,8), (6,7), (5,6), (3,4), (2,3), (0,1)] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: # optional - bliss + sage: G = Graph() + sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) # random + ((12,13), (11,12), (10,11), (9,10), (7,8), (6,7), (5,6), (3,4), + (2,3), (1,0), (18,19), (17,18), (16,17), (15,16), (14,15)) + sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) True + sage: # optional - bliss + sage: G = Graph() sage: alpha = "abcdefghijklmnopqrstuvwxyz" - - sage: G = Graph() # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss - [('r','t'), ('s','r'), ('p','s'), ('q','p'), ('o','q'), ('l','n'), - ('m','l'), ('j','m'), ('k','j'), ('i','h'), ('f','i'), ('g','f'), - ('e','d'), ('c','e'), ('a','b')] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) + (('m','n'), ('l','m'), ('k','l'), ('j','k'), ('h','i'), + ('g','h'), ('f','g'), ('d','e'), ('c','d'), ('s','t'), + ('r','s'), ('q','r'), ('p','q'), ('o','p'), ('a','b')) + sage: A.cardinality() == prod(factorial(n) for n in [2, 3, 4, 5, 6]) True - sage: gg = graphs.CompleteGraph(5) # optional - bliss - sage: gg.allow_loops(True) # optional - bliss - sage: gg.add_edge(0,0) # optional - bliss - sage: gg.add_edge(1,1) # optional - bliss - sage: automorphism_group(gg).cardinality() # optional - bliss + sage: # optional - bliss + sage: gg = graphs.CompleteGraph(5) + sage: gg.allow_loops(True) + sage: gg.add_edge(0, 0) + sage: gg.add_edge(1, 1) + sage: automorphism_group(gg).cardinality() 12 - sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() # optional - bliss + sage: automorphism_group(gg, [[0], [1, 2, 3, 4]]).cardinality() 6 """ # We need this to convert the numbers from to diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 9de214115f9..0f6e83565ee 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -99,11 +99,12 @@ def centrality_betweenness(G, bint exact=False, bint normalize=True): Compare with NetworkX:: - sage: import networkx # optional - networkx - sage: g = graphs.RandomGNP(100, .2) # optional - networkx - sage: nw = networkx.betweenness_centrality(g.networkx_graph()) # optional - networkx - sage: sg = centrality_betweenness(g) # optional - networkx - sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 # optional - networkx + sage: # needs networkx + sage: import networkx + sage: g = graphs.RandomGNP(100, .2) + sage: nw = networkx.betweenness_centrality(g.networkx_graph()) + sage: sg = centrality_betweenness(g) + sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 0 Stupid cases:: @@ -637,34 +638,36 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): The result is correct:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 sage: m = random.randint(1, n * (n - 1) / 2) sage: k = random.randint(1, n) - sage: g = graphs.RandomGNM(n, m) # optional - networkx - sage: topk = centrality_closeness_top_k(g, k) # optional - networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx - sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx + sage: g = graphs.RandomGNM(n, m) + sage: topk = centrality_closeness_top_k(g, k) + sage: centr = g.centrality_closeness(algorithm='BFS') + sage: sorted_centr = sorted(centr.values(), reverse=True) + sage: len(topk) == min(k, len(sorted_centr)) True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) True Directed case:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 sage: m = random.randint(1, n * (n - 1)) sage: k = random.randint(1, n) - sage: g = digraphs.RandomDirectedGNM(n, m) # optional - networkx - sage: topk = centrality_closeness_top_k(g, k) # optional - networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx - sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx + sage: g = digraphs.RandomDirectedGNM(n, m) + sage: topk = centrality_closeness_top_k(g, k) + sage: centr = g.centrality_closeness(algorithm='BFS') + sage: sorted_centr = sorted(centr.values(), reverse=True) + sage: len(topk) == min(k, len(sorted_centr)) True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) True """ cdef list res diff --git a/src/sage/graphs/cliquer.pyx b/src/sage/graphs/cliquer.pyx index 9ff02b8572e..6f232d97e16 100644 --- a/src/sage/graphs/cliquer.pyx +++ b/src/sage/graphs/cliquer.pyx @@ -115,7 +115,7 @@ def all_max_clique(graph): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.cliques_maximum() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -302,7 +302,7 @@ def clique_number(graph): sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index b694b552ee8..119cd892265 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -417,20 +417,20 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): The 5-cycle or the Petersen Graph are not transitively orientable:: sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate = True) + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip (False, None) sage: g = graphs.PetersenGraph() - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (False, None) But the Bull graph is:: sage: g = graphs.BullGraph() - sage: is_comparability(g) + sage: is_comparability(g) # needs sage.numerical.mip True - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (True, Digraph on 5 vertices) - sage: is_comparability(g, certificate = True)[1].is_transitive() + sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException @@ -642,7 +642,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, sage: p1 = Permutation([nn+1 for nn in perm[0]]) sage: p2 = Permutation([nn+1 for nn in perm[1]]) sage: p = p2 * p1.inverse() - sage: p.show(representation="braid") # optional - sage.plot + sage: p.show(representation="braid") # needs sage.plot TESTS: @@ -664,7 +664,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, Then with MILP:: sage: from sage.graphs.comparability import is_permutation - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: p = Permutations(10).random_element() ....: g1 = graphs.PermutationGraph(p) ....: isit, certif = is_permutation(g1, algorithm="MILP", certificate=True) @@ -745,15 +745,15 @@ def is_transitive(g, certificate=False): (0, 2) sage: digraphs.RandomDirectedGNP(30,.2).is_transitive() False - sage: D = digraphs.DeBruijn(5, 2) # optional - sage.combinat - sage: D.is_transitive() # optional - sage.combinat + sage: D = digraphs.DeBruijn(5, 2) # needs sage.combinat + sage: D.is_transitive() # needs sage.combinat False - sage: cert = D.is_transitive(certificate=True) # optional - sage.combinat - sage: D.has_edge(*cert) # optional - sage.combinat + sage: cert = D.is_transitive(certificate=True) # needs sage.combinat + sage: D.has_edge(*cert) # needs sage.combinat False - sage: bool(D.shortest_path(*cert)) # optional - sage.combinat + sage: bool(D.shortest_path(*cert)) # needs sage.combinat True - sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # optional - networkx + sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # needs networkx True """ cdef int n = g.order() diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index c2100141f30..ff0cabb8f37 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -258,12 +258,12 @@ def connected_components_subgraphs(G): sage: from sage.graphs.connectivity import connected_components_subgraphs sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(G) - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(D) - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot sage: L = D.connected_components_subgraphs() - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot TESTS: @@ -1361,25 +1361,25 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver A basic application on a ``PappusGraph``:: sage: from sage.graphs.connectivity import vertex_connectivity - sage: g=graphs.PappusGraph() - sage: vertex_connectivity(g) + sage: g = graphs.PappusGraph() + sage: vertex_connectivity(g) # needs sage.numerical.mip 3 - sage: g.vertex_connectivity() + sage: g.vertex_connectivity() # needs sage.numerical.mip 3 In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of cardinality `1`:: sage: g = graphs.GridGraph([ 3,3 ]) - sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) - sage: len(setA) == 1 or len(setB) == 1 + sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) # needs sage.numerical.mip + sage: len(setA) == 1 or len(setB) == 1 # needs sage.numerical.mip True A vertex cut in a tree is any internal vertex:: sage: tree = graphs.RandomTree(15) - sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) - sage: tree.degree(cut_vertex) > 1 + sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) # needs sage.numerical.mip + sage: tree.degree(cut_vertex) > 1 # needs sage.numerical.mip True When ``value_only = True``, this function is optimized for small @@ -1388,41 +1388,41 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver It is the case for connected graphs which are not connected:: sage: g = 2 * graphs.PetersenGraph() - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 Or if they are just 1-connected:: sage: g = graphs.PathGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 1 For directed graphs, the strong connectivity is tested through the dedicated function:: sage: g = digraphs.ButterflyGraph(3) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 A complete graph on `10` vertices is `9`-connected:: sage: g = graphs.CompleteGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 A complete digraph on `10` vertices is `9`-connected:: sage: g = DiGraph(graphs.CompleteGraph(10)) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 When parameter ``k`` is set, we only check for the existence of a vertex cut of order at least ``k``:: sage: g = graphs.PappusGraph() - sage: vertex_connectivity(g, k=3) + sage: vertex_connectivity(g, k=3) # needs sage.numerical.mip True - sage: vertex_connectivity(g, k=4) + sage: vertex_connectivity(g, k=4) # needs sage.numerical.mip False TESTS: @@ -1441,13 +1441,13 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver sage: from sage.graphs.connectivity import is_strongly_connected sage: from sage.graphs.connectivity import is_connected sage: empty = Graph() - sage: vertex_connectivity(empty) + sage: vertex_connectivity(empty) # needs sage.numerical.mip 0 - sage: vertex_connectivity(empty, k=1) == is_connected(empty) + sage: vertex_connectivity(empty, k=1) == is_connected(empty) # needs sage.numerical.mip True - sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() + sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() # needs sage.numerical.mip True - sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) + sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) # needs sage.numerical.mip True If ``G`` is not a Sage (Di)Graph, an error is raised:: @@ -1460,16 +1460,16 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver Complete Graph with loops or multiple edges (:trac:`25589`):: sage: G = Graph([(0, 1), (0, 1)], multiedges=True) - sage: G.vertex_connectivity() + sage: G.vertex_connectivity() # needs sage.numerical.mip 1 sage: G = graphs.CompleteGraph(4) sage: G.allow_loops(True) sage: G.add_edge(0, 0) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) sage: G.allow_multiple_edges(True) sage: G.add_edge(0, 1) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) """ from sage.graphs.generic_graph import GenericGraph @@ -2379,21 +2379,21 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan") sage: G.is_isomorphic(spqr_tree_to_graph(T)) True - sage: T2 = spqr_tree(G, algorithm='cleave') - sage: G.is_isomorphic(spqr_tree_to_graph(T2)) + sage: T2 = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: G.is_isomorphic(spqr_tree_to_graph(T2)) # needs sage.numerical.mip True sage: G = Graph([(0, 1)], multiedges=True) - sage: T = spqr_tree(G, algorithm='cleave') - sage: T.vertices(sort=True) + sage: T = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: T.vertices(sort=True) # needs sage.numerical.mip [('Q', Multi-graph on 2 vertices)] - sage: G.is_isomorphic(spqr_tree_to_graph(T)) + sage: G.is_isomorphic(spqr_tree_to_graph(T)) # needs sage.numerical.mip True sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan') sage: T.vertices(sort=True) [('Q', Multi-graph on 2 vertices)] sage: G.add_edge(0, 1) - sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) + sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) # needs sage.numerical.mip [('P', Multi-graph on 2 vertices)] sage: from collections import Counter @@ -2401,24 +2401,24 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: Counter(u[0] for u in T) Counter({'R': 1}) - sage: T = G.spqr_tree(algorithm="cleave") - sage: Counter(u[0] for u in T) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: Counter(u[0] for u in T) # needs sage.numerical.mip Counter({'R': 1}) sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 15), ('R', 1), ('S', 15)] - sage: T = G.spqr_tree(algorithm="cleave") - sage: sorted(Counter(u[0] for u in T).items()) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # needs sage.numerical.mip [('P', 15), ('R', 1), ('S', 15)] sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 60), ('R', 1), ('S', 75)] - sage: T = G.spqr_tree(algorithm="cleave") # long time - sage: sorted(Counter(u[0] for u in T).items()) # long time + sage: T = G.spqr_tree(algorithm="cleave") # long time # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # long time # needs sage.numerical.mip [('P', 60), ('R', 1), ('S', 75)] TESTS:: @@ -2814,7 +2814,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ self.mem = MemoryAllocator() @@ -2861,7 +2861,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ if self.component_type == 0: @@ -4344,8 +4344,8 @@ def is_triconnected(G): Comparing different methods on random graphs that are not always triconnected:: - sage: G = graphs.RandomBarabasiAlbert(50, 3) # optional - networkx - sage: G.is_triconnected() == G.vertex_connectivity(k=3) # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 3) # needs networkx + sage: G.is_triconnected() == G.vertex_connectivity(k=3) # needs networkx True .. SEEALSO:: diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index b1d046ee25d..a8e6e9997b1 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -357,7 +357,7 @@ class DiGraph(GenericGraph): sage: g = DiGraph([[1..12], lambda i,j: i != j and i.divides(j)]) sage: g.vertices(sort=True) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() # optional - sage.modules + sage: g.adjacency_matrix() # needs sage.modules [0 1 1 1 1 1 1 1 1 1 1 1] [0 0 0 1 0 1 0 1 0 1 0 1] [0 0 0 0 0 1 0 0 1 0 0 1] @@ -377,28 +377,28 @@ class DiGraph(GenericGraph): - an adjacency matrix:: - sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # optional - sage.modules + sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # needs sage.modules ....: [0, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]); M [0 1 1 1 0] [0 0 0 0 0] [0 0 0 0 1] [0 0 0 0 0] [0 0 0 0 0] - sage: DiGraph(M) # optional - sage.modules + sage: DiGraph(M) # needs sage.modules Digraph on 5 vertices - sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # optional - sage.modules + sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # needs sage.modules [ 0 1 -1] [ -1 0 -1/2] [ 1 1/2 0] - sage: G = DiGraph(M, sparse=True, weighted=True); G # optional - sage.modules + sage: G = DiGraph(M, sparse=True, weighted=True); G # needs sage.modules Digraph on 3 vertices - sage: G.weighted() # optional - sage.modules + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # optional - sage.modules + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] @@ -406,7 +406,7 @@ class DiGraph(GenericGraph): [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: DiGraph(M) # optional - sage.modules + sage: DiGraph(M) # needs sage.modules Digraph on 6 vertices #. A ``dig6`` string: Sage automatically recognizes whether a string is in @@ -429,17 +429,17 @@ class DiGraph(GenericGraph): #. A NetworkX MultiDiGraph:: - sage: import networkx # optional - networkx - sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Multi-digraph on 5 vertices #. A NetworkX digraph:: - sage: import networkx # optional - networkx - sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph directed Graph (see also @@ -453,11 +453,12 @@ class DiGraph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -479,18 +480,19 @@ class DiGraph(GenericGraph): Demonstrate that digraphs using the static backend are equal to mutable graphs but can be used as dictionary keys:: - sage: import networkx # optional - networkx - sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: G = DiGraph(g) # optional - networkx - sage: G_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx - sage: H_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx - sage: H_imm is G_imm # optional - networkx + sage: # needs networkx + sage: import networkx + sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) + sage: G = DiGraph(g) + sage: G_imm = DiGraph(G, data_structure="static_sparse") + sage: H_imm = DiGraph(G, data_structure="static_sparse") + sage: H_imm is G_imm False - sage: H_imm == G_imm == G # optional - networkx + sage: H_imm == G_imm == G True - sage: {G_imm:1}[H_imm] # optional - networkx + sage: {G_imm:1}[H_imm] 1 - sage: {G_imm:1}[G] # optional - networkx + sage: {G_imm:1}[G] Traceback (most recent call last): ... TypeError: This graph is mutable, and thus not hashable. Create an @@ -500,10 +502,10 @@ class DiGraph(GenericGraph): specifying the ``immutable`` optional argument (not only by ``data_structure='static_sparse'`` as above):: - sage: J_imm = DiGraph(G, immutable=True) # optional - networkx - sage: J_imm == G_imm # optional - networkx + sage: J_imm = DiGraph(G, immutable=True) # needs networkx + sage: J_imm == G_imm # needs networkx True - sage: type(J_imm._backend) == type(G_imm._backend) # optional - networkx + sage: type(J_imm._backend) == type(G_imm._backend) # needs networkx True From a list of vertices and a list of edges:: @@ -515,7 +517,7 @@ class DiGraph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # optional - networkx + sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # needs networkx Digraph on 0 vertices """ _directed = True @@ -532,12 +534,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: loads(dumps(D)) == D True - sage: a = matrix(2,2,[1,2,0,1]) # optional - sage.modules - sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules + sage: a = matrix(2,2,[1,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[3,2,0,1]) # optional - sage.modules - sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules + sage: a = matrix(2,2,[3,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the DiGraph is built from another DiGraph @@ -580,9 +582,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3}, ....: 3:{5:4},4:{5:1,6:5},5:{4:1,6:7,5:1}} sage: grafo3 = DiGraph(B, weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() # optional - sage.modules - sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # optional - sage.modules - sage: grafo4.shortest_path(0, 6, by_weight=True) # optional - sage.modules + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Building a DiGraph with ``immutable=False`` returns a mutable graph:: @@ -923,8 +925,8 @@ def is_directed(self): # Properties def is_directed_acyclic(self, certificate=False): - """ - Return whether the digraph is acyclic or not. + r""" + Check whether the digraph is acyclic or not. A directed graph is acyclic if for any vertex `v`, there is no directed path that starts and ends at `v`. Every directed acyclic graph (DAG) @@ -943,8 +945,8 @@ def is_directed_acyclic(self, certificate=False): * When ``certificate=True``: * If the graph is acyclic, returns a pair ``(True, ordering)`` where - ``ordering`` is a list of the vertices such that ``u`` appears - before ``v`` in ``ordering`` if ``u, v`` is an edge. + ``ordering`` is a list of the vertices such that `u` appears + before `v` in ``ordering`` if `uv` is an edge. * Else, returns a pair ``(False, cycle)`` where ``cycle`` is a list of vertices representing a circuit in the graph. @@ -954,7 +956,7 @@ def is_directed_acyclic(self, certificate=False): At first, the following graph is acyclic:: sage: D = DiGraph({0:[1, 2, 3], 4:[2, 5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10]}) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -1272,8 +1274,7 @@ def in_degree(self, vertices=None, labels=False): return self._backend.in_degree(vertices) elif labels: return {v: d for v, d in self.in_degree_iterator(vertices, labels=labels)} - else: - return list(self.in_degree_iterator(vertices, labels=labels)) + return list(self.in_degree_iterator(vertices, labels=labels)) def in_degree_iterator(self, vertices=None, labels=False): """ @@ -1343,8 +1344,7 @@ def out_degree(self, vertices=None, labels=False): return self._backend.out_degree(vertices) elif labels: return {v: d for v, d in self.out_degree_iterator(vertices, labels=labels)} - else: - return list(self.out_degree_iterator(vertices, labels=labels)) + return list(self.out_degree_iterator(vertices, labels=labels)) def out_degree_iterator(self, vertices=None, labels=False): """ @@ -1457,12 +1457,12 @@ def degree_polynomial(self): EXAMPLES:: - sage: G = posets.PentagonPoset().hasse_diagram() # optional - sage.matrix - sage: G.degree_polynomial() # optional - sage.matrix + sage: G = posets.PentagonPoset().hasse_diagram() # needs sage.modules + sage: G.degree_polynomial() # needs sage.modules x^2 + 3*x*y + y^2 sage: G = posets.BooleanLattice(4).hasse_diagram() - sage: G.degree_polynomial().factor() + sage: G.degree_polynomial().factor() # needs sage.libs.pari (x + y)^4 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1563,7 +1563,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: dcycle=DiGraph(cycle) sage: cycle.size() 5 - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 And in this situation, for any edge `uv` of the first graph, `uv` of @@ -1573,9 +1573,9 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: while not g.num_edges(): ....: g = graphs.RandomGNP(5,.3) sage: dg = DiGraph(g) - sage: feedback = dg.feedback_edge_set() + sage: feedback = dg.feedback_edge_set() # needs sage.numerical.mip sage: u,v,l = next(g.edge_iterator()) - sage: (u,v) in feedback or (v,u) in feedback + sage: (u,v) in feedback or (v,u) in feedback # needs sage.numerical.mip True TESTS: @@ -1583,7 +1583,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Comparing with/without constraint generation. Also double-checks issue :trac:`12833`:: - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: g = digraphs.RandomDirectedGNP(10, .3) ....: x = g.feedback_edge_set(value_only=True) ....: y = g.feedback_edge_set(value_only=True, @@ -1594,34 +1594,37 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Loops are part of the feedback edge set (:trac:`23989`):: + sage: # needs sage.combinat sage: D = digraphs.DeBruijn(2, 2) sage: sorted(D.loops(labels=None)) [('00', '00'), ('11', '11')] - sage: FAS = D.feedback_edge_set(value_only=False) - sage: all(l in FAS for l in D.loops(labels=None)) + sage: FAS = D.feedback_edge_set(value_only=False) # needs sage.numerical.mip + sage: all(l in FAS for l in D.loops(labels=None)) # needs sage.numerical.mip True - sage: FAS2 = D.feedback_edge_set(value_only=False, constraint_generation=False) - sage: len(FAS) == len(FAS2) + sage: FAS2 = D.feedback_edge_set(value_only=False, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: len(FAS) == len(FAS2) # needs sage.numerical.mip True Check that multi-edges are properly taken into account:: sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 sage: dcycle.allow_multiple_edges(True) sage: dcycle.add_edges(dcycle.edges(sort=True)) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 10 - sage: dcycle.feedback_edge_set(value_only=True, constraint_generation=False) + sage: dcycle.feedback_edge_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) 10 Strongly connected components are well handled (:trac:`23989`):: sage: g = digraphs.Circuit(3) * 2 sage: g.add_edge(0, 3) - sage: g.feedback_edge_set(value_only=True) + sage: g.feedback_edge_set(value_only=True) # needs sage.numerical.mip 2 """ # It would be a pity to start a LP if the digraph is already acyclic @@ -1631,14 +1634,16 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if self.has_loops(): # We solve the problem on a copy without loops of the digraph D = DiGraph(self.edges(sort=False), multiedges=self.allows_multiple_edges(), loops=True) - D.allow_loops(False) + loops = D.loops(labels=None) + D.delete_edges(loops) + D.allow_loops(False, check=False) FAS = D.feedback_edge_set(constraint_generation=constraint_generation, value_only=value_only, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if value_only: - return FAS + self.number_of_loops() + return FAS + len(loops) else: - return FAS + self.loops(labels=None) + return FAS + loops if not self.is_strongly_connected(): # If the digraph is not strongly connected, we solve the problem on @@ -1647,6 +1652,8 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, FAS = 0 if value_only else [] for h in self.strongly_connected_components_subgraphs(): + if not h.size(): + continue if value_only: FAS += h.feedback_edge_set(constraint_generation=constraint_generation, value_only=True, solver=solver, verbose=verbose, @@ -1691,9 +1698,8 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if isok: if value_only: return sum(1 for e in self.edge_iterator(labels=False) if val[e]) - else: - # listing the edges contained in the MFAS - return [e for e in self.edge_iterator(labels=False) if val[e]] + # listing the edges contained in the MFAS + return [e for e in self.edge_iterator(labels=False) if val[e]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -1736,28 +1742,92 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if value_only: return sum(1 for e in self.edge_iterator(labels=False) if b_sol[e]) - else: - return [e for e in self.edge_iterator(labels=False) if b_sol[e]] + return [e for e in self.edge_iterator(labels=False) if b_sol[e]] # Construction - def reverse(self): + def reverse(self, immutable=None): """ Return a copy of digraph with edges reversed in direction. + INPUT: + + - ``immutable`` -- boolean (default: ``None``); whether to return an + immutable digraph or not. By default (``None``), the returned digraph + has the same setting than ``self``. That is, if ``self`` is immutable, + the returned digraph also is. + EXAMPLES:: - sage: D = DiGraph({0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1]}) - sage: D.reverse() + sage: adj = {0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1]} + sage: D = DiGraph(adj) + sage: R = D.reverse(); R Reverse of (): Digraph on 6 vertices + sage: H = R.reverse() + sage: adj == H.to_dictionary() + True + + TESTS:: + + sage: adj = {0: [1, 1], 1: [1]} + sage: D = DiGraph(adj, immutable=True, multiedges=True, loops=True) + sage: R = D.reverse() + sage: R.is_immutable() and R.allows_loops() and R.allows_multiple_edges() + True + sage: adj == R.reverse().to_dictionary(multiple_edges=True) + True + + Check the behavior of parameter ``immutable``:: + + sage: D = DiGraph([(0, 1)], immutable=False) + sage: R = D.reverse() + sage: R.is_immutable() + False + sage: R = D.reverse(immutable=True) + sage: R.is_immutable() + True + sage: H = R.reverse() + sage: H.is_immutable() + True + sage: H = R.reverse(immutable=False) + sage: H.is_immutable() + False """ - H = DiGraph(multiedges=self.allows_multiple_edges(), loops=self.allows_loops()) + from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(self._backend, DenseGraphBackend): + data_structure = "dense" + else: + data_structure = "sparse" + + H = DiGraph(data_structure=data_structure, + multiedges=self.allows_multiple_edges(), loops=self.allows_loops(), + pos=copy(self._pos), weighted=self.weighted(), + hash_labels=self._hash_labels) H.add_vertices(self) H.add_edges((v, u, d) for u, v, d in self.edge_iterator()) name = self.name() if name is None: name = '' H.name("Reverse of (%s)" % name) + + attributes_to_copy = ('_assoc', '_embedding') + for attr in attributes_to_copy: + if hasattr(self, attr): + copy_attr = {} + old_attr = getattr(self, attr) + if isinstance(old_attr, dict): + for v, value in old_attr.items(): + try: + copy_attr[v] = value.copy() + except AttributeError: + copy_attr[v] = copy(value) + setattr(H, attr, copy_attr) + else: + setattr(H, attr, copy(old_attr)) + + if immutable or (immutable is None and self.is_immutable()): + return H.copy(immutable=True) + return H def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): @@ -2071,10 +2141,10 @@ def reverse_edges(self, edges, inplace=True, multiedges=None): [(0, 5, None), (1, 0, None), (2, 1, None), (3, 2, None), (4, 3, None), (5, 4, None)] - sage: D = digraphs.Kautz(2, 3) # optional - sage.combinat - sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # optional - sage.combinat + sage: D = digraphs.Kautz(2, 3) # needs sage.combinat + sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # needs sage.combinat ....: multiedges=True) - sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # optional - sage.combinat + sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # needs sage.combinat True """ tempG = self if inplace else copy(self) @@ -2181,7 +2251,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, [2, 2, 2] sage: G.eccentricity(algorithm='Floyd-Warshall-Cython') [2, 2, 2] - sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # optional - networkx + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [5, 5, 4] sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_Boost') [5, 5, 4] @@ -2446,11 +2516,12 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, EXAMPLES:: - sage: G = digraphs.DeBruijn(5,4) # optional - sage.combinat - sage: G.diameter() # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(5,4) + sage: G.diameter() 4 - sage: G = digraphs.GeneralizedDeBruijn(9, 3) # optional - sage.combinat - sage: G.diameter() # optional - sage.combinat + sage: G = digraphs.GeneralizedDeBruijn(9, 3) + sage: G.diameter() 2 TESTS:: @@ -3144,7 +3215,7 @@ def topological_sort(self, implementation="default"): sage: D = DiGraph({0: [1, 2, 3], 4: [2, 5], 1: [8], 2: [7], 3: [7], ....: 5: [6, 7], 7: [8], 6: [9], 8: [10], 9: [10]}) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.topological_sort() [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10] @@ -3156,9 +3227,9 @@ def topological_sort(self, implementation="default"): Using the NetworkX implementation :: - sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # optional - networkx + sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # needs networkx [0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10] - sage: all(s.index(u) < s.index(v) # optional - networkx + sage: all(s.index(u) < s.index(v) # needs networkx ....: for u, v in D.edges(sort=False, labels=False)) True @@ -3225,14 +3296,14 @@ def topological_sort_generator(self): EXAMPLES:: sage: D = DiGraph({0: [1, 2], 1: [3], 2: [3, 4]}) - sage: D.plot(layout='circular').show() # optional - sage.plot - sage: list(D.topological_sort_generator()) # optional - sage.modules sage.rings.finite_rings + sage: D.plot(layout='circular').show() # needs sage.plot + sage: list(D.topological_sort_generator()) # needs sage.modules sage.rings.finite_rings [[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3], [0, 2, 4, 1, 3], [0, 1, 2, 4, 3]] :: - sage: for sort in D.topological_sort_generator(): + sage: for sort in D.topological_sort_generator(): # needs sage.modules sage.rings.finite_rings ....: for u, v in D.edge_iterator(labels=False): ....: if sort.index(u) > sort.index(v): ....: print("this should never happen") @@ -3592,7 +3663,7 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Flow polytopes can also be built through the ``polytopes.`` object:: - sage: polytopes.flow_polytope(digraphs.Path(5)) # optional - sage.geometry.polyhedron + sage: polytopes.flow_polytope(digraphs.Path(5)) # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex EXAMPLES: @@ -3600,26 +3671,27 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A commutative square:: sage: G = DiGraph({1: [2, 3], 2: [4], 3: [4]}) - sage: fl = G.flow_polytope(); fl # optional - sage.geometry.polyhedron + sage: fl = G.flow_polytope(); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0)) Using a different order for the edges of the graph:: - sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl # optional - sage.geometry.polyhedron + sage: ordered_edges = G.edges(sort=True, key=lambda x: x[0] - x[1]) + sage: fl = G.flow_polytope(edges=ordered_edges); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1)) A tournament on 4 vertices:: sage: H = digraphs.TransitiveTournament(4) - sage: fl = H.flow_polytope(); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(); fl # needs sage.geometry.polyhedron A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 4 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 1, 0, 0, 0), A vertex at (0, 1, 0, 0, 0, 1), A vertex at (1, 0, 0, 0, 1, 0), @@ -3627,40 +3699,41 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Restricting to a subset of the edges:: - sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # needs sage.geometry.polyhedron ....: (2, 3, None), (0, 3, None)]); fl A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0)) Using a different choice of sources and sinks:: - sage: fl = H.flow_polytope(ends=([1], [3])); fl # optional - sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([1], [3])); fl A 1-dimensional polyhedron in QQ^6 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 0, 1, 0, 1), A vertex at (0, 0, 0, 0, 1, 0)) - sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl The empty polyhedron in QQ^6 - sage: fl = H.flow_polytope(ends=([3], [0])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([3], [0])); fl The empty polyhedron in QQ^6 - sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 5 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 1, 1, 0, 0), A vertex at (0, 1, 0, 0, 1, 0), A vertex at (1, 0, 0, 2, 0, 1), A vertex at (1, 0, 0, 1, 1, 0), A vertex at (0, 1, 0, 1, 0, 1)) - sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), ....: (2, 3, None), (0, 2, None), ....: (1, 3, None)], ....: ends=([0, 1], [2, 3])); fl A 2-dimensional polyhedron in QQ^5 defined as the convex hull of 4 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 0, 1, 1), A vertex at (1, 2, 1, 0, 0), A vertex at (1, 1, 0, 0, 1), @@ -3669,13 +3742,13 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A digraph with one source and two sinks:: sage: Y = DiGraph({1: [2], 2: [3, 4]}) - sage: Y.flow_polytope() # optional - sage.geometry.polyhedron + sage: Y.flow_polytope() # needs sage.geometry.polyhedron The empty polyhedron in QQ^3 A digraph with one vertex and no edge:: sage: Z = DiGraph({1: []}) - sage: Z.flow_polytope() # optional - sage.geometry.polyhedron + sage: Z.flow_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex @@ -3683,11 +3756,11 @@ def flow_polytope(self, edges=None, ends=None, backend=None): sage: G = DiGraph([(0, 1), (0,1)], multiedges=True); G Multi-digraph on 2 vertices - sage: P = G.flow_polytope(); P # optional - sage.geometry.polyhedron + sage: P = G.flow_polytope(); P # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.geometry.polyhedron + sage: P.vertices() # needs sage.geometry.polyhedron (A vertex at (1, 0), A vertex at (0, 1)) - sage: P.lines() # optional - sage.geometry.polyhedron + sage: P.lines() # needs sage.geometry.polyhedron () """ from sage.geometry.polyhedron.constructor import Polyhedron diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index b9a87601a47..3070cb2f37f 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -226,22 +226,23 @@ def ButterflyGraph(self, n, vertices='strings'): sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False) [(('00', 0), ('00', 1)), - (('00', 0), ('10', 1)), - (('00', 1), ('00', 2)), - (('00', 1), ('01', 2)), - (('01', 0), ('01', 1)), - (('01', 0), ('11', 1)), - (('01', 1), ('00', 2)), - (('01', 1), ('01', 2)), - (('10', 0), ('00', 1)), - (('10', 0), ('10', 1)), - (('10', 1), ('10', 2)), - (('10', 1), ('11', 2)), - (('11', 0), ('01', 1)), - (('11', 0), ('11', 1)), - (('11', 1), ('10', 2)), - (('11', 1), ('11', 2))] - sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(sort=True, labels=False) + (('00', 0), ('10', 1)), + (('00', 1), ('00', 2)), + (('00', 1), ('01', 2)), + (('01', 0), ('01', 1)), + (('01', 0), ('11', 1)), + (('01', 1), ('00', 2)), + (('01', 1), ('01', 2)), + (('10', 0), ('00', 1)), + (('10', 0), ('10', 1)), + (('10', 1), ('10', 2)), + (('10', 1), ('11', 2)), + (('11', 0), ('01', 1)), + (('11', 0), ('11', 1)), + (('11', 1), ('10', 2)), + (('11', 1), ('11', 2))] + sage: digraphs.ButterflyGraph(2, vertices='vectors').edges(sort=True, # needs sage.modules sage.rings.finite_rings + ....: labels=False) [(((0, 0), 0), ((0, 0), 1)), (((0, 0), 0), ((1, 0), 1)), (((0, 0), 1), ((0, 0), 2)), @@ -338,7 +339,7 @@ def Path(self, n): [0, 1, 2, 3, 4] sage: g.size() 4 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 """ g = DiGraph(n, name="Path") @@ -370,9 +371,11 @@ def StronglyRegular(self, n): A Strongly Regular digraph satisfies the condition `AJ = JA = kJ` where `A` is the adjacency matrix:: + sage: # needs sage.modules sage: g = digraphs.StronglyRegular(7); g Strongly regular digraph: Digraph on 7 vertices - sage: A = g.adjacency_matrix()*ones_matrix(7); B = ones_matrix(7)*g.adjacency_matrix() + sage: A = g.adjacency_matrix()*ones_matrix(7) + sage: B = ones_matrix(7)*g.adjacency_matrix() sage: A == B == A[0, 0]*ones_matrix(7) True @@ -380,7 +383,7 @@ def StronglyRegular(self, n): Wrong parameter:: - sage: digraphs.StronglyRegular(73) + sage: digraphs.StronglyRegular(73) # needs sage.modules Traceback (most recent call last): ... ValueError: strongly regular digraph with 73 vertices not yet implemented @@ -413,16 +416,16 @@ def Paley(self, q): A Paley digraph has `n * (n-1) / 2` edges, its underlying graph is a clique, and so it is a tournament:: - sage: g = digraphs.Paley(7); g + sage: g = digraphs.Paley(7); g # needs sage.rings.finite_rings Paley digraph with parameter 7: Digraph on 7 vertices - sage: g.size() == g.order() * (g.order() - 1) / 2 + sage: g.size() == g.order() * (g.order() - 1) / 2 # needs sage.rings.finite_rings True - sage: g.to_undirected().is_clique() + sage: g.to_undirected().is_clique() # needs sage.rings.finite_rings True A Paley digraph is always self-complementary:: - sage: g.complement().is_isomorphic(g) + sage: g.complement().is_isomorphic(g) # needs sage.rings.finite_rings True TESTS: @@ -470,7 +473,7 @@ def TransitiveTournament(self, n): [0, 1, 2, 3, 4] sage: g.size() 10 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 .. SEEALSO:: @@ -890,15 +893,16 @@ def DeBruijn(self, k, n, vertices='strings'): de Bruijn digraph of degree 2 and diameter 2:: - sage: db = digraphs.DeBruijn(2, 2); db + sage: db = digraphs.DeBruijn(2, 2); db # needs sage.combinat De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices - sage: db.order(), db.size() + sage: db.order(), db.size() # needs sage.combinat (4, 8) - sage: db.diameter() + sage: db.diameter() # needs sage.combinat 2 Building a de Bruijn digraph on a different alphabet:: + sage: # needs sage.combinat sage: g = digraphs.DeBruijn(['a', 'b'], 2) sage: g.vertices(sort=True) ['aa', 'ab', 'ba', 'bb'] @@ -914,20 +918,20 @@ def DeBruijn(self, k, n, vertices='strings'): Alphabet of null size or words of length zero:: - sage: digraphs.DeBruijn(5, 0) + sage: digraphs.DeBruijn(5, 0) # needs sage.combinat De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex - sage: digraphs.DeBruijn(0, 0) + sage: digraphs.DeBruijn(0, 0) # needs sage.combinat De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices :trac:`22355`:: - sage: db = digraphs.DeBruijn(2, 2, vertices='strings') - sage: db.vertices(sort=True) + sage: db = digraphs.DeBruijn(2, 2, vertices='strings') # needs sage.combinat + sage: db.vertices(sort=True) # needs sage.combinat ['00', '01', '10', '11'] sage: h = digraphs.DeBruijn(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3] - sage: db.is_isomorphic(h) + sage: db.is_isomorphic(h) # needs sage.combinat True sage: digraphs.DeBruijn(0, 0, vertices='integers') De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices @@ -998,8 +1002,9 @@ def GeneralizedDeBruijn(self, n, d): EXAMPLES:: sage: GB = digraphs.GeneralizedDeBruijn(8, 2) - sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110', 7: '111'}) + sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '000', 1: '001', 2: '010', 3: '011', + 4: '100', 5: '101', 6: '110', 7: '111'}) TESTS: @@ -1054,14 +1059,15 @@ def ImaseItoh(self, n, d): EXAMPLES:: sage: II = digraphs.ImaseItoh(8, 2) - sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100', 7: '101'}) + sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '010', 1: '011', 2: '000', 3: '001', + 4: '110', 5: '111', 6: '100', 7: '101'}) sage: II = digraphs.ImaseItoh(12, 2) - sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) - sage: b + sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) # needs sage.combinat + sage: b # needs sage.combinat True - sage: D # random isomorphism + sage: D # random isomorphism # needs sage.combinat {0: '202', 1: '201', 2: '210', 3: '212', 4: '121', 5: '120', 6: '102', 7: '101', 8: '010', 9: '012', 10: '021', 11: '020'} @@ -1132,23 +1138,24 @@ def Kautz(self, k, D, vertices='strings'): EXAMPLES:: + sage: # needs sage.combinat sage: K = digraphs.Kautz(2, 3) - sage: b,D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) + sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) sage: b True sage: D # random isomorphism {'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6, '120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3} - sage: K = digraphs.Kautz([1,'a','B'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'a','B'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] - sage: K = digraphs.Kautz([1,'aA','BB'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'aA','BB'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), @@ -1160,12 +1167,12 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the degree is less than one:: - sage: G = digraphs.Kautz(0, 2) + sage: G = digraphs.Kautz(0, 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one - sage: G = digraphs.Kautz(['a'], 2) + sage: G = digraphs.Kautz(['a'], 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one @@ -1173,23 +1180,23 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the diameter of the graph is less than one:: - sage: G = digraphs.Kautz(2, 0) + sage: G = digraphs.Kautz(2, 0) # needs sage.combinat Traceback (most recent call last): ... ValueError: diameter must be greater than or equal to one :trac:`22355`:: - sage: K = digraphs.Kautz(2, 2, vertices='strings') - sage: K.vertices(sort=True) + sage: K = digraphs.Kautz(2, 2, vertices='strings') # needs sage.combinat + sage: K.vertices(sort=True) # needs sage.combinat ['01', '02', '10', '12', '20', '21'] sage: h = digraphs.Kautz(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h = digraphs.Kautz([1,'aA','BB'], 2, vertices='integers') - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] @@ -1346,6 +1353,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGN(25) sage: D.num_verts() 25 @@ -1355,7 +1363,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): True sage: D.parent() is DiGraph True - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1382,12 +1390,13 @@ def RandomDirectedGNC(self, n, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNC(25) sage: D.is_directed_acyclic() True sage: D.topological_sort() [24, 23, ..., 1, 0] - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1583,12 +1592,13 @@ def RandomDirectedGNR(self, n, p, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNR(25, .2) sage: D.is_directed_acyclic() True sage: D.to_undirected().is_tree() True - sage: D.show() # long time + sage: D.show() # long time # needs sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 46baaf8ca73..a5a90cc0c0c 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -545,7 +545,7 @@ def is_distance_regular(G, parameters=False): sage: graphs.PathGraph(2).is_distance_regular(parameters=True) ([1, None], [None, 1]) - sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # optional - networkx + sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # needs networkx ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) """ @@ -843,8 +843,8 @@ cdef uint32_t * c_eccentricity_DHV(short_digraph sd) except NULL: TESTS: - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) # needs networkx + sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # needs networkx True """ cdef uint32_t n = sd.n @@ -1777,26 +1777,28 @@ def diameter(G, algorithm=None, source=None): Comparison of exact algorithms for graphs:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx - sage: d1 = diameter(G, algorithm='standard') # optional - networkx - sage: d2 = diameter(G, algorithm='iFUB') # optional - networkx - sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex()) # optional - networkx - sage: d4 = diameter(G, algorithm='DHV') # optional - networkx - sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!") # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: d1 = diameter(G, algorithm='standard') + sage: d2 = diameter(G, algorithm='iFUB') + sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex()) + sage: d4 = diameter(G, algorithm='DHV') + sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!") Comparison of lower bound algorithms:: - sage: lb2 = diameter(G, algorithm='2sweep') # optional - networkx - sage: lbm = diameter(G, algorithm='multi-sweep') # optional - networkx - sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # optional - networkx + sage: lb2 = diameter(G, algorithm='2sweep') # needs networkx + sage: lbm = diameter(G, algorithm='multi-sweep') # needs networkx + sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # needs networkx Comparison of exact algorithms for digraphs:: - sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) # optional - networkx - sage: d1 = diameter(D, algorithm='standard') # optional - networkx - sage: d2 = diameter(D, algorithm='DiFUB') # optional - networkx - sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex()) # optional - networkx - sage: d1 == d2 and d1 == d3 # optional - networkx + sage: # needs networkx + sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) + sage: d1 = diameter(D, algorithm='standard') + sage: d2 = diameter(D, algorithm='DiFUB') + sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex()) + sage: d1 == d2 and d1 == d3 True TESTS: @@ -2294,10 +2296,11 @@ def szeged_index(G, algorithm=None): Check that both algorithms return same value:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # long time - sage: a = szeged_index(G, algorithm='low') # long time - sage: b = szeged_index(G, algorithm='high') # long time - sage: a == b # long time + sage: # long time + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: a = szeged_index(G, algorithm='low') + sage: b = szeged_index(G, algorithm='high') + sage: a == b True The Szeged index of a directed circuit of order `n` is `(n-1)^2`:: @@ -2438,8 +2441,8 @@ def distances_distribution(G): The de Bruijn digraph dB(2,3):: - sage: D = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: D.distances_distribution() # optional - sage.combinat + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: D.distances_distribution() # needs sage.combinat {1: 1/4, 2: 11/28, 3: 5/14} """ cdef size_t n = G.order() diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index ed2fdd17183..4b664e3eb65 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -24,7 +24,7 @@ We compute the size of a minimum dominating set of the Petersen graph:: sage: g = graphs.PetersenGraph() - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 3 We enumerate the minimal dominating sets of the 5-star graph:: @@ -137,7 +137,7 @@ def is_redundant(G, dom, focus=None): False """ dom = list(dom) - focus = list(G) if focus is None else list(focus) + focus = G if focus is None else set(focus) # dominator[v] (for v in focus) will be equal to: # - (0, None) if v has no neighbor in dom @@ -281,7 +281,7 @@ def dominating_sets(g, k=1, independent=False, total=False, Number of distance-`k` dominating sets of a Path graph of order 10:: sage: g = graphs.PathGraph(10) - sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip [1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10] If we build a graph from two disjoint stars, then link their centers we will @@ -290,15 +290,15 @@ def dominating_sets(g, k=1, independent=False, total=False, sage: g = 2 * graphs.StarGraph(5) sage: g.add_edge(0, 6) - sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip [1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12] The total dominating set of the Petersen graph has cardinality 4:: sage: G = graphs.PetersenGraph() - sage: G.dominating_set(total=True, value_only=True) + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip 4 - sage: sorted(G.dominating_sets(k=1)) + sage: sorted(G.dominating_sets(k=1)) # needs sage.numerical.mip [[0, 2, 6], [0, 3, 9], [0, 7, 8], @@ -312,6 +312,7 @@ def dominating_sets(g, k=1, independent=False, total=False, Independent distance-`k` dominating sets of a Path graph:: + sage: # needs sage.numerical.mip sage: G = graphs.PathGraph(6) sage: sorted(G.dominating_sets(k=1, independent=True)) [[1, 4]] @@ -323,6 +324,7 @@ def dominating_sets(g, k=1, independent=False, total=False, The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: + sage: # needs sage.numerical.mip sage: g = digraphs.Path(3) sage: g.dominating_set(value_only=True) 2 @@ -339,17 +341,24 @@ def dominating_sets(g, k=1, independent=False, total=False, TESTS:: sage: g = Graph([(0, 1)]) - sage: next(g.dominating_sets(k=-1)) + sage: next(g.dominating_sets(k=-1)) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the domination distance must be a non-negative integer + + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)]) + sage: L = list(G.dominating_sets()) + sage: len(L) + 6 """ g._scream_if_not_simple(allow_multiple_edges=True, allow_loops=not total) if not k: yield list(g) return - elif k < 0: + if k < 0: raise ValueError("the domination distance must be a non-negative integer") from sage.numerical.mip import MixedIntegerLinearProgram @@ -468,7 +477,7 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, A basic illustration on a ``PappusGraph``:: sage: g = graphs.PappusGraph() - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 5 If we build a graph from two disjoint stars, then link their centers we will @@ -477,34 +486,34 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, sage: g = 2 * graphs.StarGraph(5) sage: g.add_edge(0, 6) - sage: len(g.dominating_set()) + sage: len(g.dominating_set()) # needs sage.numerical.mip 2 - sage: len(g.dominating_set(independent=True)) + sage: len(g.dominating_set(independent=True)) # needs sage.numerical.mip 6 The total dominating set of the Petersen graph has cardinality 4:: sage: G = graphs.PetersenGraph() - sage: G.dominating_set(total=True, value_only=True) + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip 4 The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: sage: g = digraphs.Path(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 2 sage: g = graphs.PathGraph(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 1 Cardinality of distance-`k` dominating sets:: sage: G = graphs.PetersenGraph() - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip [10, 3, 1] sage: G = graphs.PathGraph(5) - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip [5, 2, 1] """ dom = next(dominating_sets(g, k=k, independent=independent, total=total, @@ -719,8 +728,8 @@ def _aux_with_rep(H, to_dom, u_next): # Here we use aux_with_rep twice to enumerate the minimal # dominating sets while avoiding repeated outputs - for (X, i) in _aux_with_rep(G, to_dom, u_next): - for (Y, j) in _aux_with_rep(G, to_dom, u_next): + for X, i in _aux_with_rep(G, to_dom, u_next): + for Y, j in _aux_with_rep(G, to_dom, u_next): if j >= i: # This is the first time we meet X: we output it yield X @@ -730,7 +739,7 @@ def _aux_with_rep(H, to_dom, u_next): break -def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): +def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True, k=1): r""" Return an iterator over the minimal dominating sets of a graph. @@ -741,7 +750,7 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): - ``to_dominate`` -- vertex iterable or ``None`` (default: ``None``); the set of vertices to be dominated. - - ``work_on_copy`` -- boolean (default: ``False``); whether or not to work on + - ``work_on_copy`` -- boolean (default: ``True``); whether or not to work on a copy of the input graph; if set to ``False``, the input graph will be modified (relabeled). @@ -780,32 +789,32 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets()) sage: pp = [{0, 2, 6}, - ....: {0, 9, 3}, - ....: {0, 8, 7}, - ....: {1, 3, 7}, - ....: {1, 4, 5}, - ....: {8, 1, 9}, - ....: {8, 2, 4}, - ....: {9, 2, 5}, - ....: {3, 5, 6}, - ....: {4, 6, 7}, - ....: {0, 8, 2, 9}, - ....: {0, 3, 6, 7}, - ....: {1, 3, 5, 9}, - ....: {8, 1, 4, 7}, - ....: {2, 4, 5, 6}, - ....: {0, 1, 2, 3, 4}, - ....: {0, 1, 2, 5, 7}, - ....: {0, 1, 4, 6, 9}, - ....: {0, 1, 5, 6, 8}, - ....: {0, 8, 3, 4, 5}, - ....: {0, 9, 4, 5, 7}, - ....: {8, 1, 2, 3, 6}, - ....: {1, 2, 9, 6, 7}, - ....: {9, 2, 3, 4, 7}, - ....: {8, 2, 3, 5, 7}, - ....: {8, 9, 3, 4, 6}, - ....: {8, 9, 5, 6, 7}] + ....: {0, 9, 3}, + ....: {0, 8, 7}, + ....: {1, 3, 7}, + ....: {1, 4, 5}, + ....: {8, 1, 9}, + ....: {8, 2, 4}, + ....: {9, 2, 5}, + ....: {3, 5, 6}, + ....: {4, 6, 7}, + ....: {0, 8, 2, 9}, + ....: {0, 3, 6, 7}, + ....: {1, 3, 5, 9}, + ....: {8, 1, 4, 7}, + ....: {2, 4, 5, 6}, + ....: {0, 1, 2, 3, 4}, + ....: {0, 1, 2, 5, 7}, + ....: {0, 1, 4, 6, 9}, + ....: {0, 1, 5, 6, 8}, + ....: {0, 8, 3, 4, 5}, + ....: {0, 9, 4, 5, 7}, + ....: {8, 1, 2, 3, 6}, + ....: {1, 2, 9, 6, 7}, + ....: {9, 2, 3, 4, 7}, + ....: {8, 2, 3, 5, 7}, + ....: {8, 9, 3, 4, 6}, + ....: {8, 9, 5, 6, 7}] sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp) True @@ -834,6 +843,19 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): sage: list(G.minimal_dominating_sets(k=3)) [{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}] + When parameter ``work_on_copy`` is ``False``, the input graph is modified + (relabeled):: + + sage: G = Graph([('A', 'B')]) + sage: _ = list(G.minimal_dominating_sets(work_on_copy=True)) + sage: set(G) == {'A', 'B'} + True + sage: _ = list(G.minimal_dominating_sets(work_on_copy=False)) + sage: set(G) == {'A', 'B'} + False + sage: set(G) == {0, 1} + True + TESTS: The empty graph is handled correctly:: @@ -889,6 +911,15 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): Traceback (most recent call last): ... ValueError: vertex (foo) is not a vertex of the graph + + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)]) + sage: L = list(G.minimal_dominating_sets()) + sage: len(L) + 6 + sage: {3, 'A'} in L + True """ def tree_search(H, plng, dom, i): r""" @@ -942,7 +973,8 @@ def tree_search(H, plng, dom, i): # We complete dom with can_ext -> canD canD = set().union(can_ext, dom) - if (not H.is_redundant(canD, V_next)) and set(dom) == set(_parent(H, canD, plng[i][1])): + if (not H.is_redundant(canD, V_next) + and set(dom) == set(_parent(H, canD, plng[i][1]))): # By construction, can_ext is a dominating set of # `V_next - N[dom]`, so canD dominates V_next. # If canD is a legitimate child of dom and is not redundant, we @@ -952,6 +984,12 @@ def tree_search(H, plng, dom, i): ## # end of tree-search routine + if k < 0: + raise ValueError("the domination distance must be a non-negative integer") + if not k: + yield set(G) if to_dominate is None else set(to_dominate) + return + int_to_vertex = list(G) vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} @@ -963,28 +1001,24 @@ def tree_search(H, plng, dom, i): raise ValueError(f"vertex ({u}) is not a vertex of the graph") vertices_to_dominate = {vertex_to_int[u] for u in to_dominate} - if k < 0: - raise ValueError("the domination distance must be a non-negative integer") - elif not k: - yield set(int_to_vertex) if to_dominate is None else set(to_dominate) + if not vertices_to_dominate: + # base case: vertices_to_dominate is empty + # the empty set/list is the only minimal DS of the empty set + yield set() return - elif k > 1: + if k > 1: # We build a graph H with an edge between u and v if these vertices are # at distance at most k in G H = G.__class__(G.order()) for u, ui in vertex_to_int.items(): - H.add_edges((ui, vertex_to_int[v]) for v in G.breadth_first_search(u, distance=k) if u != v) + H.add_edges((ui, vertex_to_int[v]) + for v in G.breadth_first_search(u, distance=k) if u != v) G = H elif work_on_copy: - G.relabel(perm=vertex_to_int) - else: G = G.relabel(perm=vertex_to_int, inplace=False) - - if not vertices_to_dominate: - # base case: vertices_to_dominate is empty - # the empty set/list is the only minimal DS of the empty set - yield set() - return + else: + # The input graph is modified + G.relabel(perm=vertex_to_int, inplace=True) peeling = _peel(G, vertices_to_dominate) @@ -1117,6 +1151,12 @@ def greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=Fals sage: G = graphs.PathGraph(5) sage: dom = greedy_dominating_set(G, vertices=[0, 1, 3, 4]) + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A')]) + sage: len(greedy_dominating_set(G)) + 1 + Check parameters:: sage: greedy_dominating_set(G, ordering="foo") diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py index 95850012885..ce2cd873c8b 100644 --- a/src/sage/graphs/dot2tex_utils.py +++ b/src/sage/graphs/dot2tex_utils.py @@ -74,7 +74,7 @@ def quoted_latex(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules + sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '\\left(\\begin{array}{rr}1 & 1 \\\\0 & 1 \\\\0 & 0\\end{array}\\right)' """ return re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x)) @@ -89,9 +89,9 @@ def quoted_str(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules + sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '[1 1]\\n\\\n[0 1]\\n\\\n[0 0]' - sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # optional - sage.modules + sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # needs sage.modules [1 1]\n\ [0 1]\n\ [0 0] diff --git a/src/sage/graphs/edge_connectivity.pyx b/src/sage/graphs/edge_connectivity.pyx index c4cf6a4f81b..02326437a54 100644 --- a/src/sage/graphs/edge_connectivity.pyx +++ b/src/sage/graphs/edge_connectivity.pyx @@ -56,10 +56,10 @@ cdef class GabowEdgeConnectivity: A random `d`-regular digraph is `d`-edge-connected:: sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity - sage: D = DiGraph(graphs.RandomRegular(6, 50)) # optional - networkx - sage: while not D.is_strongly_connected(): # optional - networkx + sage: D = DiGraph(graphs.RandomRegular(6, 50)) # needs networkx + sage: while not D.is_strongly_connected(): # needs networkx ....: D = DiGraph(graphs.RandomRegular(6, 50)) - sage: GabowEdgeConnectivity(D).edge_connectivity() # optional - networkx + sage: GabowEdgeConnectivity(D).edge_connectivity() # needs networkx 6 A complete digraph with `n` vertices is `n-1`-edge-connected:: @@ -72,15 +72,16 @@ cdef class GabowEdgeConnectivity: Check that we get the same result when with and without the DFS-based speed-up initialization proposed in [GKLP2021]_:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx - sage: D = DiGraph(G) # optional - networkx - sage: ec1 = GabowEdgeConnectivity(D, # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: D = DiGraph(G) + sage: ec1 = GabowEdgeConnectivity(D, ....: dfs_preprocessing=False).edge_connectivity() - sage: ec2 = GabowEdgeConnectivity(D, # optional - networkx + sage: ec2 = GabowEdgeConnectivity(D, ....: dfs_preprocessing=True).edge_connectivity() - sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, # optional - networkx + sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, ....: use_rec=True).edge_connectivity() - sage: ec1 == ec2 and ec2 == ec3 # optional - networkx + sage: ec1 == ec2 and ec2 == ec3 True TESTS: diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py index 43e0b683703..314d66aef43 100644 --- a/src/sage/graphs/generators/basic.py +++ b/src/sage/graphs/generators/basic.py @@ -179,13 +179,13 @@ def CircularLadderGraph(n): sage: for i in range(9): ....: k = graphs.CircularLadderGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ G = Graph(2 * n, name="Circular Ladder graph") G._circle_embedding(list(range(n)), radius=1, angle=pi/2) @@ -248,44 +248,47 @@ def CycleGraph(n): Compare plotting using the predefined layout and networkx:: - sage: import networkx # optional - networkx - sage: n = networkx.cycle_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx - sage: posdict23 = graphs.CycleGraph(23) # optional - networkx - sage: spring23.show() # long time # optional - networkx - sage: posdict23.show() # long time # optional - networkx + sage: # needs networkx sage.plot + sage: import networkx + sage: n = networkx.cycle_graph(23) + sage: spring23 = Graph(n) + sage: posdict23 = graphs.CycleGraph(23) + sage: spring23.show() # long time + sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CycleGraph`` constructor, which fills in the position dictionary:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CycleGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time TESTS: @@ -334,42 +337,45 @@ def CompleteGraph(n): We view many Complete graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CompleteGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time We compare to plotting with the spring-layout algorithm:: - sage: import networkx # optional - networkx + sage: # needs networkx sage.plot + sage: import networkx sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.complete_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare the constructors (results will vary):: - sage: import networkx # optional - networkx - sage: t = cputime() # optional - networkx - sage: n = networkx.complete_graph(389); spring389 = Graph(n) # optional - networkx - sage: cputime(t) # random # optional - networkx + sage: # needs networkx + sage: import networkx + sage: t = cputime() + sage: n = networkx.complete_graph(389); spring389 = Graph(n) + sage: cputime(t) # random 0.59203700000000126 sage: t = cputime() sage: posdict389 = graphs.CompleteGraph(389) @@ -378,12 +384,13 @@ def CompleteGraph(n): We compare plotting:: - sage: import networkx # optional - networkx - sage: n = networkx.complete_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.complete_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.CompleteGraph(23) - sage: spring23.show() # long time # optional - networkx sage.plot - sage: posdict23.show() # long time # optional - sage.plot + sage: spring23.show() # long time # needs sage.plot + sage: posdict23.show() # long time # needs sage.plot """ G = Graph(n, name="Complete graph") if n == 1: @@ -403,16 +410,17 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation): EXAMPLES: + sage: # needs numpy sage: from sage.graphs.generators.basic import CorrelationGraph sage: data = [[1,2,3], [4,5,6], [7,8,9999]] - sage: CG1 = CorrelationGraph(data, 0.9, False) # optional - numpy - sage: CG2 = CorrelationGraph(data, 0.9, True) # optional - numpy - sage: CG3 = CorrelationGraph(data, 0.1, True) # optional - numpy - sage: CG1.edges(sort=False) # optional - numpy + sage: CG1 = CorrelationGraph(data, 0.9, False) + sage: CG2 = CorrelationGraph(data, 0.9, True) + sage: CG3 = CorrelationGraph(data, 0.1, True) + sage: CG1.edges(sort=False) [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG2.edges(sort=False) # optional - numpy + sage: CG2.edges(sort=False) [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG3.edges(sort=False) # optional - numpy + sage: CG3.edges(sort=False) [(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)] """ @@ -477,20 +485,21 @@ def CompleteBipartiteGraph(p, q, set_position=True): Two ways of constructing the complete bipartite graph, using different layout algorithms:: - sage: import networkx # optional - networkx - sage: n = networkx.complete_bipartite_graph(389, 157) # long time # optional - networkx - sage: spring_big = Graph(n) # long time # optional - networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.complete_bipartite_graph(389, 157) # long time + sage: spring_big = Graph(n) # long time sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: - sage: n = networkx.complete_bipartite_graph(11, 17) # optional - networkx - sage: spring_med = Graph(n) # optional - networkx + sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx + sage: spring_med = Graph(n) # needs networkx sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17) Notice here how the spring-layout tends to center the nodes of `n1`:: - sage: spring_med.show() # long time # optional - networkx + sage: spring_med.show() # long time # needs networkx sage: posdict_med.show() # long time View many complete bipartite graphs with a Sage Graphics Array, with this @@ -501,29 +510,30 @@ def CompleteBipartiteGraph(p, q, set_position=True): sage: for i in range(9): ....: k = graphs.CompleteBipartiteGraph(i+1,4) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot We compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.complete_bipartite_graph(i+1,4) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time :trac:`12155`:: @@ -825,13 +835,13 @@ def Toroidal6RegularGrid2dGraph(p, q): sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5) sage: g.is_regular(k=6) True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True - sage: g.line_graph().is_vertex_transitive() # optional - sage.groups + sage: g.line_graph().is_vertex_transitive() # needs sage.groups True - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 300 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True TESTS: @@ -973,9 +983,9 @@ def GridGraph(dim_list): sage: dim = [randint(1,4) for i in range(4)] sage: g = graphs.GridGraph(dim) - sage: import networkx # optional - networkx - sage: h = Graph(networkx.grid_graph(list(dim))) # optional - networkx - sage: g.is_isomorphic(h) # optional - networkx + sage: import networkx # needs networkx + sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx + sage: g.is_isomorphic(h) # needs networkx True Trivial cases:: @@ -1110,18 +1120,19 @@ def LadderGraph(n): Create several ladder graphs in a Sage graphics array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ pos_dict = {} for i in range(n): @@ -1263,14 +1274,15 @@ def StarGraph(n): EXAMPLES:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx Compare the plots:: - sage: n = networkx.star_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: # needs networkx sage.plot + sage: n = networkx.star_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.StarGraph(23) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time sage: posdict23.show() # long time View many star graphs as a Sage Graphics Array @@ -1279,36 +1291,38 @@ def StarGraph(n): :: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.StarGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compared to plotting with the spring-layout algorithm :: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.star_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ G = Graph({0: list(range(1, n + 1))}, name="Star graph", format="dict_of_lists") G.set_pos({0: (0, 0)}) diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index 2835fbe987f..59517d128bb 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -414,7 +414,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False): The `(6,6)`-Knight Graph is Hamiltonian:: sage: G = graphs.KnightGraph( [6, 6] ) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True """ G, dimstr = ChessboardGraphGenerator(dim_list, diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 680402dc476..bf1aa04e933 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -48,32 +48,34 @@ def SymplecticPolarGraph(d, q, algorithm=None): Computation of the spectrum of `Sp(6,2)`:: - sage: g = graphs.SymplecticPolarGraph(6,2) + sage: g = graphs.SymplecticPolarGraph(6, 2) sage: g.is_strongly_regular(parameters=True) (63, 30, 13, 15) - sage: set(g.spectrum()) == {-5, 3, 30} + sage: set(g.spectrum()) == {-5, 3, 30} # needs sage.rings.number_field True The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are not isomorphic if `q` is odd:: - sage: G = graphs.SymplecticPolarGraph(4,3) + sage: G = graphs.SymplecticPolarGraph(4, 3) sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: O = graphs.OrthogonalPolarGraph(5,3) + + sage: # needs sage.libs.gap + sage: O = graphs.OrthogonalPolarGraph(5, 3) sage: O.is_strongly_regular(parameters=True) (40, 12, 2, 4) sage: O.is_isomorphic(G) False - sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time) # optional - sage.libs.gap - sage: S.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.libs.gap + sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time) + sage: S.is_strongly_regular(parameters=True) # not tested (long time) (1365, 340, 83, 85) TESTS:: - sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (85, 20, 3, 5) - sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) + sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) # needs sage.libs.pari (85, 20, 3, 5) sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah") Traceback (most recent call last): @@ -147,13 +149,14 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): The :meth:`Brouwer-Haemers graph ` is isomorphic to `VO^-(4,3)`:: - sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") - sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) + sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") # needs sage.libs.gap + sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # needs sage.libs.gap True Some examples from `Brouwer's table or strongly regular graphs `_:: + sage: # needs sage.libs.gap sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g Affine Polar Graph VO^-(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) @@ -165,6 +168,7 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): When ``sign is None``:: + sage: # needs sage.libs.gap sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g Affine Polar Graph VO^-(5,2): Graph on 32 vertices sage: g.is_strongly_regular(parameters=True) @@ -224,14 +228,14 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): Petersen graph:: sage: from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph - sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) A locally Petersen graph (a.k.a. Doro graph, a.k.a. Hall graph):: - sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # optional - sage.libs.gap - sage: g.is_distance_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # needs sage.libs.gap + sage: g.is_distance_regular(parameters=True) # needs sage.libs.gap ([10, 6, 4, None], [None, 1, 2, 5]) Various big and slow to build graphs: @@ -250,20 +254,20 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^+(6,3)`:: - sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (117, 36, 15, 9) `NO^-(6,3)`:: - sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (126, 45, 12, 18) `NO^{-,\perp}(5,5)`:: - sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: @@ -274,11 +278,12 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): TESTS:: - sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) + sage: g.is_strongly_regular(parameters=True) (45, 12, 3, 3) - sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) + sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) """ @@ -342,34 +347,35 @@ def OrthogonalPolarGraph(m, q, sign="+"): EXAMPLES:: - sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (130, 48, 20, 16) - sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (112, 30, 2, 10) - sage: G = graphs.OrthogonalPolarGraph(5,3); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(5,3); G Orthogonal Polar Graph O(5, 3): Graph on 40 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (135, 70, 37, 35) - sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (119, 54, 21, 27) TESTS:: - sage: G = graphs.OrthogonalPolarGraph(4,3,"") # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(4,3,"") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '-' or '+' when m is even - sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '' or '+' when m is odd @@ -417,43 +423,46 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): `NO^-(4,2)` is isomorphic to Petersen graph:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # needs sage.libs.gap NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) `NO^-(6,2)` and `NO^+(6,2)`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') + sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g NO^+(6, 2): Graph on 28 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (28, 15, 6, 10) `NO^+(8,2)`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (120, 63, 30, 36) Wilbrink's graphs for `q=5`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (325, 60, 15, 10) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) Wilbrink's graphs:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') + sage: g.is_strongly_regular(parameters=True) (136, 75, 42, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') + sage: g.is_strongly_regular(parameters=True) (120, 51, 18, 24) sage: g = graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices @@ -462,29 +471,33 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): TESTS:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g NO^+(4, 2): Graph on 6 vertices - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') + sage: g.is_strongly_regular(parameters=True) (15, 6, 1, 3) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (10, 3, 0, 1) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + + sage: # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') + sage: g.is_strongly_regular(parameters=True) (117, 36, 15, 9) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (126, 45, 12, 18) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') + sage: g.is_strongly_regular(parameters=True) (300, 104, 28, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') + sage: g.is_strongly_regular(parameters=True) (325, 144, 68, 60) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') # optional - sage.libs.gap + + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): ... ValueError: for m even q must be 2 or 3 @@ -565,9 +578,9 @@ def _polar_graph(m, q, g, intersection_size=None): TESTS:: sage: from sage.graphs.generators.classical_geometries import _polar_graph - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # optional - sage.libs.gap + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap Graph on 45 vertices - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # optional - sage.libs.gap + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # needs sage.libs.gap Graph on 27 vertices """ from sage.libs.gap.libgap import libgap @@ -609,20 +622,21 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): EXAMPLES:: - sage: G = graphs.UnitaryPolarGraph(4,2); G # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.UnitaryPolarGraph(4,2); G Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (45, 12, 3, 3) - sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) (165, 36, 3, 9) - sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) Unitary Polar Graph U(6, 2): Graph on 693 vertices TESTS:: - sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) - sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo") Traceback (most recent call last): @@ -676,18 +690,18 @@ def NonisotropicUnitaryPolarGraph(m, q): EXAMPLES:: - sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # needs sage.libs.gap NU(5, 2): Graph on 176 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (176, 135, 102, 108) TESTS:: - sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # needs sage.libs.gap (40, 27, 18, 18) - sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (540, 224, 88, 96) - sage: graphs.NonisotropicUnitaryPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): ... ValueError: q must be a prime power @@ -742,16 +756,16 @@ def UnitaryDualPolarGraph(m, q): The point graph of a generalized quadrangle (see :wikipedia:`Generalized_quadrangle`, [PT2009]_) of order (8,4):: - sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # optional - sage.libs.gap + sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # needs sage.libs.gap Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices - sage: G.is_strongly_regular(parameters=True) # long time # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (297, 40, 7, 5) Another way to get the generalized quadrangle of order (2,4):: - sage: G = graphs.UnitaryDualPolarGraph(4,2); G # optional - sage.libs.gap + sage: G = graphs.UnitaryDualPolarGraph(4,2); G # needs sage.libs.gap Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices - sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # optional - sage.libs.gap + sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # needs sage.libs.gap True A bigger graph:: @@ -763,7 +777,7 @@ def UnitaryDualPolarGraph(m, q): TESTS:: - sage: graphs.UnitaryDualPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.UnitaryDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, must be a prime or a finite field @@ -800,11 +814,11 @@ def SymplecticDualPolarGraph(m, q): TESTS:: - sage: G = graphs.SymplecticDualPolarGraph(6,2); G # optional - sage.libs.gap + sage: G = graphs.SymplecticDualPolarGraph(6,2); G # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices - sage: G.is_distance_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_distance_regular(parameters=True) # needs sage.libs.gap ([14, 12, 8, None], [None, 1, 3, 7]) - sage: graphs.SymplecticDualPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.SymplecticDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, must be a prime or a finite field @@ -848,28 +862,30 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): EXAMPLES:: - sage: g = graphs.TaylorTwographDescendantSRG(3); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.TaylorTwographDescendantSRG(3); g Taylor two-graph descendant SRG: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time, optional - sage.rings.finite_rings - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time, optional - sage.rings.finite_rings + sage: T = taylor_twograph(3) # long time + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True - sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (125, 52, 15, 26) TESTS:: - sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) # optional - sage.rings.finite_rings - sage: all(g.is_clique(x) for x in l) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) + sage: all(g.is_clique(x) for x in l) True - sage: graphs.TaylorTwographDescendantSRG(4) # optional - sage.rings.finite_rings + sage: graphs.TaylorTwographDescendantSRG(4) Traceback (most recent call last): ... ValueError: q must be an odd prime power - sage: graphs.TaylorTwographDescendantSRG(6) # optional - sage.rings.finite_rings + sage: graphs.TaylorTwographDescendantSRG(6) Traceback (most recent call last): ... ValueError: q must be an odd prime power @@ -922,9 +938,9 @@ def TaylorTwographSRG(q): EXAMPLES:: - sage: t = graphs.TaylorTwographSRG(3); t # optional - sage.rings.finite_rings + sage: t = graphs.TaylorTwographSRG(3); t # needs sage.rings.finite_rings Taylor two-graph SRG: Graph on 28 vertices - sage: t.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: t.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (28, 15, 6, 10) """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) @@ -959,13 +975,13 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): EXAMPLES:: - sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g # optional - sage.rings.finite_rings + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g AS(5); GQ(4, 6): Graph on 125 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (125, 28, 3, 7) - sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g # optional - sage.rings.finite_rings + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g AS(5)*; GQ(6, 4): Graph on 175 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (175, 30, 5, 5) """ from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -1029,35 +1045,38 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, using the built-in construction:: - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g # optional - sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g T2*(O,4)*; GQ(5, 3): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) supplying your own hyperoval:: - sage: F = GF(4,'b') # optional - sage.rings.finite_rings - sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') + sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) ....: for x in F] - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g # optional - sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g T2*(O,4); GQ(3, 5): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(4,'b') # repeating a point... - sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval @@ -1149,35 +1168,36 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h using the built-in constructions:: - sage: g = graphs.HaemersGraph(4); g # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(4); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) supplying your own hyperoval_matching:: - sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) TESTS:: - sage: F=GF(4,'b') # repeating a point... # optional - sage.rings.finite_rings - sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') # repeating a point... + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval - sage: g = graphs.HaemersGraph(8); g # not tested (long time) # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings (640, 71, 6, 8) """ @@ -1264,20 +1284,20 @@ def CossidentePenttilaGraph(q): For `q=3` one gets Sims-Gewirtz graph. :: - sage: g = graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(3) # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (56, 10, 0, 2) For `q>3` one gets new graphs. :: - sage: g = graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(5) # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (378, 52, 1, 8) TESTS:: - sage: g = graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time + sage: G = graphs.CossidentePenttilaGraph(7) # optional - gap_package_grape, long time + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape, long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): @@ -1372,9 +1392,10 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov using the built-in construction:: - sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -1382,23 +1403,25 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov supplying your own hyperoval:: + sage: # needs sage.rings.finite_rings sage: F = GF(8) - sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) ....: for x in F] - sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g # optional - sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) TESTS:: - sage: F = GF(8) # repeating a point... # optional - sage.rings.finite_rings - sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(8) # repeating a point... + sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] + sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings + sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... @@ -1467,13 +1490,14 @@ def OrthogonalDualPolarGraph(e, d, q): EXAMPLES:: - sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) + sage: G.is_distance_regular(True) ([7, 6, 4, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time # optional - sage.libs.gap - sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time + sage: G.is_distance_regular(True) # long time ([39, 36, 27, None], [None, 1, 4, 13]) - sage: G.order() # long time # optional - sage.libs.gap + sage: G.order() # long time 1120 REFERENCES: @@ -1482,17 +1506,18 @@ def OrthogonalDualPolarGraph(e, d, q): TESTS:: - sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) + sage: G.is_distance_regular(True) ([14, 12, 8, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time # optional - sage.libs.gap - sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time + sage: G.is_distance_regular(True) # long time ([28, 24, 16, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) + sage: G.is_distance_regular(True) ([21, 20, 16, None], [None, 1, 5, 21]) - sage: G = graphs.OrthogonalDualPolarGraph(1,4,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,4,2) + sage: G.is_distance_regular(True) ([15, 14, 12, 8, None], [None, 1, 3, 7, 15]) """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py index 071878d124e..ed89ce43abc 100644 --- a/src/sage/graphs/generators/degree_sequence.py +++ b/src/sage/graphs/generators/degree_sequence.py @@ -41,25 +41,25 @@ def DegreeSequence(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequence([3,3,3,3]) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: G = graphs.DegreeSequence([3,3,3,3]) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence])) @@ -93,15 +93,15 @@ def DegreeSequenceBipartite(s1, s2): If we are given as sequences ``[2,2,2,2,2]`` and ``[5,5]`` we are given as expected the complete bipartite graph `K_{2,5}`:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # optional - sage.modules - sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # optional - sage.modules + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # needs sage.modules + sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # needs sage.modules True Some sequences being incompatible if, for example, their sums are different, the functions raises a ``ValueError`` when no graph corresponding to the degree sequences exists:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # optional - sage.modules + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # needs sage.modules Traceback (most recent call last): ... ValueError: there exists no bipartite graph corresponding to the given degree sequences @@ -110,7 +110,7 @@ def DegreeSequenceBipartite(s1, s2): :trac:`12155`:: - sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # optional - sage.modules + sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # needs sage.modules Graph on 7 vertices """ from sage.combinat.integer_vector import gale_ryser_theorem @@ -147,20 +147,21 @@ def DegreeSequenceConfigurationModel(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # optional - networkx - sage: G.adjacency_matrix() # optional - networkx sage.modules + sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # needs networkx + sage: G.adjacency_matrix() # needs networkx sage.modules [0 1] [1 0] The output is allowed to contain both loops and multiple edges:: - sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] # optional - networkx - sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: # needs networkx + sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] + sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) + sage: G.order(), G.size() (20, 30) - sage: G.has_loops() or G.has_multiple_edges() # random # optional - networkx + sage: G.has_loops() or G.has_multiple_edges() # random True - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs sage.plot REFERENCE: @@ -191,9 +192,9 @@ def DegreeSequenceTree(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # optional - networkx + sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # needs networkx Graph on 9 vertices - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence])) @@ -219,9 +220,9 @@ def DegreeSequenceExpected(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # optional - networkx + sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # needs networkx Looped graph on 5 vertices - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot REFERENCE: diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index dd809a835af..b90795b86a1 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -103,8 +103,8 @@ def locally_GQ42_distance_transitive_graph(): EXAMPLES:: - sage: G = graphs.locally_GQ42_distance_transitive_graph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.locally_GQ42_distance_transitive_graph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([45, 32, 12, 1, None], [None, 1, 6, 32, 45]) REFERENCES: @@ -132,8 +132,8 @@ def ConwaySmith_for_3S7(): EXAMPLES:: - sage: G = graphs.ConwaySmith_for_3S7() - sage: G.is_distance_regular(True) + sage: G = graphs.ConwaySmith_for_3S7() # needs sage.modules sage.rings.finite_rings sage.rings.number_field + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings sage.rings.number_field ([10, 6, 4, 1, None], [None, 1, 2, 6, 10]) REFERENCES: @@ -217,8 +217,8 @@ def graph_3O73(): EXAMPLES:: - sage: G = graphs.graph_3O73() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.graph_3O73() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([117, 80, 24, 1, None], [None, 1, 12, 80, 117]) REFERENCES: @@ -243,8 +243,8 @@ def FosterGraph3S6(): EXAMPLES:: - sage: G = graphs.FosterGraph3S6() - sage: G.is_distance_regular(True) + sage: G = graphs.FosterGraph3S6() # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([6, 4, 2, 1, None], [None, 1, 1, 4, 6]) REFERENCES: @@ -272,8 +272,8 @@ def J2Graph(): EXAMPLES:: - sage: G = graphs.J2Graph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.J2Graph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([10, 8, 8, 2, None], [None, 1, 1, 4, 5]) REFERENCES: @@ -295,8 +295,8 @@ def IvanovIvanovFaradjevGraph(): EXAMPLES:: - sage: G = graphs.IvanovIvanovFaradjevGraph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.IvanovIvanovFaradjevGraph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7]) REFERENCES: @@ -321,8 +321,8 @@ def LargeWittGraph(): EXAMPLES:: - sage: g = graphs.LargeWittGraph() - sage: g.is_distance_regular(True) + sage: g = graphs.LargeWittGraph() # needs sage.modules + sage: g.is_distance_regular(True) # needs sage.modules ([30, 28, 24, None], [None, 1, 3, 15]) REFERENCES: @@ -359,8 +359,8 @@ def TruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.TruncatedWittGraph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.TruncatedWittGraph() # long time # needs sage.modules + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules ([15, 14, 12, None], [None, 1, 1, 9]) REFERENCES: @@ -388,8 +388,8 @@ def DoublyTruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.DoublyTruncatedWittGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.DoublyTruncatedWittGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([7, 6, 4, 4, None], [None, 1, 1, 1, 6]) REFERENCES: @@ -411,8 +411,8 @@ def distance_3_doubly_truncated_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time, needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules sage.rings.finite_rings ([9, 8, 6, 3, None], [None, 1, 1, 3, 8]) ALGORITHM: @@ -446,8 +446,8 @@ def shortened_00_11_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21]) ALGORITHM: @@ -485,8 +485,8 @@ def shortened_000_111_extended_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21]) ALGORITHM: @@ -526,8 +526,8 @@ def vanLintSchrijverGraph(): EXAMPLES:: - sage: G = graphs.vanLintSchrijverGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.vanLintSchrijverGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([6, 5, 5, 4, None], [None, 1, 1, 2, 6]) REFERENCES: @@ -557,8 +557,8 @@ def LeonardGraph(): EXAMPLES:: - sage: G = graphs.LeonardGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.LeonardGraph() # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -597,8 +597,8 @@ def UstimenkoGraph(const int m, const int q): EXAMPLES:: - sage: G = graphs.UstimenkoGraph(4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.UstimenkoGraph(4, 2) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([70, 32, None], [None, 1, 35]) REFERENCES: @@ -607,13 +607,14 @@ def UstimenkoGraph(const int m, const int q): TESTS:: - sage: G = graphs.UstimenkoGraph(5, 2) # long time - sage: G.order() # long time + sage: # long time, needs sage.libs.gap + sage: G = graphs.UstimenkoGraph(5, 2) + sage: G.order() 2295 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) ([310, 224, None], [None, 1, 35]) - sage: G = graphs.UstimenkoGraph(4,3) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.UstimenkoGraph(4,3) + sage: G.is_distance_regular(True) ([390, 243, None], [None, 1, 130]) """ from sage.graphs.graph_generators import graphs @@ -652,14 +653,15 @@ def BilinearFormsGraph(const int d, const int e, const int q): EXAMPLES:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(3, 3, 2) sage: G.is_distance_regular(True) ([49, 36, 16, None], [None, 1, 6, 28]) - sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) - sage: G.order() # not tested (due to above) + sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) # needs sage.rings.finite_rings + sage: G.order() # not tested (due to above) # needs sage.rings.finite_rings 19683 - sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time # needs sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([105, 84, 48, None], [None, 1, 6, 28]) REFERENCES: @@ -669,6 +671,7 @@ def BilinearFormsGraph(const int d, const int e, const int q): TESTS:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(2,3,2) sage: G.is_distance_regular(True) ([21, 12, None], [None, 1, 6]) @@ -754,10 +757,11 @@ def AlternatingFormsGraph(const int n, const int q): TESTS:: - sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) - sage: G.order() # not tested (because of above) + sage: # needs sage.modules + sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) # needs sage.rings.finite_rings + sage: G.order() # not tested (because of above) # needs sage.rings.finite_rings 32768 - sage: G.is_distance_regular(True) # not tested (33 min) + sage: G.is_distance_regular(True) # not tested (33 min) # needs sage.rings.finite_rings ([651, 560, 256, None], [None, 1, 20, 336]) sage: G = graphs.AlternatingFormsGraph(4, 3) sage: G.is_distance_regular(True) @@ -840,11 +844,12 @@ def HermitianFormsGraph(const int n, const int r): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(2, 2) sage: G.is_distance_regular(True) ([5, 4, None], [None, 1, 2]) - sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) - sage: G.order() # not tested (bacuase of the above) + sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) + sage: G.order() # not tested (bacuase of the above) 19683 REFERENCES: @@ -853,6 +858,7 @@ def HermitianFormsGraph(const int n, const int r): TESTS:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(3, 2) sage: G.is_distance_regular(True) ([21, 20, 16, None], [None, 1, 2, 12]) @@ -1079,8 +1085,8 @@ def GrassmannGraph(const int q, const int n, const int input_e): EXAMPLES:: - sage: G = graphs.GrassmannGraph(2, 4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.GrassmannGraph(2, 4, 2) # needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings ([18, 8, None], [None, 1, 9]) REFERENCES: @@ -1089,8 +1095,9 @@ def GrassmannGraph(const int q, const int n, const int input_e): TESTS:: - sage: G = graphs.GrassmannGraph(2, 6, 3) # long time - sage: G.is_distance_regular(True) # long time + sage: # needs sage.modules sage.rings.finite_rings + sage: G = graphs.GrassmannGraph(2, 6, 3) # long time + sage: G.is_distance_regular(True) # long time ([98, 72, 32, None], [None, 1, 9, 49]) sage: G = graphs.GrassmannGraph(3, 4, 2) sage: G.is_distance_regular(True) @@ -1132,10 +1139,10 @@ def DoubleGrassmannGraph(const int q, const int e): EXAMPLES:: - sage: G = graphs.DoubleGrassmannGraph(2,1) - sage: G.diameter() + sage: G = graphs.DoubleGrassmannGraph(2,1) # needs sage.modules + sage: G.diameter() # needs sage.modules 3 - sage: G.is_distance_regular(True) + sage: G.is_distance_regular(True) # needs sage.modules ([3, 2, 2, None], [None, 1, 1, 3]) @@ -1145,15 +1152,16 @@ def DoubleGrassmannGraph(const int q, const int e): TESTS:: + sage: # needs sage.modules sage: G = graphs.DoubleGrassmannGraph(5,1) sage: G.order() 62 sage: G.is_distance_regular(True) ([6, 5, 5, None], [None, 1, 1, 6]) - sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time - sage: G.order() # long time + sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time # needs sage.rings.finite_rings + sage: G.order() # long time # needs sage.rings.finite_rings 2420 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([13, 12, 12, 9, 9, None], [None, 1, 1, 4, 4, 13]) """ n = 2*e + 1 @@ -1187,10 +1195,10 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread, graph_from_GQ_spread - sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) + sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) # needs sage.libs.pari (5, 25) - sage: G = graph_from_GQ_spread(5, 25) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(5, 25) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([125, 120, 1, None], [None, 1, 24, 125]) REFERENCES: @@ -1202,9 +1210,9 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread - sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) # needs sage.libs.pari (7, 49) - sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) # needs sage.libs.pari False Check that we don't get ``True`` for inexisting GQs:: @@ -1215,7 +1223,7 @@ def is_from_GQ_spread(list arr): sage: t = 6 sage: [s * t, s * (t-1), 1, 1, t - 1, s * t] [30, 25, 1, 1, 5, 30] - sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) + sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) # needs sage.libs.pari False """ from sage.combinat.designs import design_catalog as designs @@ -1258,8 +1266,8 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread - sage: G = graph_from_GQ_spread(4, 16) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(4, 16) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([64, 60, 1, None], [None, 1, 15, 64]) REFERENCES: @@ -1270,11 +1278,11 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread, is_from_GQ_spread - sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) + sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) # needs sage.libs.pari (4, 16) - sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) + sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) # needs sage.libs.pari Graph on 112 vertices - sage: _.is_distance_regular(True) + sage: _.is_distance_regular(True) # needs sage.libs.pari ([27, 24, 1, None], [None, 1, 8, 27]) """ from sage.combinat.designs import design_catalog as designs @@ -1302,13 +1310,14 @@ def GeneralisedDodecagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 5) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 5) + sage: G.is_distance_regular(True) ([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6]) - sage: H = graphs.GeneralisedDodecagonGraph(5, 1) # optional - gap_packages internet - sage: H.order() # optional - gap_packages internet + sage: H = graphs.GeneralisedDodecagonGraph(5, 1) + sage: H.order() 23436 - sage: H.is_distance_regular(True) # not tested (6 min); optional - gap_packages internet + sage: H.is_distance_regular(True) # not tested (6 min) ([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2]) .. NOTE:: @@ -1326,29 +1335,31 @@ def GeneralisedDodecagonGraph(const int s, const int t): Test all graphs of order `(1, q)`:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 4) + sage: G.is_distance_regular(True) ([5, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 3) + sage: G.is_distance_regular(True) ([4, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 4]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 2) + sage: G.is_distance_regular(True) ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 1) + sage: G.is_distance_regular(True) ([2, 1, 1, 1, 1, 1, None], [None, 1, 1, 1, 1, 1, 2]) Now test all graphs of order `(q, 1)`:: - sage: G = graphs.GeneralisedDodecagonGraph(4, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(4, 1) + sage: G.is_distance_regular(True) ([8, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(3, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(3, 1) + sage: G.is_distance_regular(True) ([6, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(2, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(2, 1) + sage: G.is_distance_regular(True) ([4, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 2]) """ from sage.arith.misc import is_prime_power @@ -1407,15 +1418,16 @@ def GeneralisedOctagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedOctagonGraph(1, 4) - sage: G.is_distance_regular(True) - ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet - ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(5, 1) - sage: G.is_distance_regular(True) - ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) + sage: # needs sage.libs.gap + sage: G = graphs.GeneralisedOctagonGraph(1, 4) + sage: G.is_distance_regular(True) + ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_package_atlasrep internet + sage: G.is_distance_regular(True) # optional - gap_package_atlasrep internet + ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(5, 1) + sage: G.is_distance_regular(True) + ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) .. NOTE:: @@ -1430,11 +1442,11 @@ def GeneralisedOctagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedOctagonGraph(8, 64) + sage: G = graphs.GeneralisedOctagonGraph(8, 64) # needs sage.libs.gap Traceback (most recent call last): ... NotImplementedError: Graph would be too big - sage: G = graphs.GeneralisedOctagonGraph(4, 16) + sage: G = graphs.GeneralisedOctagonGraph(4, 16) # needs sage.libs.gap Traceback (most recent call last): ... ValueError: generalised octagons of order (q, q^2) are known only for odd powers q of 2 @@ -1517,8 +1529,9 @@ def GeneralisedHexagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # needs sage.libs.gap + sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_package_atlasrep internet + sage: G.is_distance_regular(True) # optional - gap_package_atlasrep internet ([30, 25, 25, None], [None, 1, 1, 6]) sage: G = graphs.GeneralisedHexagonGraph(7, 1) sage: G.is_distance_regular(True) @@ -1539,17 +1552,18 @@ def GeneralisedHexagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedHexagonGraph(4, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedHexagonGraph(4, 4) + sage: G.is_distance_regular(True) ([20, 16, 16, None], [None, 1, 1, 5]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(3, 3) + sage: G.is_distance_regular(True) ([12, 9, 9, None], [None, 1, 1, 4]) - sage: G = graphs.GeneralisedHexagonGraph(2, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 2) + sage: G.is_distance_regular(True) ([6, 4, 4, None], [None, 1, 1, 3]) - sage: G = graphs.GeneralisedHexagonGraph(2, 8) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 8) + sage: G.is_distance_regular(True) ([18, 16, 16, None], [None, 1, 1, 9]) """ from sage.arith.misc import is_prime_power @@ -1672,6 +1686,7 @@ def _extract_lines(G): EXAMPLES:: + sage: # needs sage.libs.gap sage: from sage.graphs.generators.distance_regular import _extract_lines sage: G = graphs.GeneralisedHexagonGraph(1, 8) sage: lines = _extract_lines(G) @@ -1739,16 +1754,17 @@ def _line_graph_generalised_polygon(H): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import \ - ....: _line_graph_generalised_polygon - sage: G = graphs.GeneralisedHexagonGraph(1, 8) - sage: H = _line_graph_generalised_polygon(G) - sage: H.is_distance_regular(True) - ([16, 8, 8, None], [None, 1, 1, 2]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet - sage: G.is_isomorphic(H) # optional - gap_packages internet - True + sage: # needs sage.libs.gap + sage: from sage.graphs.generators.distance_regular import ( + ....: _line_graph_generalised_polygon) + sage: G = graphs.GeneralisedHexagonGraph(1, 8) + sage: H = _line_graph_generalised_polygon(G) + sage: H.is_distance_regular(True) + ([16, 8, 8, None], [None, 1, 1, 2]) + sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_package_atlasrep internet + sage: H = _line_graph_generalised_polygon(G) # optional - gap_package_atlasrep internet + sage: G.is_isomorphic(H) # optional - gap_package_atlasrep internet + True REFERENCES: @@ -1792,9 +1808,9 @@ def _intersection_array_from_graph(G): sage: from sage.graphs.generators.distance_regular import \ ....: _intersection_array_from_graph - sage: _intersection_array_from_graph(graphs.FosterGraph()) + sage: _intersection_array_from_graph(graphs.FosterGraph()) # needs networkx [3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3] - sage: graphs.FosterGraph().is_distance_regular(True) + sage: graphs.FosterGraph().is_distance_regular(True) # needs networkx ([3, 2, 2, 2, 2, 1, 1, 1, None], [None, 1, 1, 1, 1, 2, 2, 2, 3]) sage: graphs.DartGraph().is_distance_regular() False @@ -1877,7 +1893,7 @@ def is_classical_parameters_graph(list array): sage: G = graphs.HammingGraph(5, 4) sage: G.is_distance_regular(True) ([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5]) - sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) + sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) # needs sage.combinat (5, 1, 0, 3, 2) REFERENCES: @@ -1890,12 +1906,12 @@ def is_classical_parameters_graph(list array): sage: from sage.graphs.generators.distance_regular import \ ....: is_classical_parameters_graph - sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg + sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg # needs sage.combinat False - sage: G = graphs.GossetGraph() # sporadic classical parameters graph + sage: G = graphs.GossetGraph() # sporadic classical parameters graph sage: G.is_distance_regular(True) ([27, 10, 1, None], [None, 1, 10, 27]) - sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) + sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) # needs sage.combinat False """ from sage.misc.functional import log @@ -2101,7 +2117,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): Hamming Graph with parameters 3,4: Graph on 64 vertices sage: G = _; G.is_distance_regular(True) ([9, 6, 3, None], [None, 1, 2, 3]) - sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) + sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) # needs sage.combinat (3, 1, 0, 3, 2) Two families of graphs are not implemented yet:: @@ -2125,11 +2141,11 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): sage: graph_with_classical_parameters(3, 1, 2, 3, 3) Half 4 Cube: Graph on 8 vertices - sage: graph_with_classical_parameters(3, 2, 0, 2, 9) + sage: graph_with_classical_parameters(3, 2, 0, 2, 9) # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices sage: graph_with_classical_parameters(3, 2, 2, 14, 7) # long time Grassmann graph J_2(6, 3): Graph on 1395 vertices - sage: graph_with_classical_parameters(3, -2, -2, 6, 6) # optional - gap_packages internet + sage: graph_with_classical_parameters(3, -2, -2, 6, 6) # optional - gap_package_atlasrep internet Generalised hexagon of order (2, 8): Graph on 819 vertices """ from sage.rings.rational import Rational @@ -2389,7 +2405,7 @@ def is_near_polygon(array): sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) - sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) + sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) # needs sage.combinat (2, 7) sage: near_polygon_graph(2, 7) Odd Graph with parameter 7: Graph on 1716 vertices @@ -2403,19 +2419,20 @@ def is_near_polygon(array): TESTS:: + sage: # needs sage.combinat sage.libs.pari sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) (4, (2, 2)) sage: near_polygon_graph(4, (2, 2)) Double Grassmann graph (5, 2, 2): Graph on 310 vertices - sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) + sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.rings.finite_rings Generalised hexagon of order (1, 2): Graph on 14 vertices sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) (6, (4, 5)) sage: is_near_polygon([]) False - sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph + sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph False """ from sage.arith.misc import is_prime_power @@ -2525,12 +2542,11 @@ def near_polygon_graph(family, params): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import ( - ....: is_near_polygon, near_polygon_graph) - sage: near_polygon_graph(*is_near_polygon([6, 5, 5, 4, 4, 3, 3, 2, 2, \ - ....: 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) + sage: from sage.graphs.generators.distance_regular import is_near_polygon, near_polygon_graph + sage: near_polygon_graph(*is_near_polygon( # needs sage.combinat + ....: [6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices - sage: G=_; G.is_distance_regular(True) + sage: G=_; G.is_distance_regular(True) # needs sage.combinat ([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]) @@ -2541,6 +2557,7 @@ def near_polygon_graph(family, params): TESTS:: + sage: # needs sage.combinat sage: near_polygon_graph(12, 9) Traceback (most recent call last): ... @@ -2695,8 +2712,8 @@ def distance_regular_graph(list arr, existence=False, check=True): sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True) True - sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) - sage: G.is_distance_regular(True) + sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -2705,16 +2722,18 @@ def distance_regular_graph(list arr, existence=False, check=True): TESTS:: - sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], - ....: existence=True) + sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], # needs sage.combinat + ....: existence=True) True sage: graphs.distance_regular_graph([3, 2, 2, 1, 2, 1, 1, 2, 2, 3], - ....: existence=True) + ....: existence=True) False - sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_packages + sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_package_atlasrep Generalised hexagon of order (2, 8): Graph on 819 vertices + + sage: # needs sage.combinat sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, - ....: 1, 2, 3, 4, 5, 6, 7]) + ....: 1, 2, 3, 4, 5, 6, 7]) Hamming Graph with parameters 7,3: Graph on 2187 vertices sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) Graph on 1024 vertices diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 30396e1ab9e..a5916a13b5c 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -40,13 +40,13 @@ def JohnsonGraph(n, k): The Johnson graph is a Hamiltonian graph:: sage: g = graphs.JohnsonGraph(7, 3) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True Every Johnson graph is vertex transitive:: sage: g = graphs.JohnsonGraph(6, 4) - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser @@ -452,7 +452,7 @@ def HammingGraph(n, q, X=None): True sage: g.is_regular() True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True A Hamming graph with parameters (1,q) is isomorphic to the @@ -526,9 +526,9 @@ def BalancedTree(r, h): A balanced tree whose root node has degree `r = 2`, and of height `h = 1`, has order 3 and size 2:: - sage: G = graphs.BalancedTree(2, 1); G # optional - networkx + sage: G = graphs.BalancedTree(2, 1); G # needs networkx Balanced tree: Graph on 3 vertices - sage: G.order(); G.size() # optional - networkx + sage: G.order(); G.size() # needs networkx 3 2 sage: r = 2; h = 1 @@ -539,21 +539,22 @@ def BalancedTree(r, h): Plot a balanced tree of height 5, whose root node has degree `r = 3`:: - sage: G = graphs.BalancedTree(3, 5) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.BalancedTree(3, 5) # needs networkx + sage: G.show() # long time # needs networkx sage.plot A tree is bipartite. If its vertex set is finite, then it is planar. :: + sage: # needs networkx sage: r = randint(2, 5); h = randint(1, 7) - sage: T = graphs.BalancedTree(r, h) # optional - networkx - sage: T.is_bipartite() # optional - networkx + sage: T = graphs.BalancedTree(r, h) + sage: T.is_bipartite() True - sage: T.is_planar() # optional - networkx + sage: T.is_planar() True - sage: v = (r^(h + 1) - 1) / (r - 1) # optional - networkx - sage: T.order() == v # optional - networkx + sage: v = (r^(h + 1) - 1) / (r - 1) + sage: T.order() == v True - sage: T.size() == v - 1 # optional - networkx + sage: T.size() == v - 1 True TESTS: @@ -562,13 +563,13 @@ def BalancedTree(r, h): has degree `r \geq 2`, but the construction degenerates gracefully:: - sage: graphs.BalancedTree(1, 10) # optional - networkx + sage: graphs.BalancedTree(1, 10) # needs networkx Balanced tree: Graph on 11 vertices Similarly, we usually want the tree must have height `h \geq 1` but the algorithm also degenerates gracefully here:: - sage: graphs.BalancedTree(3, 0) # optional - networkx + sage: graphs.BalancedTree(3, 0) # needs networkx Balanced tree: Graph on 1 vertex """ import networkx @@ -627,11 +628,13 @@ def BarbellGraph(n1, n2): True sage: K_n1 = graphs.CompleteGraph(n1) sage: P_n2 = graphs.PathGraph(n2) - sage: s_K = g.subgraph_search(K_n1, induced=True) # optional - sage.modules - sage: s_P = g.subgraph_search(P_n2, induced=True) # optional - sage.modules - sage: K_n1.is_isomorphic(s_K) # optional - sage.modules + + sage: # needs sage.modules + sage: s_K = g.subgraph_search(K_n1, induced=True) + sage: s_P = g.subgraph_search(P_n2, induced=True) + sage: K_n1.is_isomorphic(s_K) True - sage: P_n2.is_isomorphic(s_P) # optional - sage.modules + sage: P_n2.is_isomorphic(s_P) True TESTS:: @@ -640,7 +643,7 @@ def BarbellGraph(n1, n2): sage: g = graphs.BarbellGraph(n1, n2) sage: g.num_verts() == 2 * n1 + n2 True - sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 + sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 # needs sage.symbolic True sage: g.is_connected() True @@ -717,7 +720,7 @@ def LollipopGraph(n1, n2): sage: g = graphs.LollipopGraph(n1, n2) sage: g.num_verts() == n1 + n2 True - sage: g.num_edges() == binomial(n1, 2) + n2 + sage: g.num_edges() == binomial(n1, 2) + n2 # needs sage.symbolic True sage: g.is_connected() True @@ -1027,10 +1030,10 @@ def chang_graphs(): sage: c3c5 = graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5)) sage: c8 = graphs.CycleGraph(8) - sage: s = [K8.subgraph_search(c8).edges(sort=False), # optional - sage.modules + sage: s = [K8.subgraph_search(c8).edges(sort=False), # needs sage.modules ....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)], ....: K8.subgraph_search(c3c5).edges(sort=False)] - sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # optional - sage.modules + sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # needs sage.modules ....: for x, G in zip(s, chang_graphs)] [True, True, True] @@ -1076,51 +1079,54 @@ def CirculantGraph(n, adjacency): EXAMPLES: Compare plotting using the predefined layout and networkx:: - sage: import networkx # optional - networkx - sage: n = networkx.cycle_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.cycle_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.CirculantGraph(23,2) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CirculantGraph`` constructor, which fills in the position dictionary:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CirculantGraph(i+4, i+1) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Passing a 1 into adjacency should give the cycle. :: - sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6) + sage: graphs.CirculantGraph(6,1) == graphs.CycleGraph(6) True sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false) [(0, 1), @@ -1187,27 +1193,28 @@ def CubeGraph(n, embedding=1): Plot several `n`-cubes in a Sage Graphics Array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(6): ....: k = graphs.CubeGraph(i+1) ....: g.append(k) ... - sage: for i in range(2): # optional - sage.plot + sage: for i in range(2): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show(figsize=[6,4]) # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show(figsize=[6,4]) # long time Use the plot options to display larger `n`-cubes:: sage: g = graphs.CubeGraph(9, embedding=1) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot sage: g = graphs.CubeGraph(9, embedding=2) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot AUTHORS: @@ -1306,9 +1313,9 @@ def GoethalsSeidelGraph(k, r): EXAMPLES:: - sage: graphs.GoethalsSeidelGraph(3,3) + sage: graphs.GoethalsSeidelGraph(3,3) # needs sage.modules Graph on 28 vertices - sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) + sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) # needs sage.modules (28, 15, 6, 10) """ from sage.combinat.designs.bibd import balanced_incomplete_block_design @@ -1353,8 +1360,8 @@ def DorogovtsevGoltsevMendesGraph(n): EXAMPLES:: - sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # optional - networkx - sage: G.size() # optional - networkx + sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # needs networkx + sage: G.size() # needs networkx 6561 REFERENCE: @@ -1438,24 +1445,25 @@ def FriendshipGraph(n): The first few friendship graphs. :: + sage: # needs sage.plot sage: A = []; B = [] sage: for i in range(9): ....: g = graphs.FriendshipGraph(i + 1) ....: A.append(g) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for j in range(3): ....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False)) ....: B.append(n) - sage: G = graphics_array(B) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(B) + sage: G.show() # long time For `n = 1`, the friendship graph `F_1` is isomorphic to the cycle graph `C_3`, whose visual representation is a triangle. :: sage: G = graphs.FriendshipGraph(1); G Friendship graph: Graph on 3 vertices - sage: G.show() # long time # optional - sage.plot + sage: G.show() # long time # needs sage.plot sage: G.is_isomorphic(graphs.CycleGraph(3)) True @@ -1538,7 +1546,7 @@ def FuzzyBallGraph(partition, q): EXAMPLES:: sage: F = graphs.FuzzyBallGraph([3,1],2) - sage: F.adjacency_matrix(vertices=list(F)) # optional - sage.modules + sage: F.adjacency_matrix(vertices=list(F)) # needs sage.modules [0 0 1 1 1 0 0 0] [0 0 0 0 0 1 0 0] [1 0 0 1 1 1 1 1] @@ -1554,9 +1562,9 @@ def FuzzyBallGraph(partition, q): Laplacian:: sage: m = 4; q = 2; k = 2 - sage: g_list = [graphs.FuzzyBallGraph(p,q) # optional - sage.combinat sage.modules + sage: g_list = [graphs.FuzzyBallGraph(p,q) # needs sage.combinat sage.modules ....: for p in Partitions(m, length=k)] - sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), optional - sage.combinat sage.modules + sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), needs sage.combinat sage.modules ....: vertices=list(g)).charpoly() ....: for g in g_list) {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 @@ -1588,15 +1596,15 @@ def FibonacciTree(n): EXAMPLES:: - sage: g = graphs.FibonacciTree(3) - sage: g.is_tree() + sage: g = graphs.FibonacciTree(3) # needs sage.libs.pari + sage: g.is_tree() # needs sage.libs.pari True :: - sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] - sage: l2 = list(fibonacci_sequence(2,8)) - sage: l1 == l2 + sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] # needs sage.libs.pari + sage: l2 = list(fibonacci_sequence(2,8)) # needs sage.libs.pari + sage: l1 == l2 # needs sage.libs.pari True AUTHORS: @@ -2074,15 +2082,15 @@ def HararyGraph(k, n): 9 sage: h.size() 23 - sage: h.vertex_connectivity() + sage: h.vertex_connectivity() # needs sage.numerical.mip 5 TESTS: Connectivity of some Harary graphs:: - sage: n=10 - sage: for k in range(2,n): + sage: n = 10 + sage: for k in range(2,n): # needs sage.numerical.mip ....: g = graphs.HararyGraph(k,n) ....: if k != g.vertex_connectivity(): ....: print("Connectivity of Harary graphs not satisfied.") @@ -2207,31 +2215,32 @@ def LCFGraph(n, shift_list, repeats): EXAMPLES:: - sage: G = graphs.LCFGraph(4, [2,-2], 2) # optional - networkx - sage: G.is_isomorphic(graphs.TetrahedralGraph()) # optional - networkx + sage: G = graphs.LCFGraph(4, [2,-2], 2) # needs networkx + sage: G.is_isomorphic(graphs.TetrahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # optional - networkx - sage: G.is_isomorphic(graphs.DodecahedralGraph()) # optional - networkx + sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # needs networkx + sage: G.is_isomorphic(graphs.DodecahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(14, [5,-5], 7) # optional - networkx - sage: G.is_isomorphic(graphs.HeawoodGraph()) # optional - networkx + sage: G = graphs.LCFGraph(14, [5,-5], 7) # needs networkx + sage: G.is_isomorphic(graphs.HeawoodGraph()) # needs networkx True The largest cubic nonplanar graph of diameter three:: - sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, # optional - networkx + sage: # needs networkx + sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, ....: -10,-7,6,-5,7,-10,-7,5,-6,7], 1) - sage: G.degree() # optional - networkx + sage: G.degree() [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - sage: G.diameter() # optional - networkx + sage: G.diameter() 3 - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs sage.plot PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above. @@ -2538,14 +2547,14 @@ def PaleyGraph(q): EXAMPLES:: - sage: G = graphs.PaleyGraph(9); G + sage: G = graphs.PaleyGraph(9); G # needs sage.rings.finite_rings Paley graph with parameter 9: Graph on 9 vertices - sage: G.is_regular() + sage: G.is_regular() # needs sage.rings.finite_rings True A Paley graph is always self-complementary:: - sage: G.is_self_complementary() + sage: G.is_self_complementary() # needs sage.rings.finite_rings True TESTS: @@ -2588,9 +2597,9 @@ def PasechnikGraph(n): EXAMPLES:: - sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # optional - sage.combinat sage.modules + sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (225, 98, 43, 42) - sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, optional - sage.combinat sage.modules + sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, needs sage.combinat sage.modules (361, 162, 73, 72) sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not tested (1225, 578, 273, 272) @@ -2630,11 +2639,15 @@ def SquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) + sage: # needs sage.modules + sage: G = graphs.SquaredSkewHadamardMatrixGraph(4) + sage: G.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: graphs.SquaredSkewHadamardMatrixGraph(5).is_strongly_regular(parameters=True) # long time + sage: G = graphs.SquaredSkewHadamardMatrixGraph(5) + sage: G.is_strongly_regular(parameters=True) # long time (361, 180, 89, 90) - sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # not tested + sage: G = graphs.SquaredSkewHadamardMatrixGraph(9) + sage: G.is_strongly_regular(parameters=True) # not tested (1225, 612, 305, 306) TESTS:: @@ -2680,13 +2693,14 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) - sage: g.is_strongly_regular(parameters=True) + sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) # needs sage.modules + sage: g.is_strongly_regular(parameters=True) # needs sage.modules (226, 105, 48, 49) sage: from sage.combinat.designs.twographs import twograph_descendant - sage: twograph_descendant(g,0).is_strongly_regular(parameters=True) + sage: twograph_descendant(g, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) - sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True) + sage: gc = g.complement() # needs sage.modules + sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) TESTS:: @@ -2817,7 +2831,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): :: sage: H = graphs.HanoiTowerGraph(3, 4, labels=False, positions=False) - sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # optional - sage.groups + sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # needs sage.groups True sage: H.chromatic_number() 3 @@ -3065,10 +3079,10 @@ def petersen_family(generate=False): The two different inputs generate the same graphs:: sage: F1 = graphs.petersen_family(generate=False) - sage: F2 = graphs.petersen_family(generate=True) + sage: F2 = graphs.petersen_family(generate=True) # needs sage.modules sage: F1 = [g.canonical_label().graph6_string() for g in F1] - sage: F2 = [g.canonical_label().graph6_string() for g in F2] - sage: set(F1) == set(F2) + sage: F2 = [g.canonical_label().graph6_string() for g in F2] # needs sage.modules + sage: set(F1) == set(F2) # needs sage.modules True """ from sage.graphs.generators.smallgraphs import PetersenGraph @@ -3183,6 +3197,7 @@ def SierpinskiGasketGraph(n): EXAMPLES:: + sage: # needs sage.modules sage: s4 = graphs.SierpinskiGasketGraph(4); s4 Graph on 42 vertices sage: s4.size() @@ -3272,14 +3287,15 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): of `G` are isomorphic to Hanoi Tower graphs:: sage: k = randint(1, 5) - sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) + sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) # needs sage.modules sage: H = graphs.HanoiTowerGraph(3, k) - sage: S.is_isomorphic(H) + sage: S.is_isomorphic(H) # needs sage.modules True The generalized Sierpinski graph of dimension `k` of any graph `G` with `n` vertices and `m` edges has `n^k` vertices and `m\sum_{i=0}^{k-1}n^i` edges:: + sage: # needs sage.modules sage: n = randint(2, 6) sage: k = randint(1, 5) sage: G = graphs.RandomGNP(n, .5) @@ -3302,14 +3318,14 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): sage: G = graphs.HouseGraph() sage: G.get_pos() is not None True - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic - sage: H.get_pos() is not None # optional - sage.symbolic + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic True sage: G = Graph([(0, 1)]) sage: G.get_pos() is not None False - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic - sage: H.get_pos() is not None # optional - sage.symbolic + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic False .. PLOT:: @@ -3318,6 +3334,7 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): TESTS:: + sage: # needs sage.modules sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) Generalized Sierpinski Graph of Graph on 0 vertices of dimension 3: Graph on 0 vertices sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) @@ -3397,46 +3414,49 @@ def WheelGraph(n): We view many wheel graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.WheelGraph(i+3) ....: g.append(k) ... - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Next, using the spring-layout algorithm:: - sage: import networkx # optional - networkx + sage: # needs networkx sage.plot + sage: import networkx sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: spr = networkx.wheel_graph(i+3) ....: k = Graph(spr) ....: g.append(k) ... - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare the plotting:: - sage: n = networkx.wheel_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: # needs networkx sage.plot + sage: n = networkx.wheel_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.WheelGraph(23) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time sage: posdict23.show() # long time """ from sage.graphs.generators.basic import CycleGraph @@ -3740,9 +3760,10 @@ def RingedTree(k, vertex_labels=True): EXAMPLES:: + sage: # needs networkx sage: G = graphs.RingedTree(5) - sage: P = G.plot(vertex_labels=False, vertex_size=10) # optional - sage.plot - sage: P.show() # long time # optional - sage.plot + sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs sage.plot + sage: P.show() # long time # needs sage.plot sage: G.vertices(sort=True) ['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01', '010', '0100', '0101', '011', '0110', '0111', '1', '10', '100', @@ -3755,8 +3776,8 @@ def RingedTree(k, vertex_labels=True): Traceback (most recent call last): ... ValueError: The number of levels must be >= 1. - sage: G = graphs.RingedTree(5, vertex_labels = False) - sage: G.vertices(sort=True) + sage: G = graphs.RingedTree(5, vertex_labels=False) # needs networkx + sage: G.vertices(sort=True) # needs networkx [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] """ @@ -3828,13 +3849,13 @@ def MathonPseudocyclicMergingGraph(M, t): sage: G = mer(ES(3), 2) # long time sage: G.is_strongly_regular(parameters=True) # long time (784, 297, 116, 110) - sage: G = mer(ES(2), 2) + sage: G = mer(ES(2), 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... - sage: M = ES(3) - sage: M = [M[1],M[0],M[2],M[3]] - sage: G = mer(M, 2) + sage: M = ES(3) # needs sage.libs.gap + sage: M = [M[1],M[0],M[2],M[3]] # needs sage.libs.gap + sage: G = mer(M, 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... @@ -3889,13 +3910,14 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Using default ``G`` and ``L``. :: sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph - sage: G=MathonPseudocyclicStronglyRegularGraph(1); G + sage: G = MathonPseudocyclicStronglyRegularGraph(1); G # needs sage.modules sage.rings.finite_rings Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (45, 22, 10, 11) Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). :: + sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings sage: G = graphs.PaleyGraph(9) sage: a = G.automorphism_group(partition=[sorted(G)]) sage: it = (x for x in a.normal_subgroups() if x.order() == 9) @@ -3915,21 +3937,22 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): [-4 -3 -2 2 3 4 -1 0 1] [-2 -4 -3 4 2 3 1 -1 0] + sage: # needs sage.modules sage.rings.finite_rings sage.groups sage.libs.gap sage: G.relabel(range(9)) - sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) + sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) sage: G3x3.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss 27 - sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) + sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2) sage: G9.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss 9 TESTS:: - sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) + sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) # needs sage.modules Traceback (most recent call last): ... ValueError: 21 must be a sum of two squares!... @@ -4123,18 +4146,20 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): EXAMPLES:: - sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (378, 116, 34, 36) - sage: phi={(2,(0,2)):0,(1,(1,3)):1,(0,(0,3)):1,(2,(1,2)):1,(1,(1, - ....: 2)):0,(0,(0,2)):0,(3,(0,3)):0,(3,(1,3)):1} - sage: graphs.MuzychukS6Graph(2,2,Phi=phi).is_strongly_regular(parameters=True) + sage: phi = {(2,(0,2)):0, (1,(1,3)):1, (0,(0,3)):1, (2,(1,2)):1, # needs sage.modules + ....: (1,(1,2)):0, (0,(0,2)):0, (3,(0,3)):0, (3,(1,3)):1} + sage: graphs.MuzychukS6Graph(2, 2, # needs sage.modules sage.rings.finite_rings + ....: Phi=phi).is_strongly_regular(parameters=True) (16, 5, 0, 2) TESTS:: - sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: # needs sage.modules + sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (16, 5, 0, 2) - sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (378, 116, 34, 36) sage: graphs.MuzychukS6Graph(3,2) Traceback (most recent call last): @@ -4148,11 +4173,11 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): Traceback (most recent call last): ... AssertionError: d must be at least 2 - sage: graphs.MuzychukS6Graph(3,3,Phi=42) + sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... AssertionError: Phi must be a dictionary or 'random' or 'fixed' - sage: graphs.MuzychukS6Graph(3,3,Sigma=42) + sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Sigma must be 'random' or 'fixed' diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index f2cd8b248ad..0de3715e0e1 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -417,9 +417,10 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): EXAMPLES:: - sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G + sage: # needs sage.modules + sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G # needs sage.schemes OA(5,5): Graph on 25 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.schemes (25, 20, 15, 20) sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G OA(4,10): Graph on 100 vertices @@ -428,20 +429,21 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): Two graphs built from different orthogonal arrays are also different:: - sage: k=4;n=10 + sage: # needs sage.modules + sage: k = 4; n = 10 sage: OAa = designs.orthogonal_arrays.build(k,n) sage: OAb = [[(x+1)%n for x in R] for R in OAa] sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) False - sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa) - sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb) + sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa) + sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb) sage: Ga == Gb False As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are isomorphic:: - sage: Ga.is_isomorphic(Gb) + sage: Ga.is_isomorphic(Gb) # needs sage.modules True But there are examples of `OA(k,n)` for which the resulting graphs are not @@ -455,31 +457,31 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): ....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1], ....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3], ....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]] - sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0) - sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1) - sage: g0.is_isomorphic(g1) + sage: g0 = graphs.OrthogonalArrayBlockGraph(3, 4, oa0) # needs sage.modules + sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1) # needs sage.modules + sage: g0.is_isomorphic(g1) # needs sage.modules False But nevertheless isospectral:: - sage: g0.spectrum() + sage: g0.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] - sage: g1.spectrum() + sage: g1.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] Note that the graph ``g0`` is actually isomorphic to the affine polar graph `VO^+(4,2)`:: - sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) + sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) # needs sage.modules True TESTS:: - sage: G = graphs.OrthogonalArrayBlockGraph(4,6) + sage: G = graphs.OrthogonalArrayBlockGraph(4,6) # needs sage.modules Traceback (most recent call last): ... NotImplementedError: I don't know how to build an OA(4,6)! - sage: G = graphs.OrthogonalArrayBlockGraph(8,2) + sage: G = graphs.OrthogonalArrayBlockGraph(8,2) # needs sage.modules Traceback (most recent call last): ... ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) ! diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py index f36fa8ecf66..38e070a054a 100644 --- a/src/sage/graphs/generators/platonic_solids.py +++ b/src/sage/graphs/generators/platonic_solids.py @@ -39,28 +39,29 @@ def TetrahedralGraph(): Construct and show a Tetrahedral graph:: sage: g = graphs.TetrahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot The following example requires networkx:: - sage: import networkx as NX # optional - networkx + sage: import networkx as NX # needs networkx Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: + sage: # needs networkx sage.plot sage: tetra_pos = graphs.TetrahedralGraph() - sage: tetra_spring = Graph(NX.tetrahedral_graph()) # optional - networkx + sage: tetra_spring = Graph(NX.tetrahedral_graph()) sage: wheel = graphs.WheelGraph(4) sage: complete = graphs.CompleteGraph(4) - sage: g = [tetra_pos, tetra_spring, wheel, complete] # optional - networkx + sage: g = [tetra_pos, tetra_spring, wheel, complete] sage: j = [] - sage: for i in range(2): # optional - networkx sage.plot + sage: for i in range(2): ....: n = [] ....: for m in range(2): ....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] pos = {0: (0, 0), @@ -88,23 +89,24 @@ def HexahedralGraph(): Construct and show a Hexahedral graph:: sage: g = graphs.HexahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.HexahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]} pos = { @@ -145,18 +147,19 @@ def OctahedralGraph(): Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.OctahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]} G = Graph(adj, format='dict_of_lists', name="Octahedron") @@ -184,23 +187,24 @@ def IcosahedralGraph(): Construct and show an Octahedral graph:: sage: g = graphs.IcosahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.IcosahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], @@ -228,23 +232,24 @@ def DodecahedralGraph(): Construct and show a Dodecahedral graph:: sage: g = graphs.DodecahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.DodecahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 288515ac397..5dab4071f49 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -78,13 +78,13 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: for i in range(9): ....: k = graphs.RandomGNP(i+3,.43) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot sage: graphs.RandomGNP(4,1) Complete graph: Graph on 4 vertices @@ -97,7 +97,7 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: set_random_seed(0) sage: graphs.RandomGNP(50,.2, algorithm="Sage").size() 243 - sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # optional - networkx + sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # needs networkx 279 # 32-bit 209 # 64-bit """ @@ -149,35 +149,36 @@ def RandomBarabasiAlbert(n, m, seed=None): We show the edge list of a random graph on 6 nodes with `m = 2`:: - sage: G = graphs.RandomBarabasiAlbert(6,2) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(6,2) # needs networkx + sage: G.order(), G.size() # needs networkx (6, 8) - sage: G.degree_sequence() # random # optional - networkx + sage: G.degree_sequence() # random # needs networkx [4, 3, 3, 2, 2, 2] We plot a random graph on 12 nodes with `m = 3`:: - sage: ba = graphs.RandomBarabasiAlbert(12,3) # optional - networkx - sage: ba.show() # long time # optional - networkx sage.plot + sage: ba = graphs.RandomBarabasiAlbert(12,3) # needs networkx + sage: ba.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(1,10): # optional - networkx + sage: for i in range(1,10): ....: k = graphs.RandomBarabasiAlbert(i+3, 3) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time When `m = 1`, the generated graph is a tree:: - sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # optional - networkx + sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # needs networkx True """ if seed is None: @@ -206,35 +207,36 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None): EXAMPLES:: - sage: g = graphs.RandomBipartite(5, 2, 0.5) # optional - numpy - sage: g.vertices(sort=True) # optional - numpy + sage: g = graphs.RandomBipartite(5, 2, 0.5) # needs numpy + sage: g.vertices(sort=True) # needs numpy [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)] TESTS:: - sage: g = graphs.RandomBipartite(5, -3, 0.5) # optional - numpy + sage: g = graphs.RandomBipartite(5, -3, 0.5) # needs numpy Traceback (most recent call last): ... ValueError: n1 and n2 should be integers strictly greater than 0 - sage: g = graphs.RandomBipartite(5, 3, 1.5) # optional - numpy + sage: g = graphs.RandomBipartite(5, 3, 1.5) # needs numpy Traceback (most recent call last): ... ValueError: parameter p is a probability, and so should be a real value between 0 and 1 :trac:`12155`:: - sage: graphs.RandomBipartite(5, 6, .2).complement() # optional - numpy + sage: graphs.RandomBipartite(5, 6, .2).complement() # needs numpy complement(Random bipartite graph of order 5+6 with edge probability 0.200000000000000): Graph on 11 vertices Test assigned positions:: - sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() # optional - numpy + sage: # needs numpy + sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() {(0, 0): (1, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)} - sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() {(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (1, 0.0)} - sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos() {(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)} - sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos() """ if not (p >= 0 and p <= 1): @@ -512,7 +514,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None): sage: m, k = 6, 4 sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True) sage: from sage.combinat.designs.incidence_structures import IncidenceStructure - sage: IncidenceStructure(IS) + sage: IncidenceStructure(IS) # needs sage.modules Incidence structure with 19 points and 6 blocks sage: m*(k-1)+1 19 @@ -679,28 +681,29 @@ def RandomGNM(n, m, dense=False, seed=None): We show the edge list of a random graph on 5 nodes with 10 edges:: - sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # optional - networkx + sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] We plot a random graph on 12 nodes with m = 12:: - sage: gnm = graphs.RandomGNM(12, 12) # optional - networkx - sage: gnm.show() # long time # optional - networkx sage.plot + sage: gnm = graphs.RandomGNM(12, 12) # needs networkx + sage: gnm.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): ....: k = graphs.RandomGNM(i+3, i^2-i) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -737,33 +740,34 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None): We check that the generated graph contains a cycle of order `n`:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) # optional - networkx - sage: G.order() # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) + sage: G.order() 7 - sage: C7 = graphs.CycleGraph(7) # optional - networkx - sage: G.subgraph_search(C7) # optional - networkx + sage: C7 = graphs.CycleGraph(7) + sage: G.subgraph_search(C7) Subgraph of (): Graph on 7 vertices - sage: G.diameter() <= C7.diameter() # optional - networkx + sage: G.diameter() <= C7.diameter() True :: - sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot TESTS: We check that when `k = 2` and `p = 0`, the generated graph is a cycle:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # optional - networkx - sage: G.is_cycle() # optional - networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # needs networkx + sage: G.is_cycle() # needs networkx True We check that when `k = 4` and `p = 0`, the generated graph is a circulant graph of parameters ``[1, 2]``:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # optional - networkx - sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # optional - networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # needs networkx + sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # needs networkx True REFERENCE: @@ -807,8 +811,8 @@ def RandomHolmeKim(n, m, p, seed=None): EXAMPLES:: - sage: G = graphs.RandomHolmeKim(12, 3, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomHolmeKim(12, 3, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot REFERENCE: @@ -952,8 +956,8 @@ def connecting_nodes(T, l): sage: from sage.graphs.generators.random import connecting_nodes sage: T = graphs.RandomTree(10) - sage: S = connecting_nodes(T, 5) # optional - numpy - sage: len(S) # optional - numpy + sage: S = connecting_nodes(T, 5) # needs numpy + sage: len(S) # needs numpy 10 """ from sage.combinat.permutation import Permutations @@ -1178,8 +1182,8 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s sage: T = RandomChordalGraph(20, algorithm="growing", k=5) sage: T.is_chordal() True - sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # optional - numpy - sage: T.is_chordal() # optional - numpy + sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # needs numpy + sage: T.is_chordal() # needs numpy True sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5) sage: T.is_chordal() @@ -1303,13 +1307,14 @@ def RandomLobster(n, p, q, seed=None): We check a random graph with 12 backbone nodes and probabilities `p = 0.7` and `q = 0.3`:: - sage: G = graphs.RandomLobster(12, 0.7, 0.3) # optional - networkx - sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx - sage: G.delete_vertices(leaves) # caterpillar # optional - networkx - sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx - sage: G.delete_vertices(leaves) # path # optional - networkx - sage: s = G.degree_sequence() # optional - networkx - sage: if G: # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomLobster(12, 0.7, 0.3) + sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] + sage: G.delete_vertices(leaves) # caterpillar + sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] + sage: G.delete_vertices(leaves) # path + sage: s = G.degree_sequence() + sage: if G: ....: if G.num_verts() == 1: ....: assert s == [0] ....: else: @@ -1318,8 +1323,8 @@ def RandomLobster(n, p, q, seed=None): :: - sage: G = graphs.RandomLobster(9, .6, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomLobster(9, .6, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1434,16 +1439,16 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): We check that the generated graph is a tree:: - sage: G = graphs.RandomTreePowerlaw(10, 3) # optional - networkx - sage: G.is_tree() # optional - networkx + sage: G = graphs.RandomTreePowerlaw(10, 3) # needs networkx + sage: G.is_tree() # needs networkx True - sage: G.order(), G.size() # optional - networkx + sage: G.order(), G.size() # needs networkx (10, 9) :: - sage: G = graphs.RandomTreePowerlaw(15, 2) # optional - networkx - sage: if G: # random output, long time # optional - networkx sage.plot + sage: G = graphs.RandomTreePowerlaw(15, 2) # needs networkx + sage: if G: # random output # long time, needs networkx sage.plot ....: G.show() """ if seed is None: @@ -1474,16 +1479,16 @@ def RandomRegular(d, n, seed=None): We check that a random graph with 8 nodes each of degree 3 is 3-regular:: - sage: G = graphs.RandomRegular(3, 8) # optional - networkx - sage: G.is_regular(k=3) # optional - networkx + sage: G = graphs.RandomRegular(3, 8) # needs networkx + sage: G.is_regular(k=3) # needs networkx True - sage: G.degree_histogram() # optional - networkx + sage: G.degree_histogram() # needs networkx [0, 0, 0, 8] :: - sage: G = graphs.RandomRegular(3, 20) # optional - networkx - sage: if G: # random output, long time # optional - networkx sage.plot + sage: G = graphs.RandomRegular(3, 20) # needs networkx + sage: if G: # random output # long time, needs networkx sage.plot ....: G.show() REFERENCES: @@ -1524,10 +1529,10 @@ def RandomShell(constructor, seed=None): EXAMPLES:: - sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # needs networkx + sage: G.order(), G.size() # needs networkx (30, 52) - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1889,7 +1894,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None): True sage: G.girth() 3 - sage: G.plot(vertex_size=0, vertex_labels=False) # optional - sage.plot + sage: G.plot(vertex_size=0, vertex_labels=False) # needs sage.plot Graphics object consisting of 13 graphics primitives sage: H = graphs.RandomTriangulation(7, k=5) @@ -2005,16 +2010,16 @@ def blossoming_contour(t, shift=0, seed=None): sage: print(blossoming_contour(BinaryTrees(1).an_element())) [('i', 0), ('xb',), ('i', 0), ('xb',), ('i', 0)] - sage: t = BinaryTrees(2).random_element() # optional - sage.combinat - sage: print(blossoming_contour(t)) # random # optional - sage.combinat + sage: t = BinaryTrees(2).random_element() # needs sage.combinat + sage: print(blossoming_contour(t)) # random # needs sage.combinat [('i', 0), ('xb',), ('i', 0), ('n', 2), ('i', 1), ('xb',), ('i', 1), ('xb',), ('i', 1), ('n', 2), ('x',), ('n', 2), ('i', 0)] - sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # optional - sage.combinat + sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # needs sage.combinat 21 - sage: w.count(('xb',)) # optional - sage.combinat + sage: w.count(('xb',)) # needs sage.combinat 4 - sage: w.count(('x',)) # optional - sage.combinat + sage: w.count(('x',)) # needs sage.combinat 2 TESTS:: @@ -2098,17 +2103,18 @@ def RandomBicubicPlanar(n, seed=None): EXAMPLES:: + sage: # needs sage.combinat sage: n = randint(200, 300) - sage: G = graphs.RandomBicubicPlanar(n) # optional - sage.combinat - sage: G.order() == 2*n # optional - sage.combinat + sage: G = graphs.RandomBicubicPlanar(n) + sage: G.order() == 2*n True - sage: G.size() == 3*n # optional - sage.combinat + sage: G.size() == 3*n True - sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) # optional - sage.combinat + sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) True - sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], # optional - sage.combinat + sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], ....: 'blue': [v for v in G.vertices(sort=False) if v[0] != 'n']} - sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # optional - sage.combinat sage.plot + sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.plot Graphics object consisting of ... graphics primitives .. PLOT:: @@ -2210,23 +2216,24 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None): When using twice the same seed, the vertices get the same positions:: + sage: # needs scipy sage: from sage.misc.randstate import current_randstate sage: seed = current_randstate().seed() - sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) # optional - scipy - sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) # optional - scipy - sage: H.is_subgraph(G, induced=False) # optional - scipy + sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) + sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) + sage: H.is_subgraph(G, induced=False) True - sage: H.size() <= G.size() # optional - scipy + sage: H.size() <= G.size() True - sage: Gpos = G.get_pos() # optional - scipy - sage: Hpos = H.get_pos() # optional - scipy - sage: all(Gpos[u] == Hpos[u] for u in G) # optional - scipy + sage: Gpos = G.get_pos() + sage: Hpos = H.get_pos() + sage: all(Gpos[u] == Hpos[u] for u in G) True When the radius is more than `\sqrt{2 \text{side}}`, the graph is a clique:: - sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # optional - scipy - sage: G.is_clique() # optional - scipy + sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # needs scipy + sage: G.is_clique() # needs scipy True """ if seed is not None: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 36275b2ce57..bb73e4c487e 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -139,21 +139,22 @@ def HarriesGraph(embedding=1): EXAMPLES:: - sage: g = graphs.HarriesGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HarriesGraph() + sage: g.order() 70 - sage: g.size() # optional - networkx + sage: g.size() 105 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot - sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.HarriesGraph(embedding=3) # optional - networkx + sage: graphs.HarriesGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -257,25 +258,26 @@ def HarriesWongGraph(embedding=1): EXAMPLES:: - sage: g = graphs.HarriesWongGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HarriesWongGraph() + sage: g.order() 70 - sage: g.size() # optional - networkx + sage: g.size() 105 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # optional - networkx sage.groups - sage: g.show(figsize=[15, 15], partition=orbits) # long time # optional - networkx sage.groups sage.plot + sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # needs sage.groups + sage: g.show(figsize=[15, 15], partition=orbits) # long time # needs sage.groups sage.plot Alternative embedding:: - sage: graphs.HarriesWongGraph(embedding=2).show() # long time # optional - networkx sage.plot + sage: graphs.HarriesWongGraph(embedding=2).show() # long time # needs networkx sage.plot TESTS:: - sage: graphs.HarriesWongGraph(embedding=3) # optional - networkx + sage: graphs.HarriesWongGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -453,12 +455,13 @@ def Cell600(embedding=1): EXAMPLES:: - sage: g = graphs.Cell600() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell600() + sage: g.size() 720 - sage: g.is_regular(12) # long time + sage: g.is_regular(12) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -528,12 +531,13 @@ def Cell120(): EXAMPLES:: - sage: g = graphs.Cell120() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell120() + sage: g.size() 1200 - sage: g.is_regular(4) # long time + sage: g.is_regular(4) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -679,7 +683,7 @@ def HallJankoGraph(from_string=True): sage: g = graphs.HallJankoGraph() sage: g.is_regular(36) True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True Is it really strongly regular with parameters 14, 12? :: @@ -702,7 +706,7 @@ def HallJankoGraph(from_string=True): 2 sage: g.girth() 3 - sage: factor(g.characteristic_polynomial()) + sage: factor(g.characteristic_polynomial()) # needs sage.libs.pari sage.modules (x - 36) * (x - 6)^36 * (x + 4)^63 TESTS:: @@ -804,20 +808,21 @@ def Balaban10Cage(embedding=1): EXAMPLES:: - sage: g = graphs.Balaban10Cage() # optional - networkx - sage: g.girth() # optional - networkx + sage: # needs networkx + sage: g = graphs.Balaban10Cage() + sage: g.girth() 10 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical.mip True - sage: g.show(figsize=[10,10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10,10]) # long time # needs sage.plot TESTS:: - sage: graphs.Balaban10Cage(embedding='foo') # optional - networkx + sage: graphs.Balaban10Cage(embedding='foo') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -897,21 +902,21 @@ def Balaban11Cage(embedding=1): 11 sage: g.diameter() 8 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 64 Our many embeddings:: sage: g1 = graphs.Balaban11Cage(embedding=1) - sage: g2 = graphs.Balaban11Cage(embedding=2) - sage: g3 = graphs.Balaban11Cage(embedding=3) - sage: g1.show(figsize=[10,10]) # long time # optional - sage.plot - sage: g2.show(figsize=[10,10]) # long time # optional - sage.plot - sage: g3.show(figsize=[10,10]) # long time # optional - sage.plot + sage: g2 = graphs.Balaban11Cage(embedding=2) # needs networkx + sage: g3 = graphs.Balaban11Cage(embedding=3) # needs networkx + sage: g1.show(figsize=[10,10]) # long time # needs sage.plot + sage: g2.show(figsize=[10,10]) # long time # needs networkx sage.plot + sage: g3.show(figsize=[10,10]) # long time # needs sage.plot Proof that the embeddings are the same graph:: - sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic + sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic # needs networkx True TESTS:: @@ -1071,7 +1076,7 @@ def BidiakisCube(): It is a Hamiltonian graph with diameter 3 and girth 4:: - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True sage: g.diameter() 3 @@ -1084,11 +1089,11 @@ def BidiakisCube(): sage: g.is_planar() True - sage: char_poly = g.characteristic_polynomial() - sage: x = char_poly.parent()('x') - sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 + sage: char_poly = g.characteristic_polynomial() # needs sage.modules + sage: x = char_poly.parent()('x') # needs sage.modules + sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 # needs sage.modules True - sage: g.chromatic_number() + sage: g.chromatic_number() # needs sage.modules 3 """ edge_dict = { @@ -1114,26 +1119,27 @@ def BiggsSmithGraph(embedding=1): Basic properties:: - sage: g = graphs.BiggsSmithGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.BiggsSmithGraph() + sage: g.order() 102 - sage: g.size() # optional - networkx + sage: g.size() 153 - sage: g.girth() # optional - networkx + sage: g.girth() 9 - sage: g.diameter() # optional - networkx + sage: g.diameter() 7 - sage: g.automorphism_group().cardinality() # long time # optional - networkx + sage: g.automorphism_group().cardinality() # long time 2448 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot The other embedding:: - sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # optional - networkx + sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # needs networkx TESTS:: - sage: graphs.BiggsSmithGraph(embedding='xyzzy') # optional - networkx + sage: graphs.BiggsSmithGraph(embedding='xyzzy') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -1199,16 +1205,16 @@ def BlanusaFirstSnarkGraph(): EXAMPLES:: - sage: g = graphs.BlanusaFirstSnarkGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: g = graphs.BlanusaFirstSnarkGraph() + sage: g.order() 18 - sage: g.size() # optional - sage.groups + sage: g.size() 27 - sage: g.diameter() # optional - sage.groups + sage: g.diameter() 4 - sage: g.girth() # optional - sage.groups + sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 8 """ g = Graph({17: [4, 7, 1], 0: [5], 3: [8], 13: [9], 12: [16], @@ -1234,16 +1240,16 @@ def BlanusaSecondSnarkGraph(): EXAMPLES:: - sage: g = graphs.BlanusaSecondSnarkGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: g = graphs.BlanusaSecondSnarkGraph() + sage: g.order() 18 - sage: g.size() # optional - sage.groups + sage: g.size() 27 - sage: g.diameter() # optional - sage.groups + sage: g.diameter() 4 - sage: g.girth() # optional - sage.groups + sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 4 """ c0 = (-1, 0) @@ -1312,15 +1318,15 @@ def BrinkmannGraph(): The Brinkmann graph is also Hamiltonian with chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.chromatic_number() 4 Its automorphism group is isomorphic to `D_7`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(7)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(7)) # needs sage.groups True """ edge_dict = { @@ -1361,18 +1367,17 @@ def BrouwerHaemersGraph(): EXAMPLES:: - sage: g = graphs.BrouwerHaemersGraph() # optional - sage.modules - sage: g # optional - sage.modules + sage: g = graphs.BrouwerHaemersGraph(); g # needs sage.modules Brouwer-Haemers: Graph on 81 vertices It is indeed strongly regular with parameters `(81,20,1,6)`:: - sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.modules + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.modules sage.rings.finite_rings (81, 20, 1, 6) Its has as eigenvalues `20,2` and `-7`:: - sage: set(g.spectrum()) == {20,2,-7} # optional - sage.modules + sage: set(g.spectrum()) == {20,2,-7} # needs sage.modules sage.rings.finite_rings True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1419,16 +1424,17 @@ def BuckyBall(): The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is much slower:: - sage: g = polytopes.buckyball().vertex_graph() # optional - sage.geometry.polyhedron - sage: g.remove_loops() # optional - sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron sage.rings.number_field + sage: g = polytopes.buckyball().vertex_graph() + sage: g.remove_loops() sage: h = graphs.BuckyBall() - sage: g.is_isomorphic(h) # optional - sage.geometry.polyhedron + sage: g.is_isomorphic(h) True The graph is returned along with an attractive embedding:: sage: g = graphs.BuckyBall() # long time - sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time # optional - sage.plot + sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time, needs sage.plot """ edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), @@ -1573,11 +1579,11 @@ def DoubleStarSnark(): 45 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 80 - sage: g.show() # optional - sage.plot + sage: g.show() # needs sage.plot """ d = {0: [1, 14, 15], 1: [0, 2, 11], @@ -1641,7 +1647,7 @@ def MeredithGraph(): 4 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip False """ g = Graph(name="Meredith Graph") @@ -1735,12 +1741,13 @@ def CameronGraph(): EXAMPLES:: - sage: g = graphs.CameronGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: # needs sage.groups + sage: g = graphs.CameronGraph() + sage: g.order() 231 - sage: g.size() # optional - sage.groups + sage: g.size() 3465 - sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.groups + sage: g.is_strongly_regular(parameters=True) # long time (231, 30, 9, 3) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -1804,9 +1811,9 @@ def ChvatalGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.ChvatalGraph() - sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # needs networkx True """ edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9], @@ -1828,7 +1835,7 @@ def ClebschGraph(): EXAMPLES:: sage: g = graphs.ClebschGraph() - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 1920 sage: g.girth() 4 @@ -1836,7 +1843,7 @@ def ClebschGraph(): 4 sage: g.diameter() 2 - sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph(pos={}) x = 0 @@ -1865,7 +1872,7 @@ def CoxeterGraph(): EXAMPLES:: sage: g = graphs.CoxeterGraph() - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.girth() 7 @@ -1873,7 +1880,7 @@ def CoxeterGraph(): 3 sage: g.diameter() 4 - sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph({ 27: [6, 22, 14], @@ -1904,11 +1911,11 @@ def DejterGraph(): EXAMPLES:: - sage: g = graphs.DejterGraph(); g # optional - sage.rings.finite_rings + sage: g = graphs.DejterGraph(); g # needs sage.rings.finite_rings Dejter Graph: Graph on 112 vertices - sage: g.is_regular(k=6) # optional - sage.rings.finite_rings + sage: g.is_regular(k=6) # needs sage.rings.finite_rings True - sage: g.girth() # optional - sage.rings.finite_rings + sage: g.girth() # needs sage.rings.finite_rings 4 """ from sage.graphs.generators.families import CubeGraph @@ -1931,10 +1938,10 @@ def DesarguesGraph(): EXAMPLES:: sage: D = graphs.DesarguesGraph() - sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # optional - networkx - sage: D.is_isomorphic(L) # optional - networkx + sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # needs networkx + sage: D.is_isomorphic(L) # needs networkx True - sage: D.show() # long time # optional - sage.plot + sage: D.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(10, 3) @@ -1973,8 +1980,8 @@ def DurerGraph(): Its automorphism group is isomorphic to `D_6`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ from sage.graphs.generators.families import GeneralizedPetersenGraph @@ -2012,7 +2019,7 @@ def DyckGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_bipartite() True @@ -2030,12 +2037,12 @@ def DyckGraph(): sage: G.chromatic_number() 2 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is a non-integral graph as it has irrational eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6 It is a toroidal graph, and its embedding on a torus is dual to an embedding @@ -2085,22 +2092,23 @@ def HortonGraph(): EXAMPLES:: - sage: g = graphs.HortonGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HortonGraph() + sage: g.order() 96 - sage: g.size() # optional - networkx + sage: g.size() 144 - sage: g.radius() # optional - networkx + sage: g.radius() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 10 - sage: g.girth() # optional - networkx + sage: g.girth() 6 - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 96 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.is_hamiltonian() # not tested -- veeeery long # optional - networkx + sage: g.is_hamiltonian() # not tested (veeeery long) # needs sage.numerical.mip False """ g = Graph(name="Horton Graph") @@ -2160,14 +2168,14 @@ def EllinghamHorton54Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested - too long 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: @@ -2237,23 +2245,23 @@ def EllinghamHorton78Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested (too long) 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: - sage: g.show(figsize=[10,10]) # not tested - too long + sage: g.show(figsize=[10,10]) # not tested (too long) TESTS:: - sage: g.show(figsize=[10, 10]) # not tested - too long + sage: g.show(figsize=[10, 10]) # not tested (too long) """ g = Graph({ 0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], @@ -2321,7 +2329,7 @@ def ErreraGraph(): The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.radius() 3 @@ -2343,8 +2351,8 @@ def ErreraGraph(): The automorphism group of the Errera graph is isomorphic to the dihedral group of order 20:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(10)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(10)) # needs sage.groups True """ edge_dict = { @@ -2374,17 +2382,18 @@ def F26AGraph(): EXAMPLES:: - sage: g = graphs.F26AGraph(); g # optional - networkx + sage: # needs networkx + sage: g = graphs.F26AGraph(); g F26A Graph: Graph on 26 vertices - sage: g.order(), g.size() # optional - networkx + sage: g.order(), g.size() (26, 39) - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 78 - sage: g.girth() # optional - networkx + sage: g.girth() 6 - sage: g.is_bipartite() # optional - networkx + sage: g.is_bipartite() True - sage: g.characteristic_polynomial().factor() # optional - networkx + sage: g.characteristic_polynomial().factor() (x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6 """ from sage.graphs.generators.families import LCFGraph @@ -2435,26 +2444,27 @@ def FolkmanGraph(): EXAMPLES:: - sage: g = graphs.FolkmanGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.FolkmanGraph() + sage: g.order() 20 - sage: g.size() # optional - networkx + sage: g.size() 40 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.girth() # optional - networkx + sage: g.girth() 4 - sage: g.charpoly().factor() # optional - networkx + sage: g.charpoly().factor() (x - 4) * (x + 4) * x^10 * (x^2 - 6)^4 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.is_eulerian() # optional - networkx + sage: g.is_eulerian() True - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical_mip True - sage: g.is_vertex_transitive() # optional - networkx + sage: g.is_vertex_transitive() False - sage: g.is_bipartite() # optional - networkx + sage: g.is_bipartite() True """ from sage.graphs.generators.families import LCFGraph @@ -2471,18 +2481,19 @@ def FosterGraph(): EXAMPLES:: - sage: g = graphs.FosterGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.FosterGraph() + sage: g.order() 90 - sage: g.size() # optional - networkx + sage: g.size() 135 - sage: g.diameter() # optional - networkx + sage: g.diameter() 8 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 4320 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical_mip True """ from sage.graphs.generators.families import LCFGraph @@ -2514,7 +2525,7 @@ def FranklinGraph(): The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical_mip True sage: G.is_bipartite() True @@ -2565,18 +2576,18 @@ def FruchtGraph(): EXAMPLES:: - sage: FRUCHT = graphs.FruchtGraph() # optional - networkx - sage: FRUCHT # optional - networkx + sage: FRUCHT = graphs.FruchtGraph() + sage: FRUCHT Frucht graph: Graph on 12 vertices - sage: FRUCHT.graph6_string() # optional - networkx + sage: FRUCHT.graph6_string() 'KhCKM?_EGK?L' - sage: (graphs.FruchtGraph()).show() # long time # optional - networkx + sage: (graphs.FruchtGraph()).show() # long time # needs networkx TESTS:: - sage: import networkx # optional - networkx - sage: G = graphs.FruchtGraph() # optional - networkx - sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # optional - networkx + sage: import networkx # needs networkx + sage: G = graphs.FruchtGraph() + sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # needs networkx True """ edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9], @@ -2624,8 +2635,8 @@ def GoldnerHararyGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2668,12 +2679,12 @@ def GolombGraph(): and 18 edges. It has chromatic number 4, diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:: - sage: G = graphs.GolombGraph(); G # optional - sage.symbolic + sage: G = graphs.GolombGraph(); G # needs sage.symbolic Golomb graph: Graph on 10 vertices - sage: pos = G.get_pos() # optional - sage.symbolic + sage: pos = G.get_pos() # needs sage.symbolic sage: def dist2(u, v): ....: return (u[0]-v[0])**2 + (u[1]-v[1])**2 - sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # optional - sage.symbolic + sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # needs sage.symbolic True """ edge_dict = { @@ -2713,6 +2724,7 @@ def GrayGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.GrayGraph() sage: g.order() 54 @@ -2722,12 +2734,12 @@ def GrayGraph(embedding=1): 8 sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time - sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.GrayGraph(embedding=3) + sage: graphs.GrayGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1, 2, or 3 @@ -2762,7 +2774,7 @@ def GrotzschGraph(): sage: G = graphs.GrotzschGraph(); G Grotzsch graph: Graph on 11 vertices - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.order() 11 @@ -2786,8 +2798,8 @@ def GrotzschGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(5)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(5)) # needs sage.groups True """ edges = [(0, u) for u in range(1, 6)] @@ -2836,9 +2848,9 @@ def HeawoodGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.HeawoodGraph() - sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # needs networkx True """ edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9], @@ -2888,8 +2900,8 @@ def HerschelGraph(): sage: G.chromatic_number() 2 - sage: ag = G.automorphism_group() # optional - sage.groups - sage: ag.is_isomorphic(DihedralGroup(6)) # optional - sage.groups + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2919,9 +2931,9 @@ def GritsenkoGraph(): EXAMPLES:: - sage: H = graphs.GritsenkoGraph(); H # optional - sage.groups + sage: H = graphs.GritsenkoGraph(); H # needs sage.groups Gritsenko strongly regular graph: Graph on 65 vertices - sage: H.is_strongly_regular(parameters=True) # optional - sage.groups + sage: H.is_strongly_regular(parameters=True) # needs sage.groups (65, 32, 15, 16) """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -3000,13 +3012,13 @@ def HigmanSimsGraph(relabel=True): which is of index 2 and is simple. It is known as the Higman-Sims group:: sage: H = graphs.HigmanSimsGraph() - sage: G = H.automorphism_group() # optional - sage.groups - sage: g = G.order(); g # optional - sage.groups + sage: G = H.automorphism_group() # needs sage.groups + sage: g = G.order(); g # needs sage.groups 88704000 - sage: K = G.normal_subgroups()[1] # optional - sage.groups - sage: K.is_simple() # optional - sage.groups + sage: K = G.normal_subgroups()[1] # needs sage.groups + sage: K.is_simple() # needs sage.groups True - sage: g//K.order() # optional - sage.groups + sage: g//K.order() # needs sage.groups 2 AUTHOR: @@ -3186,13 +3198,13 @@ def HoffmanGraph(): sage: g = graphs.HoffmanGraph() sage: g.is_bipartite() True - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 sage: g.diameter() 4 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 48 """ g = Graph({ @@ -3231,11 +3243,11 @@ def HoltGraph(): Holt graph: Graph on 27 vertices sage: g.is_regular() True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 @@ -3243,7 +3255,7 @@ def HoltGraph(): 3 sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 54 """ g = Graph(loops=False, name="Holt graph", pos={}) @@ -3295,9 +3307,9 @@ def KrackhardtKiteGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.KrackhardtKiteGraph() - sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # needs networkx True """ edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6], @@ -3324,7 +3336,7 @@ def Klein3RegularGraph(): (56, 84) sage: g.girth() 7 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 3 @@ -3357,7 +3369,7 @@ def Klein7RegularGraph(): (24, 84) sage: g.girth() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 4 @@ -3382,9 +3394,9 @@ def LocalMcLaughlinGraph(): EXAMPLES:: - sage: g = graphs.LocalMcLaughlinGraph(); g # long time # optional - gap_packages + sage: g = graphs.LocalMcLaughlinGraph(); g # long time, optional - gap_package_design Local McLaughlin Graph: Graph on 162 vertices - sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages + sage: g.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (162, 56, 10, 24) """ g = McLaughlinGraph() @@ -3413,21 +3425,22 @@ def LjubljanaGraph(embedding=1): EXAMPLES:: - sage: g = graphs.LjubljanaGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.LjubljanaGraph() + sage: g.order() 112 - sage: g.size() # optional - networkx + sage: g.size() 168 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 8 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot - sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.LjubljanaGraph(embedding=3) # optional - networkx + sage: graphs.LjubljanaGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3486,16 +3499,17 @@ def LivingstoneGraph(): EXAMPLES:: - sage: g = graphs.LivingstoneGraph() # optional - internet - sage: g.order() # optional - internet + sage: # optional - internet + sage: g = graphs.LivingstoneGraph() + sage: g.order() 266 - sage: g.size() # optional - internet + sage: g.size() 1463 - sage: g.girth() # optional - internet + sage: g.girth() 5 - sage: g.is_vertex_transitive() # optional - internet + sage: g.is_vertex_transitive() True - sage: g.is_distance_regular() # optional - internet + sage: g.is_distance_regular() True """ from sage.groups.perm_gps.permgroup_named import JankoGroup @@ -3518,12 +3532,13 @@ def M22Graph(): EXAMPLES:: - sage: g = graphs.M22Graph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: # needs sage.groups + sage: g = graphs.M22Graph() + sage: g.order() 77 - sage: g.size() # optional - sage.groups + sage: g.size() 616 - sage: g.is_strongly_regular(parameters=True) # optional - sage.groups + sage: g.is_strongly_regular(parameters=True) (77, 16, 0, 4) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -3561,11 +3576,11 @@ def MarkstroemGraph(): True sage: g.is_regular(3) True - sage: g.subgraph_search(graphs.CycleGraph(4)) is None # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(4)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(8)) is None # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(8)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(16)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(16)) # needs sage.modules Subgraph of (Markstroem Graph): Graph on 16 vertices """ g = Graph(name="Markstroem Graph") @@ -3602,21 +3617,22 @@ def McGeeGraph(embedding=2): EXAMPLES:: - sage: g = graphs.McGeeGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.McGeeGraph() + sage: g.order() 24 - sage: g.size() # optional - networkx + sage: g.size() 36 - sage: g.girth() # optional - networkx + sage: g.girth() 7 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.show() # optional - networkx sage.plot - sage: graphs.McGeeGraph(embedding=1).show() # long time # optional - networkx sage.plot + sage: g.show() # needs sage.plot + sage: graphs.McGeeGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.McGeeGraph(embedding=3) # optional - networkx + sage: graphs.McGeeGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3661,10 +3677,10 @@ def McLaughlinGraph(): EXAMPLES:: - sage: g = graphs.McLaughlinGraph() # optional gap_packages - sage: g.is_strongly_regular(parameters=True) # optional gap_packages + sage: g = graphs.McLaughlinGraph() # optional - gap_package_design + sage: g.is_strongly_regular(parameters=True) # optional - gap_package_design (275, 112, 30, 56) - sage: set(g.spectrum()) == {112, 2, -28} # optional gap_packages + sage: set(g.spectrum()) == {112, 2, -28} # optional - gap_package_design True """ from sage.combinat.designs.block_design import WittDesign @@ -3726,7 +3742,7 @@ def MoebiusKantorGraph(): Moebius-Kantor Graph: Graph on 16 vertices sage: MK.graph6_string() 'OhCGKE?O@?ACAC@I?Q_AS' - sage: (graphs.MoebiusKantorGraph()).show() # long time # optional - sage.plot + sage: (graphs.MoebiusKantorGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(8, 3) @@ -3744,38 +3760,41 @@ def MoserSpindle(): The Moser spindle is a planar graph having 7 vertices and 11 edges:: - sage: G = graphs.MoserSpindle(); G # optional - sage.symbolic + sage: # needs sage.symbolic + sage: G = graphs.MoserSpindle(); G Moser spindle: Graph on 7 vertices - sage: G.is_planar() # optional - sage.symbolic + sage: G.is_planar() True - sage: G.order() # optional - sage.symbolic + sage: G.order() 7 - sage: G.size() # optional - sage.symbolic + sage: G.size() 11 It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:: - sage: G.is_hamiltonian() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: G.is_hamiltonian() # needs sage.numerical.mip True - sage: G.radius() # optional - sage.symbolic + sage: G.radius() 2 - sage: G.diameter() # optional - sage.symbolic + sage: G.diameter() 2 - sage: G.girth() # optional - sage.symbolic + sage: G.girth() 3 The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its automorphism group is isomorphic to the dihedral group `D_4`:: - sage: pos = G.get_pos() # optional - sage.symbolic - sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 # optional - sage.symbolic + sage: # needs sage.symbolic + sage: pos = G.get_pos() + sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 ....: for u, v in G.edge_iterator(labels=None)) True - sage: G.chromatic_number() # optional - sage.symbolic + sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() # optional - sage.symbolic - sage: ag.is_isomorphic(DihedralGroup(4)) # optional - sage.symbolic + sage: ag = G.automorphism_group() + sage: ag.is_isomorphic(DihedralGroup(4)) True """ edge_dict = { @@ -3821,8 +3840,8 @@ def NauruGraph(embedding=2): 6 sage: g.diameter() 4 - sage: g.show() # optional - sage.plot - sage: graphs.NauruGraph(embedding=1).show() # long time # optional - sage.plot + sage: g.show() # needs sage.plot + sage: graphs.NauruGraph(embedding=1).show() # long time # needs sage.plot TESTS:: @@ -3830,7 +3849,7 @@ def NauruGraph(embedding=2): Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 - sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # optional - networkx + sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # needs networkx True """ @@ -3857,10 +3876,10 @@ def PappusGraph(): EXAMPLES:: sage: G = graphs.PappusGraph() - sage: G.show() # long time # optional - sage.plot - sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # optional - networkx - sage: L.show() # long time # optional - networkx sage.plot - sage: G.is_isomorphic(L) # optional - networkx + sage: G.show() # long time # needs sage.plot + sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # needs networkx + sage: L.show() # long time # needs networkx sage.plot + sage: G.is_isomorphic(L) # needs networkx True """ edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], @@ -3923,9 +3942,9 @@ def PetersenGraph(): ....: 3:[2,4,8], 4:[0,3,9], 5:[0,7,8], ....: 6:[1,8,9], 7:[2,5,9], 8:[3,5,6], ....: 9:[4,6,7]}) - sage: petersen_spring.show() # long time # optional - sage.plot + sage: petersen_spring.show() # long time # needs sage.plot sage: petersen_database = graphs.PetersenGraph() - sage: petersen_database.show() # long time # optional - sage.plot + sage: petersen_database.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph P = GeneralizedPetersenGraph(5, 2) @@ -3970,23 +3989,24 @@ def RobertsonGraph(): EXAMPLES:: - sage: g = graphs.RobertsonGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.RobertsonGraph() + sage: g.order() 19 - sage: g.size() # optional - networkx + sage: g.size() 38 - sage: g.diameter() # optional - networkx + sage: g.diameter() 3 - sage: g.girth() # optional - networkx + sage: g.girth() 5 - sage: g.charpoly().factor() # optional - networkx + sage: g.charpoly().factor() (x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) * (x^2 - 3)^2 * (x^2 + x - 4)^2 * (x^2 + x - 3)^2 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical.mip True - sage: g.is_vertex_transitive() # optional - networkx + sage: g.is_vertex_transitive() False """ from sage.graphs.generators.families import LCFGraph @@ -4024,7 +4044,7 @@ def SchlaefliGraph(): The graph is vertex-transitive:: - sage: S.is_vertex_transitive() # optional - sage.groups + sage: S.is_vertex_transitive() # needs sage.groups True The neighborhood of each vertex is isomorphic to the complement of the @@ -4079,7 +4099,7 @@ def ShrikhandeGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_eulerian() True @@ -4097,12 +4117,12 @@ def ShrikhandeGraph(): sage: G.chromatic_number() 4 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is an integral graph since it has only integral eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 6) * (x - 2)^6 * (x + 2)^9 It is a toroidal graph, and its embedding on a torus is dual to an @@ -4236,12 +4256,12 @@ def SousselierGraph(): 2 sage: g.diameter() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 2 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ g = Graph(name="Sousselier Graph") @@ -4317,7 +4337,7 @@ def ThomsenGraph(): Thomsen graph: Graph on 6 vertices sage: T.graph6_string() 'EFz_' - sage: (graphs.ThomsenGraph()).show() # long time # optional - sage.plot + sage: (graphs.ThomsenGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.basic import CompleteBipartiteGraph G = CompleteBipartiteGraph(3, 3) @@ -4343,9 +4363,9 @@ def TietzeGraph(): 3 sage: g.girth() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 12 - sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # optional - sage.groups + sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # needs sage.groups True """ g = Graph([(0, 9), (3, 10), (6, 11), (1, 5), (2, 7), (4, 8)], @@ -4370,11 +4390,11 @@ def TruncatedIcosidodecahedralGraph(): Unfortunately, this graph can not be constructed currently, due to numerical issues:: - sage: g = graphs.TruncatedIcosidodecahedralGraph(); g + sage: g = graphs.TruncatedIcosidodecahedralGraph(); g # needs sage.geometry.polyhedron sage.groups sage.rings.number_field Traceback (most recent call last): ... ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic. - sage: g.order(), g.size() # not tested + sage: g.order(), g.size() # not tested # needs sage.geometry.polyhedron sage.groups sage.rings.number_field (120, 180) """ from sage.geometry.polyhedron.library import polytopes @@ -4397,7 +4417,7 @@ def TruncatedTetrahedralGraph(): Truncated Tetrahedron: Graph on 12 vertices sage: g.order(), g.size() (12, 18) - sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # optional - sage.geometry.polyhedron + sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # needs sage.geometry.polyhedron True """ g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False) @@ -4416,16 +4436,17 @@ def Tutte12Cage(): EXAMPLES:: - sage: g = graphs.Tutte12Cage() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.Tutte12Cage() + sage: g.order() 126 - sage: g.size() # optional - networkx + sage: g.size() 189 - sage: g.girth() # optional - networkx + sage: g.girth() 12 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.show() # optional - networkx sage.plot + sage: g.show() # needs sage.plot """ L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11, -21, -57, 59, -17] @@ -4449,21 +4470,22 @@ def TutteCoxeterGraph(embedding=2): EXAMPLES:: - sage: g = graphs.TutteCoxeterGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.TutteCoxeterGraph() + sage: g.order() 30 - sage: g.size() # optional - networkx + sage: g.size() 45 - sage: g.girth() # optional - networkx + sage: g.girth() 8 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.show() # optional - networkx sage.plot - sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # optional - networkx sage.plot + sage: g.show() # needs sage.plot + sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.TutteCoxeterGraph(embedding=3) # optional - networkx + sage: graphs.TutteCoxeterGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -4516,9 +4538,9 @@ def TutteGraph(): 3 sage: g.girth() 4 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False """ g = Graph(name="Tutte Graph") @@ -4562,16 +4584,17 @@ def WagnerGraph(): EXAMPLES:: - sage: g = graphs.WagnerGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.WagnerGraph() + sage: g.order() 8 - sage: g.size() # optional - networkx + sage: g.size() 12 - sage: g.girth() # optional - networkx + sage: g.girth() 4 - sage: g.diameter() # optional - networkx + sage: g.diameter() 2 - sage: g.show() # optional - networkx sage.plot + sage: g.show() # needs sage.plot """ from sage.graphs.generators.families import LCFGraph g = LCFGraph(8, [4], 8) @@ -4637,10 +4660,10 @@ def WienerArayaGraph(): 4 sage: g.is_planar() True - sage: g.is_hamiltonian() # not tested -- around 30s long + sage: g.is_hamiltonian() # not tested (30s) # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ g = Graph(name="Wiener-Araya Graph") @@ -4695,7 +4718,7 @@ def _EllipticLinesProjectivePlaneScheme(k): TESTS:: sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme - sage: _EllipticLinesProjectivePlaneScheme(2) + sage: _EllipticLinesProjectivePlaneScheme(2) # needs sage.libs.gap [ [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] @@ -4738,11 +4761,12 @@ def MathonStronglyRegularGraph(t): TESTS:: - sage: G = graphs.MathonStronglyRegularGraph(1) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: # long time + sage: G = graphs.MathonStronglyRegularGraph(1) + sage: G.is_strongly_regular(parameters=True) (784, 270, 98, 90) - sage: G = graphs.MathonStronglyRegularGraph(2) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = graphs.MathonStronglyRegularGraph(2) + sage: G.is_strongly_regular(parameters=True) (784, 297, 116, 110) """ @@ -5009,12 +5033,12 @@ def IoninKharaghani765Graph(): EXAMPLES:: - sage: g = graphs.IoninKharaghani765Graph(); g + sage: g = graphs.IoninKharaghani765Graph(); g # needs sage.modules sage.rings.finite_rings Ionin-Kharaghani: Graph on 765 vertices TESTS:: - sage: graphs.strongly_regular_graph(765, 192, 48, 48) + sage: graphs.strongly_regular_graph(765, 192, 48, 48) # needs sage.modules sage.rings.finite_rings Ionin-Kharaghani: Graph on 765 vertices .. TODO:: @@ -5105,8 +5129,8 @@ def U42Graph216(): EXAMPLES:: - sage: G=graphs.U42Graph216() # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G=graphs.U42Graph216() # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (216, 40, 4, 8) """ from sage.libs.gap.libgap import libgap @@ -5152,8 +5176,8 @@ def U42Graph540(): EXAMPLES:: - sage: G=graphs.U42Graph540() # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.U42Graph540() # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (540, 187, 58, 68) """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a083ed43e5e..2deb533f7f1 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -439,7 +439,6 @@ from sage.misc.decorators import options from sage.misc.cachefunc import cached_method from sage.misc.prandom import random -from sage.misc.superseded import deprecation from sage.misc.lazy_import import lazy_import, LazyImport from sage.rings.integer_ring import ZZ @@ -3515,7 +3514,7 @@ def allow_multiple_edges(self, new, check=True, keep_label='any'): self._backend.multiple_edges(new) - def multiple_edges(self, to_undirected=False, labels=True, sort=False): + def multiple_edges(self, to_undirected=False, labels=True, sort=False, key=None): """ Return any multiple edges in the (di)graph. @@ -3525,7 +3524,11 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): - ``labels`` -- boolean (default: ``True``); whether to include labels - - ``sort`` - boolean (default: ``False``); whether to sort the result + - ``sort`` -- boolean (default: ``False``); whether to sort the result + + - ``key`` -- a function (default: ``None``); a function that takes an + edge as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) EXAMPLES:: @@ -3574,7 +3577,36 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): [] sage: G.multiple_edges(to_undirected=True, sort=True) [(1, 2, 'h'), (2, 1, 'g')] + + Using the ``key`` argument to order multiple edges of incomparable + types (see :trac:`35903`):: + + sage: G = Graph([('A', 'B', 3), (1, 2, 1), ('A', 'B', 4), (1, 2, 2)], multiedges=True) + sage: G.multiple_edges(sort=True) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '' + sage: G.multiple_edges(labels=False, sort=True, key=str) + [('A', 'B'), ('A', 'B'), (1, 2), (1, 2)] + sage: G.multiple_edges(sort=True, key=str) + [('A', 'B', 3), ('A', 'B', 4), (1, 2, 1), (1, 2, 2)] + sage: G.multiple_edges(labels=True, sort=True, key=lambda e:e[2]) + [(1, 2, 1), (1, 2, 2), ('A', 'B', 3), ('A', 'B', 4)] + sage: G.multiple_edges(labels=False, sort=True, key=lambda e:e[2]) + Traceback (most recent call last): + ... + IndexError: tuple index out of range + + TESTS:: + + sage: Graph().multiple_edges(sort=False, key=str) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given """ + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + multi_edges = [] seen = set() @@ -3647,7 +3679,7 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): multi_edges.extend((u, v) for _ in L) if sort: - multi_edges.sort() + return sorted(multi_edges, key=key) return multi_edges def name(self, new=None): @@ -4964,15 +4996,15 @@ def spanning_trees_count(self, root_vertex=None): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: G.spanning_trees_count() + sage: G.spanning_trees_count() # needs sage.modules 2000 :: sage: n = 11 sage: G = graphs.CompleteGraph(n) - sage: ST = G.spanning_trees_count() - sage: ST == n ^ (n - 2) + sage: ST = G.spanning_trees_count() # needs sage.modules + sage: ST == n ^ (n - 2) # needs sage.modules True :: @@ -5092,7 +5124,7 @@ def cycle_basis(self, output='vertex'): sage: G.cycle_basis() # needs networkx [[0, 2], [2, 1, 0]] sage: G.cycle_basis(output='edge') # needs networkx - [[(0, 2, 'a'), (2, 0, 'b')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]] + [[(0, 2, 'b'), (2, 0, 'a')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]] sage: H = Graph([(1, 2), (2, 3), (2, 3), (3, 4), (1, 4), ....: (1, 4), (4, 5), (5, 6), (4, 6), (6, 7)], multiedges=True) sage: H.cycle_basis() # needs networkx @@ -5134,10 +5166,9 @@ def cycle_basis(self, output='vertex'): sage: G.cycle_basis() # needs networkx [[2, 3], [4, 3, 2, 1], [4, 3, 2, 1]] sage: G.cycle_basis(output='edge') # needs networkx - [[(2, 3, 'b'), (3, 2, 'c')], + [[(2, 3, 'c'), (3, 2, 'b')], [(4, 3, 'd'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')], [(4, 3, 'e'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')]] - """ if output not in ['vertex', 'edge']: raise ValueError('output must be either vertex or edge') @@ -6860,34 +6891,36 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None The Petersen Graph does have a spanning tree (it is connected):: sage: g = graphs.PetersenGraph() - sage: [T] = g.edge_disjoint_spanning_trees(1) - sage: T.is_tree() + sage: [T] = g.edge_disjoint_spanning_trees(1) # needs sage.numerical.mip + sage: T.is_tree() # needs sage.numerical.mip True Though, it does not have 2 edge-disjoint trees (as it has less than `2(|V|-1)` edges):: - sage: g.edge_disjoint_spanning_trees(2) + sage: g.edge_disjoint_spanning_trees(2) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: this graph does not contain the required number of trees/arborescences - By Edmond's theorem, a graph which is `k`-connected always has `k` + By Edmonds' theorem, a graph which is `k`-connected always has `k` edge-disjoint arborescences, regardless of the root we pick:: + sage: # needs sage.numerical.mip sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) sage: while not k: ....: g = digraphs.RandomDirectedGNP(11, .3) ....: k = Integer(g.edge_connectivity()) - sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) - sage: all(a.is_directed_acyclic() for a in arborescences) # long time + sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) + sage: all(a.is_directed_acyclic() for a in arborescences) # long time True sage: all(a.is_connected() for a in arborescences) # long time True In the undirected case, we can only ensure half of it:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169 sage: while not g.is_biconnected(): ....: g = graphs.RandomGNP(14, .3) @@ -6898,6 +6931,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Check the validity of the algorithms for undirected graphs:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(12, .7) sage: k = Integer(g.edge_connectivity()) // 2 sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") @@ -6919,7 +6953,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None sage: G = DiGraph(d6, format='dig6') sage: G.edge_connectivity() 5 - sage: G.edge_disjoint_spanning_trees(5) # long time + sage: G.edge_disjoint_spanning_trees(5) # long time # needs sage.numerical.mip [Digraph on 28 vertices, Digraph on 28 vertices, Digraph on 28 vertices, @@ -6928,6 +6962,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Small cases:: + sage: # needs sage.numerical.mip sage: Graph().edge_disjoint_spanning_trees(0) [] sage: Graph(1).edge_disjoint_spanning_trees(0) @@ -6947,11 +6982,11 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Choice of the algorithm:: - sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) + sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="Roskind-Tarjan") [] - sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -6959,7 +6994,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None ValueError: algorithm must be None, "Rosking-Tarjan" or "MILP" for undirected graphs sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm=None) [] - sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -7370,25 +7405,25 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose A basic application in the Pappus graph:: sage: g = graphs.PappusGraph() - sage: g.vertex_cut(1, 16, value_only=True) + sage: g.vertex_cut(1, 16, value_only=True) # needs sage.numerical.mip 3 In the bipartite complete graph `K_{2,8}`, a cut between the two vertices in the size `2` part consists of the other `8` vertices:: sage: g = graphs.CompleteBipartiteGraph(2, 8) - sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) - sage: print(value) + sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) # needs sage.numerical.mip + sage: print(value) # needs sage.numerical.mip 8 - sage: vertices == list(range(2, 10)) + sage: vertices == list(range(2, 10)) # needs sage.numerical.mip True Clearly, in this case the two sides of the cut are singletons:: - sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) - sage: len(set1) == 1 + sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) # needs sage.numerical.mip + sage: len(set1) == 1 # needs sage.numerical.mip True - sage: len(set2) == 1 + sage: len(set2) == 1 # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -7495,35 +7530,35 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, edge cut:: sage: g = graphs.PetersenGraph() - sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True) + sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only=True) # needs sage.numerical.mip True As Petersen's graph is `3`-regular, a minimum multiway cut between three vertices contains at most `2\times 3` edges (which could correspond to the neighborhood of 2 vertices):: - sage: g.multiway_cut([0,3,9], value_only = True) == 2*3 + sage: g.multiway_cut([0,3,9], value_only=True) == 2*3 # needs sage.numerical.mip True In this case, though, the vertices are an independent set. If we pick instead vertices `0,9,` and `7`, we can save `4` edges in the multiway cut:: - sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1 + sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1 # needs sage.numerical.mip True This example, though, does not work in the directed case anymore, as it is not possible in Petersen's graph to mutualise edges:: sage: g = DiGraph(g) - sage: g.multiway_cut([0,7,9], value_only = True) == 3*3 + sage: g.multiway_cut([0,7,9], value_only=True) == 3*3 # needs sage.numerical.mip True Of course, a multiway cut between the whole vertex set contains all the edges of the graph:: - sage: C = g.multiway_cut(g.vertices(sort=False)) - sage: set(C) == set(g.edges(sort=False)) + sage: C = g.multiway_cut(g.vertices(sort=False)) # needs sage.numerical.mip + sage: set(C) == set(g.edges(sort=False)) # needs sage.numerical.mip True """ self._scream_if_not_simple(allow_loops=True) @@ -7633,18 +7668,20 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, Quite obviously, the max cut of a bipartite graph is the number of edges, and the two sets of vertices are the two sides:: + sage: # needs sage.numerical.mip sage: g = graphs.CompleteBipartiteGraph(5,6) sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) sage: value == 5*6 True - sage: bsetA, bsetB = map(list,g.bipartite_sets()) - sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA )) + sage: bsetA, bsetB = map(list, g.bipartite_sets()) + sage: ((bsetA == setA and bsetB == setB) + ....: or (bsetA == setB and bsetB == setA)) True The max cut of a Petersen graph:: - sage: g=graphs.PetersenGraph() - sage: g.max_cut() + sage: g = graphs.PetersenGraph() + sage: g.max_cut() # needs sage.numerical.mip 12 TESTS:: @@ -7809,8 +7846,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", `n - 2`:: sage: g = graphs.PetersenGraph() - sage: lp = g.longest_path() - sage: lp.order() >= g.order() - 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: lp.order() >= g.order() - 2 # needs sage.numerical.mip True The heuristic totally agrees:: @@ -7831,8 +7868,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = graphs.RandomGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_forest() or not max(lp.degree()) <= 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_forest() or not max(lp.degree()) <= 2 # needs sage.numerical.mip ....: or not lp.is_connected()) False @@ -7850,9 +7887,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g1 = graphs.PetersenGraph() sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path() - sage: lp2 = g2.longest_path() - sage: len(lp1) == len(lp2) + sage: lp1 = g1.longest_path() # needs sage.numerical.mip + sage: lp2 = g2.longest_path() # needs sage.numerical.mip + sage: len(lp1) == len(lp2) # needs sage.numerical.mip True Disconnected graphs weighted:: @@ -7861,13 +7898,14 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: for u,v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path(use_edge_labels=True) - sage: lp2 = g2.longest_path(use_edge_labels=True) - sage: lp1[0] == lp2[0] + sage: lp1 = g1.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp2 = g2.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp1[0] == lp2[0] # needs sage.numerical.mip True Empty graphs:: + sage: # needs sage.numerical.mip sage: Graph().longest_path() Graph on 0 vertices sage: Graph().longest_path(use_edge_labels=True) @@ -7879,6 +7917,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", Trivial graphs:: + sage: # needs sage.numerical.mip sage: G = Graph() sage: G.add_vertex(0) sage: G.longest_path() @@ -7895,8 +7934,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = digraphs.RandomDirectedGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_directed_acyclic() or + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_directed_acyclic() or # needs sage.numerical.mip ....: not max(lp.out_degree()) <= 1 or ....: not max(lp.in_degree()) <= 1 or ....: not lp.is_connected()) @@ -7905,7 +7944,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", :trac:`13019`:: sage: g = graphs.CompleteGraph(5).to_directed() - sage: g.longest_path(s=1, t=2) + sage: g.longest_path(s=1, t=2) # needs sage.numerical.mip Subgraph of (Complete graph): Digraph on 5 vertices :trac:`14412`:: @@ -7913,7 +7952,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: l = [(0, 1), (0, 3), (2, 0), (3, 4)] sage: G = DiGraph(l) sage: H = {(0, 3), (2, 0), (3, 4)} - sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} + sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -8189,6 +8228,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, starting from vertex `(0, 0)` and ending at vertex `(2, 2)`, but no Hamiltonian path starting from `(0, 0)` and ending at `(0, 1)`:: + sage: # needs sage.numerical.mip sage: g = graphs.Grid2dGraph(3, 3) sage: g.hamiltonian_path() Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices @@ -8206,13 +8246,13 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, Empty and one-element graphs:: sage: g = Graph() - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined for empty and one-element (di)graphs sage: g = Graph(1) - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined @@ -8221,20 +8261,22 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, A non-connected (di)graph has no hamiltonian path:: sage: g = Graph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True - sage: g.hamiltonian_path(use_edge_labels=True) + sage: g.hamiltonian_path(use_edge_labels=True) # needs sage.numerical.mip (0, None) sage: g = DiGraph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True Asking for a minimum (resp., maximum) weight Hamiltonian path:: sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=False)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=False)[0]) 3 - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=True)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=True)[0]) 5 Parameter ``algorithm`` must be either ``'backtrack'`` or ``'MILP'``:: @@ -8444,29 +8486,28 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, The Heawood graph is known to be Hamiltonian:: sage: g = graphs.HeawoodGraph() - sage: tsp = g.traveling_salesman_problem() - sage: tsp + sage: tsp = g.traveling_salesman_problem(); tsp # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The solution to the TSP has to be connected:: - sage: tsp.is_connected() + sage: tsp.is_connected() # needs sage.numerical.mip True It must also be a `2`-regular graph:: - sage: tsp.is_regular(k=2) + sage: tsp.is_regular(k=2) # needs sage.numerical.mip True And obviously it is a subgraph of the Heawood graph:: - sage: tsp.is_subgraph(g, induced=False) + sage: tsp.is_subgraph(g, induced=False) # needs sage.numerical.mip True On the other hand, the Petersen Graph is known not to be Hamiltonian:: sage: g = graphs.PetersenGraph() - sage: tsp = g.traveling_salesman_problem() + sage: tsp = g.traveling_salesman_problem() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -8485,8 +8526,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ....: g.add_edge(u, v) ....: g.set_edge_label(u, v, 2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum( tsp.edge_labels() ) < 2 * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum( tsp.edge_labels() ) < 2 * 10 # needs sage.numerical.mip True If we pick `1/2` instead of `2` as a cost for these new edges, they @@ -8495,17 +8536,20 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in cycle.edges(labels=None, sort=False): ....: g.set_edge_label(u,v,1/2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) == (1/2) * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) == (1/2) * 10 # needs sage.numerical.mip True Search for a minimum and a maximum weight Hamiltonian cycle:: + sage: # needs sage.numerical.mip sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=False) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, + ....: maximize=False) sage: print(sum(tsp.edge_labels())) 4 - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=True) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, + ....: maximize=True) sage: print(sum(tsp.edge_labels())) 6 @@ -8523,9 +8567,10 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in graphs.CycleGraph(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Then for digraphs:: @@ -8539,13 +8584,15 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in digraphs.Circuit(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Simple tests for multiple edges and loops:: + sage: # needs sage.numerical.mip sage: G = DiGraph(multiedges=True, loops=True) sage: G.is_hamiltonian() False @@ -8573,6 +8620,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Graphs on 2 vertices:: + sage: # needs sage.numerical.mip sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() True sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() @@ -8592,8 +8640,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Check that weight 0 edges are handled correctly (see :trac:`16214`):: sage: G = Graph([(0, 1, 1), (0, 2, 0), (0, 3, 1), (1, 2, 1), (1, 3, 0), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) # needs sage.numerical.mip 2 """ from sage.categories.sets_cat import EmptySetError @@ -8953,13 +9001,13 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation= The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The Petersen Graph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -9092,6 +9140,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, The necessary example:: + sage: # needs sage.numerical.mip sage: g = graphs.PetersenGraph() sage: fvs = g.feedback_vertex_set() sage: len(fvs) @@ -9106,6 +9155,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, of its neighbors removed: a feedback vertex set is in this situation a vertex cover:: + sage: # needs sage.numerical.mip sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) sage: cycle.vertex_cover(value_only=True) @@ -9120,7 +9170,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, For a circuit, the minimum feedback arc set is clearly `1`:: sage: circuit = digraphs.Circuit(5) - sage: circuit.feedback_vertex_set(value_only=True) == 1 + sage: circuit.feedback_vertex_set(value_only=True) == 1 # needs sage.numerical.mip True TESTS: @@ -9128,16 +9178,16 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, Comparing with/without constraint generation:: sage: g = digraphs.RandomDirectedGNP(10, .3) - sage: x = g.feedback_vertex_set(value_only=True) - sage: y = g.feedback_vertex_set(value_only=True, - ....: constraint_generation=False) - sage: x == y + sage: x = g.feedback_vertex_set(value_only=True) # needs sage.numerical.mip + sage: y = g.feedback_vertex_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: x == y # needs sage.numerical.mip True Bad algorithm:: sage: g = graphs.PetersenGraph() - sage: g.feedback_vertex_set(constraint_generation=False) + sage: g.feedback_vertex_set(constraint_generation=False) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the only implementation available for undirected graphs is with constraint_generation set to True @@ -9621,19 +9671,19 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler 4-nowhere zero flow:: sage: g = graphs.PetersenGraph() - sage: h = g.nowhere_zero_flow(k=5) - sage: sorted(set(h.edge_labels())) + sage: h = g.nowhere_zero_flow(k=5) # needs sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.numerical.mip [1, 2, 3, 4] - sage: h = g.nowhere_zero_flow(k=3) + sage: h = g.nowhere_zero_flow(k=3) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the problem has no feasible solution The de Bruijn digraph admits a 2-nowhere zero flow:: - sage: g = digraphs.DeBruijn(2, 3) - sage: h = g.nowhere_zero_flow(k=2) - sage: sorted(set(h.edge_labels())) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat + sage: h = g.nowhere_zero_flow(k=2) # needs sage.combinat sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.combinat sage.numerical.mip [-1, 1] TESTS: @@ -9641,7 +9691,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Empty graph:: sage: G = Graph() - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 0 vertices Graph with one vertex:: @@ -9649,11 +9699,12 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler sage: G = Graph([[1], []]) sage: G Graph on 1 vertex - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 1 vertex Loops and multiple edges:: + sage: # needs sage.numerical.mip sage: g = Graph([(0, 0), (0, 0)], loops=True, multiedges=True) sage: g.nowhere_zero_flow().edges(sort=True) [(0, 0, 1), (0, 0, 1)] @@ -9670,26 +9721,26 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Multiple connected components:: sage: g = graphs.CycleGraph(3) * 2 - sage: h = g.nowhere_zero_flow() - sage: h.connected_components_sizes() + sage: h = g.nowhere_zero_flow() # needs sage.numerical.mip + sage: h.connected_components_sizes() # needs sage.numerical.mip [3, 3] (Di)Graphs with bridges:: sage: g = graphs.PathGraph(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution sage: g = digraphs.Path(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution Too small value of ``k``:: - sage: Graph().nowhere_zero_flow(k=1) + sage: Graph().nowhere_zero_flow(k=1) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: parameter 'k' must be at least 2 @@ -10010,22 +10061,22 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, matching in a graph, and to consider the paired vertices as terminals :: sage: g = graphs.PetersenGraph() - sage: matching = [(u,v) for u,v,_ in g.matching()] - sage: h = g.multicommodity_flow(matching) - sage: len(h) + sage: matching = [(u,v) for u,v,_ in g.matching()] # needs networkx + sage: h = g.multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 We could also have considered ``g`` as symmetric and computed the multicommodity flow in this version instead. In this case, however edges can be used in both directions at the same time:: - sage: h = DiGraph(g).multicommodity_flow(matching) - sage: len(h) + sage: h = DiGraph(g).multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 An exception is raised when the problem has no solution :: - sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) + sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) # needs networkx Traceback (most recent call last): ... EmptySetError: the multicommodity flow problem has no solution @@ -10182,7 +10233,7 @@ def _build_flow_graph(self, flow, integer): Isolated zero-cost flow cycles are also removed:: - sage: g = digraphs.DeBruijn(2, 3) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat sage: flow = {('000', '001'): 1, ('010', '101'): 1, ('101', '010'): 1} sage: flow_graph = g._build_flow_graph(flow, True) sage: flow_graph.edges(sort=True) @@ -10258,13 +10309,13 @@ def disjoint_routed_paths(self, pairs, solver=None, verbose=0, top-right corner to the bottom-right corner is easy:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) # needs sage.numerical.mip Though there is obviously no solution to the problem in which each corner is sending information to the opposite one:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the disjoint routed paths do not exist @@ -10384,7 +10435,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, In a complete bipartite graph :: sage: g = graphs.CompleteBipartiteGraph(2, 3) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 2, 1], [0, 3, 1], [0, 4, 1]] TESTS: @@ -10392,9 +10443,9 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, Fix issues reported in :trac:`22990`:: sage: g = digraphs.Path(2) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 1]] - sage: g.vertex_disjoint_paths(1, 0) + sage: g.vertex_disjoint_paths(1, 0) # needs sage.numerical.mip [] """ obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, @@ -10507,14 +10558,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, 4: 0.3063198690713853, 5: 0.1700057609707141, 6: 0.05390084497706962} - sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs scipy + sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs networkx scipy {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs scipy + sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs networkx scipy {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, @@ -10528,14 +10579,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, 4: 0.23749999999999993, 5: 0.17775603392041744, 6: 0.10054631441617742} - sage: G.pagerank() # abs tol 1e-9 + sage: G.pagerank() # abs tol 1e-9 # needs networkx {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(by_weight=True) # abs tol 1e-9 + sage: G.pagerank(by_weight=True) # abs tol 1e-9 # needs networkx {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, @@ -11312,19 +11363,15 @@ def neighbor_iterator(self, vertex, closed=False): for u in self._backend.iterator_nbrs(vertex): yield u - def vertices(self, sort=None, key=None, degree=None, vertex_property=None): + def vertices(self, sort=False, key=None, degree=None, vertex_property=None): r""" Return a list of the vertices. INPUT: - - ``sort`` -- boolean (default: ``None``); if ``True``, vertices are - sorted according to the default ordering - - As of :trac:`22349`, this argument must be explicitly - specified (unless a ``key`` is given); otherwise a warning - is printed and ``sort=True`` is used. The default will - eventually be changed to ``False``. + - ``sort`` -- boolean (default: ``False``); whether to sort vertices + according the ordering specified with parameter ``key``. If ``False`` + (default), vertices are not sorted. - ``key`` -- a function (default: ``None``); a function that takes a vertex as its one argument and returns a value that can be used for @@ -11393,11 +11440,12 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): are first-class objects in Python, we can specify precisely the function from the Sage library that we wish to use as the key:: + sage: # needs sage.libs.flint sage: t = polygen(QQ, 't') sage: K = Graph({5*t: [t^2], t^2: [t^2+2], t^2+2: [4*t^2-6], 4*t^2-6: [5*t]}) - sage: dsc = sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.discriminant - sage: verts = K.vertices(sort=True, key=dsc) - sage: verts + sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + sage: dsc = Polynomial_rational_flint.discriminant + sage: verts = K.vertices(sort=True, key=dsc); verts [t^2 + 2, t^2, 5*t, 4*t^2 - 6] sage: [x.discriminant() for x in verts] [-8, 0, 1, 96] @@ -11411,20 +11459,7 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): Traceback (most recent call last): ... ValueError: sort keyword is False, yet a key function is given - - Deprecation warning for ``sort=None`` (:trac:`22349`):: - - sage: G = graphs.HouseGraph() - sage: G.vertices() - doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future - See https://github.com/sagemath/sage/issues/22349 for details. - [0, 1, 2, 3, 4] """ - if sort is None: - if key is None: - deprecation(22349, "parameter 'sort' will be set to False by default in the future") - sort = True - if (not sort) and key: raise ValueError('sort keyword is False, yet a key function is given') @@ -12350,7 +12385,7 @@ def has_edge(self, u, v=None, label=None): label = None return self._backend.has_edge(u, v, label) - def edges(self, vertices=None, labels=True, sort=None, key=None, + def edges(self, vertices=None, labels=True, sort=False, key=None, ignore_direction=False, sort_vertices=True): r""" Return a :class:`~EdgesView` of edges. @@ -12374,13 +12409,10 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, - ``labels`` -- boolean (default: ``True``); if ``False``, each edge is simply a pair ``(u, v)`` of vertices - - ``sort`` -- boolean (default: ``None``); if ``True``, edges are sorted - according to the default ordering - - As of :trac:`22349`, this argument must be explicitly - specified (unless a ``key`` is given); otherwise a warning - is printed and ``sort=True`` is used. The default will - eventually be changed to ``False``. + - ``sort`` -- boolean (default: ``False``); whether to sort edges + according the ordering specified with parameter ``key``. If ``False`` + (default), edges are not sorted. This is the fastest and less memory + consuming method for iterating over edges. - ``key`` -- a function (default: ``None``); a function that takes an edge (a pair or a triple, according to the ``labels`` keyword) as its @@ -12476,7 +12508,7 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ....: G.set_edge_label(e[0], e[1], chr(ord('A') + e[0] + 5 * e[1])) sage: G.edges(sort=True) [(0, 1, 'F'), (0, 4, 'U'), (1, 2, 'L'), (2, 3, 'R'), (3, 4, 'X')] - sage: G.edges(key=lambda x: x[2]) + sage: G.edges(sort=True, key=lambda x: x[2]) [(0, 1, 'F'), (1, 2, 'L'), (2, 3, 'R'), (0, 4, 'U'), (3, 4, 'X')] We can restrict considered edges to those incident to a given set:: @@ -12527,27 +12559,14 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, sage: G.edge_label(0, 1)[0] += 1 sage: G.edges(sort=True) [(0, 1, [8]), (0, 2, [7])] - - Deprecation warning for ``sort=None`` (:trac:`27408`):: - - sage: G = graphs.HouseGraph() - sage: G.edges(sort=None) - doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future - See https://github.com/sagemath/sage/issues/27408 for details. - [(0, 1, None), (0, 2, None), (1, 3, None), (2, 3, None), (2, 4, None), (3, 4, None)] """ - if sort is None: - if key is None: - deprecation(27408, "parameter 'sort' will be set to False by default in the future") - sort = True - if vertices is not None and vertices in self: vertices = [vertices] return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, ignore_direction=ignore_direction, sort_vertices=sort_vertices) - def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): + def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False, key=None): r""" Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1`` and ``v`` in ``vertices2``. @@ -12565,6 +12584,10 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): - ``sort`` -- boolean (default: ``False``); whether to sort the result + - ``key`` -- a function (default: ``None``); a function that takes an + edge as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) + EXAMPLES:: sage: K = graphs.CompleteBipartiteGraph(9, 3) @@ -12589,6 +12612,23 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): sage: D.edge_boundary([0], labels=False, sort=True) [(0, 1), (0, 2)] + Using the ``key`` argument to order multiple edges of incomparable + types (see :trac:`35903`):: + + sage: G = Graph([(1, 'A', 4), (1, 2, 3)]) + sage: G.edge_boundary([1], sort=True) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '' + sage: G.edge_boundary([1], sort=True, key=str) + [('A', 1, 4), (1, 2, 3)] + sage: G.edge_boundary([1], sort=True, key=lambda e:e[2]) + [(1, 2, 3), ('A', 1, 4)] + sage: G.edge_boundary([1], labels=False, sort=True, key=lambda e:e[2]) + Traceback (most recent call last): + ... + IndexError: tuple index out of range + TESTS:: sage: G = graphs.DiamondGraph() @@ -12598,7 +12638,14 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): [] sage: G.edge_boundary([2], [0]) [(0, 2, None)] + sage: G.edge_boundary([2], [0], sort=False, key=str) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given """ + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + vertices1 = set(v for v in vertices1 if v in self) if self._directed: if vertices2 is not None: @@ -12618,7 +12665,7 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) if e[1] not in vertices1 or e[0] not in vertices1] if sort: - output.sort() + return sorted(output, key=key) return output def edge_iterator(self, vertices=None, labels=True, ignore_direction=False, sort_vertices=True): @@ -13924,7 +13971,7 @@ def subgraph_search_count(self, G, induced=False): sage: T3 = digraphs.TransitiveTournament(3) sage: T5.subgraph_search_count(T3) # needs sage.modules 10 - sage: binomial(5,3) + sage: binomial(5,3) # needs sage.symbolic 10 sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2])) # needs sage.modules True @@ -15275,9 +15322,10 @@ def clustering_average(self, implementation=None): The result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10,20) - sage: impls = ['boost','sparse_copy','dense_copy'] - sage: impls += ['networkx'] # needs networkx + sage: impls = ['boost', 'sparse_copy', 'dense_copy'] + sage: impls += ['networkx'] sage: coeffs = [G.clustering_average(implementation=impl) ....: for impl in impls] sage: max(coeffs) - min(coeffs) # tol abs 1e-12 @@ -15355,7 +15403,7 @@ def clustering_coeff(self, {0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3, 6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0} - sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) # needs networkx {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0, 3: 0.3333333333333333, 4: 0.3333333333333333, 5: 0.3333333333333333, 6: 0.3333333333333333, @@ -15365,8 +15413,8 @@ def clustering_coeff(self, sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2]) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0} - sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], - ....: weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], # needs networkx + ....: weight=True) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0} sage: (graphs.GridGraph([5,5])).clustering_coeff(nodes=[(0,0),(0,1),(2,2)]) @@ -15390,6 +15438,7 @@ def clustering_coeff(self, Check that the result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10, 20) sage: G.relabel(list("abcdefghik")) sage: coeffs = [G.clustering_coeff(implementation=impl) @@ -15774,8 +15823,8 @@ def odd_girth(self, algorithm="bfs", certificate=False): Bipartite graphs have no odd cycle and consequently have infinite odd girth:: - sage: G = graphs.RandomBipartite(6, 6, .5) - sage: G.odd_girth() + sage: G = graphs.RandomBipartite(6, 6, .5) # needs numpy + sage: G.odd_girth() # needs numpy +Infinity sage: G = graphs.Grid2dGraph(3, 4) sage: G.odd_girth() @@ -16182,6 +16231,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, The result does not depend on the algorithm:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) @@ -16208,20 +16258,21 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: m = random.randint(0, n*(n-1)/2) sage: g = digraphs.RandomDirectedGNM(n,m) sage: c1 = g.centrality_closeness(algorithm='BFS') - sage: c2 = g.centrality_closeness(algorithm='NetworkX') + sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') - sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) + sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx True - sage: c = [c1,c2,c3,c4,c5,c6] - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 + sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 # needs networkx ....: for ci, cj in itertools.combinations(c, 2) ) True Weighted graphs:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) @@ -16370,29 +16421,29 @@ def triangles_count(self, algorithm=None): have:: sage: G = graphs.CompleteGraph(15) - sage: G.triangles_count() == binomial(15, 3) + sage: G.triangles_count() == binomial(15, 3) # needs sage.symbolic True The 2-dimensional DeBruijn graph of 2 symbols has 2 directed `C_3`:: - sage: G = digraphs.DeBruijn(2,2) - sage: G.triangles_count() + sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat + sage: G.triangles_count() # needs sage.combinat 2 The directed `n`-cycle is trivially triangle free for `n > 3`:: sage: G = digraphs.Circuit(10) - sage: G.triangles_count() + sage: G.triangles_count() # needs sage.modules 0 TESTS: Comparison of algorithms:: - sage: G = graphs.RandomBarabasiAlbert(50,2) + sage: G = graphs.RandomBarabasiAlbert(50,2) # needs networkx sage: results = [] sage: results.append(G.triangles_count(algorithm='matrix')) - sage: results.append(G.triangles_count(algorithm='iter')) + sage: results.append(G.triangles_count(algorithm='iter')) # needs sage.modules sage: results.append(G.triangles_count(algorithm='sparse_copy')) sage: results.append(G.triangles_count(algorithm='dense_copy')) sage: any(x != results[0] for x in results) @@ -17050,7 +17101,8 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, However, if ``check_weight`` is set to ``False``, unexpected behavior may occur:: - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', weight_function=lambda e:e[2], check_weight=False) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', # needs networkx + ....: weight_function=lambda e:e[2], check_weight=False) Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'dict' @@ -17093,7 +17145,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, Traceback (most recent call last): ... RuntimeError: Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) # needs networkx Traceback (most recent call last): ... ValueError: ('Contradictory paths found:', 'negative weights?') @@ -17500,12 +17552,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that distances are equal regardless of the algorithm used:: @@ -17514,12 +17566,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that weighted distances are equal regardless of the algorithm @@ -17530,12 +17582,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: for v, w in g.edges(labels=False, sort=False): ....: g.add_edge(v, w, random.uniform(1, 10)) sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 + sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 # needs networkx scipy True Checking a random path is valid:: @@ -17562,7 +17614,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='BFS') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') + sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') # needs networkx ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 1, 2: 1}, 1: {1: None, 2: 2}, 2: {2: None}}) sage: g.shortest_path_all_pairs(algorithm='Dijkstra_Boost') @@ -17574,7 +17626,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Cython') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') + sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') # needs scipy ({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) @@ -17846,7 +17898,7 @@ def wiener_index(self, by_weight=False, algorithm=None, 15 sage: G.wiener_index(algorithm='Johnson_Boost') 15 - sage: G.wiener_index(algorithm='Dijkstra_NetworkX') + sage: G.wiener_index(algorithm='Dijkstra_NetworkX') # needs networkx 15 Wiener index of complete (di)graphs:: @@ -19000,6 +19052,7 @@ def tensor_product(self, other): The tensor product of two DeBruijn digraphs of same diameter is a DeBruijn digraph:: + sage: # needs sage.combinat sage: B1 = digraphs.DeBruijn(2, 3) sage: B2 = digraphs.DeBruijn(3, 3) sage: T = B1.tensor_product(B2) @@ -20243,16 +20296,17 @@ def layout_graphviz(self, dim=2, prog='dot', **options): By default, an acyclic layout is computed using ``graphviz``'s ``dot`` layout program. One may specify an alternative layout program:: - sage: g.plot(layout="graphviz", prog="dot") # optional - dot2tex graphviz + sage: # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="dot") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="neato") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="neato") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="twopi") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="twopi") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="fdp") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="fdp") Graphics object consisting of 29 graphics primitives sage: g = graphs.BalancedTree(5,2) # needs networkx - sage: g.plot(layout="graphviz", prog="circo") # optional - dot2tex graphviz, needs networkx + sage: g.plot(layout="graphviz", prog="circo") # needs networkx Graphics object consisting of 62 graphics primitives .. TODO:: @@ -20277,13 +20331,14 @@ def layout_graphviz(self, dim=2, prog='dot', **options): Make sure that :trac:`12364` is fixed:: + sage: # needs sage.combinat sage.modules sage: m = WordMorphism('a->abb,b->ba') sage: w = m.fixed_point('a') sage: prefix = Word(list(w[:100])) sage: pals = prefix.palindromes() sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) sage: H = poset.hasse_diagram() - sage: d = H.layout_graphviz() # optional - dot2tex graphviz + sage: d = H.layout_graphviz() # optional - dot2tex graphviz """ assert_have_dot2tex() assert dim == 2, "3D graphviz layout not implemented" @@ -20750,6 +20805,7 @@ def plot(self, **options): :: + sage: # needs sage.plot sage: from sage.plot.colors import rainbow sage: C = graphs.CubeGraph(5) sage: R = rainbow(5) @@ -20758,7 +20814,7 @@ def plot(self, **options): ....: for i in range(5): ....: if u[i] != v[i]: ....: edge_colors[R[i]].append((u, v, l)) - sage: C.plot(vertex_labels=False, vertex_size=0, # needs sage.plot + sage: C.plot(vertex_labels=False, vertex_size=0, ....: edge_colors=edge_colors).show() :: @@ -20887,6 +20943,7 @@ def plot(self, **options): :: + sage: # needs sage.modular sage: S = SupersingularModule(389) sage: H = S.hecke_matrix(2) sage: D = DiGraph(H, sparse=True) @@ -21074,9 +21131,9 @@ def plot3d(self, bgcolor=(1, 1, 1), :: sage: P = graphs.PetersenGraph().to_directed() - sage: from sage.plot.colors import rainbow - sage: R = rainbow(P.size(), 'rgbtuple') - sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} + sage: from sage.plot.colors import rainbow # needs sage.plot + sage: R = rainbow(P.size(), 'rgbtuple') # needs sage.plot + sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} # needs sage.plot sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time, needs sage.plot @@ -21816,12 +21873,12 @@ def graphviz_string(self, **options): Check that :trac:`25121` is fixed:: sage: G = Graph([(0, 1)]) - sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) + sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) # needs sage.plot 'graph {\n node_0 [label="0"];\n node_1 [label="1"];\n\n node_0 -- node_1 [color = "#4080ff"];\n}' sage: G = Graph([(0, 1)]) - sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) - sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz + sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) # needs sage.plot + sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz, needs sage.plot \begin{tikzpicture}[>=latex,line join=bevel,] ... \definecolor{strokecolor}{rgb}{0.25,0.5,1.0}; @@ -22069,26 +22126,26 @@ def spectrum(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.spectrum() # needs sage.modules + sage: P.spectrum() # needs sage.modules sage.rings.number_field [3, 1, 1, 1, 1, 1, -2, -2, -2, -2] - sage: P.spectrum(laplacian=True) # needs sage.modules + sage: P.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field [5, 5, 5, 5, 2, 2, 2, 2, 2, 0] sage: D = P.to_directed() sage: D.delete_edge(7, 9) - sage: D.spectrum() # needs sage.modules + sage: D.spectrum() # needs sage.modules sage.rings.number_field [2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2] :: sage: C = graphs.CycleGraph(8) - sage: C.spectrum() # needs sage.modules + sage: C.spectrum() # needs sage.modules sage.rings.number_field [2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623..., -2] A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.spectrum() # needs sage.modules + sage: T.spectrum() # needs sage.modules sage.rings.number_field [1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I] TESTS: @@ -22101,11 +22158,12 @@ def spectrum(self, laplacian=False): test both the Laplacian construction and the computation of eigenvalues. :: + sage: # needs sage.modules sage.rings.number_field sage: H = graphs.HoffmanSingletonGraph() - sage: evals = H.spectrum() # needs sage.modules - sage: lap = [7 - x for x in evals] # needs sage.modules - sage: lap.sort(reverse=True) # needs sage.modules - sage: lap == H.spectrum(laplacian=True) # needs sage.modules + sage: evals = H.spectrum() + sage: lap = [7 - x for x in evals] + sage: lap.sort(reverse=True) + sage: lap == H.spectrum(laplacian=True) True """ # Ideally the spectrum should return something like a Factorization object @@ -22191,7 +22249,7 @@ def eigenvectors(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenvectors() # needs sage.modules + sage: P.eigenvectors() # needs sage.modules sage.rings.number_field [(3, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (-2, [ @@ -22211,7 +22269,7 @@ def eigenvectors(self, laplacian=False): graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenvectors(laplacian=True) # needs sage.modules + sage: P.eigenvectors(laplacian=True) # needs sage.modules sage.rings.number_field [(0, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (5, [ @@ -22230,7 +22288,7 @@ def eigenvectors(self, laplacian=False): :: sage: C = graphs.CycleGraph(8) - sage: C.eigenvectors() # needs sage.modules + sage: C.eigenvectors() # needs sage.modules sage.rings.number_field [(2, [ (1, 1, 1, 1, 1, 1, 1, 1) @@ -22260,7 +22318,7 @@ def eigenvectors(self, laplacian=False): graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0:[1], 1:[2], 2:[0]}) - sage: T.eigenvectors() # needs sage.modules + sage: T.eigenvectors() # needs sage.modules sage.rings.number_field [(1, [ (1, 1, 1) @@ -22301,7 +22359,7 @@ def eigenspaces(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenspaces() # needs sage.modules + sage: P.eigenspaces() # needs sage.modules sage.rings.number_field [ (3, Vector space of degree 10 and dimension 1 over Rational Field User basis matrix: @@ -22325,7 +22383,7 @@ def eigenspaces(self, laplacian=False): graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenspaces(laplacian=True) # needs sage.modules + sage: P.eigenspaces(laplacian=True) # needs sage.modules sage.rings.number_field [ (0, Vector space of degree 10 and dimension 1 over Rational Field User basis matrix: @@ -22350,7 +22408,7 @@ def eigenspaces(self, laplacian=False): corresponding eigenspace:: sage: C = graphs.CycleGraph(8) - sage: C.eigenspaces() # needs sage.modules + sage: C.eigenspaces() # needs sage.modules sage.rings.number_field [ (2, Vector space of degree 8 and dimension 1 over Rational Field User basis matrix: @@ -22373,7 +22431,7 @@ def eigenspaces(self, laplacian=False): we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.eigenspaces() # needs sage.modules + sage: T.eigenspaces() # needs sage.modules sage.rings.number_field [ (1, Vector space of degree 3 and dimension 1 over Rational Field User basis matrix: @@ -22962,6 +23020,7 @@ def automorphism_group(self, partition=None, verbosity=0, Graphs:: + sage: # needs sage.groups sage: graphs_query = GraphQuery(display_cols=['graph6'],num_vertices=4) sage: L = graphs_query.get_graphs_list() sage: graphs_list.show_graphs(L) # needs sage.plot @@ -22989,6 +23048,7 @@ def automorphism_group(self, partition=None, verbosity=0, :: + sage: # needs sage.groups sage: D = graphs.DodecahedralGraph() sage: G = D.automorphism_group() sage: A5 = AlternatingGroup(5) @@ -23003,34 +23063,35 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) - sage: G.automorphism_group() + sage: G.automorphism_group() # needs sage.groups Permutation Group with generators [('a','b')] Digraphs:: sage: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } ) - sage: D.automorphism_group() + sage: D.automorphism_group() # needs sage.groups Permutation Group with generators [(0,1,2,3,4)] Edge labeled graphs:: sage: G = Graph(sparse=True) sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] ) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(1,4)(2,3)] sage: G.automorphism_group(edge_labels=True, algorithm="bliss") # optional - bliss Permutation Group with generators [(1,4)(2,3)] - sage: G.automorphism_group(edge_labels=True, algorithm="sage") + sage: G.automorphism_group(edge_labels=True, algorithm="sage") # needs sage.groups Permutation Group with generators [(1,4)(2,3)] :: sage: G = Graph({0 : {1 : 7}}) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(0,1)] + sage: # needs sage.groups sage: foo = Graph(sparse=True) sage: bar = Graph(sparse=True) sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)]) @@ -23045,13 +23106,14 @@ def automorphism_group(self, partition=None, verbosity=0, You can also ask for just the order of the group:: sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, order=True) + sage: G.automorphism_group(return_group=False, order=True) # needs sage.groups 120 Or, just the orbits (note that each graph here is vertex transitive) :: + sage: # needs sage.groups sage: G = graphs.PetersenGraph() sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] @@ -23069,9 +23131,9 @@ def automorphism_group(self, partition=None, verbosity=0, sage: # optional - bliss sage: G = graphs.HallJankoGraph() - sage: A1 = G.automorphism_group() + sage: A1 = G.automorphism_group() # needs sage.groups sage: A2 = G.automorphism_group(algorithm='bliss') - sage: A1.is_isomorphic(A2) + sage: A1.is_isomorphic(A2) # needs sage.groups True TESTS: @@ -23080,13 +23142,14 @@ def automorphism_group(self, partition=None, verbosity=0, sage: g=graphs.CubeGraph(3) sage: g.relabel() - sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') + sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') # needs sage.groups Traceback (most recent call last): ... KeyError: ... Labeled automorphism group:: + sage: # needs sage.combinat sage.groups sage: d = digraphs.DeBruijn(3,2) sage: A = d.automorphism_group(algorithm='sage') sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')", @@ -23103,24 +23166,24 @@ def automorphism_group(self, partition=None, verbosity=0, The labeling is correct:: sage: g = graphs.PetersenGraph() - sage: ag = g.automorphism_group() - sage: all(len(ag.orbit(e, action="OnPairs")) == 30 + sage: ag = g.automorphism_group() # needs sage.groups + sage: all(len(ag.orbit(e, action="OnPairs")) == 30 # needs sage.groups ....: for e in g.edge_iterator(labels=False)) True Empty group, correct domain:: - sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() - sage: ag + sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() # needs sage.groups + sage: ag # needs sage.groups Permutation Group with generators [()] - sage: sorted(ag.domain()) + sage: sorted(ag.domain()) # needs sage.groups ['a', 'b'] We can check that the subgroups are labelled correctly (:trac:`15656`):: sage: G1 = Graph(':H`ECw@HGXGAGUG`e') - sage: G = G1.automorphism_group() + sage: G = G1.automorphism_group() # needs sage.groups sage: G.subgroups() [Subgroup generated by [()] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]), Subgroup generated by [(0,7)(1,4)(2,3)(6,8)] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)])] @@ -23128,6 +23191,7 @@ def automorphism_group(self, partition=None, verbosity=0, We check that the representations of the groups returned with ``'sage'`` and ``'bliss'`` are the same (:trac:`27571`):: + sage: # needs sage.groups sage.libs.pari sage: G = graphs.PaleyGraph(9) sage: a1 = G.automorphism_group(algorithm='sage') sage: V = sorted(G, reverse=True) @@ -23139,8 +23203,9 @@ def automorphism_group(self, partition=None, verbosity=0, sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss sage: str(a1) == str(b1) # optional - bliss True - sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss - sage: str(a2) == str(b2) # optional - bliss + sage: b2 = G.automorphism_group(algorithm='bliss', # optional - bliss + ....: partition=[V]) + sage: str(a2) == str(b2) # optional - bliss True """ from sage.features.bliss import Bliss @@ -23387,19 +23452,19 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True The Petergraph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False TESTS:: sage: g = graphs.ChvatalGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True :trac:`16210`:: @@ -23407,7 +23472,7 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, sage: g = graphs.CycleGraph(10) sage: g.allow_loops(True) sage: g.add_edge(0,0) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ from sage.categories.sets_cat import EmptySetError @@ -23904,7 +23969,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: algos = ['sage'] sage: algos.append('bliss') # optional - bliss sage: S = Set([0,1,2]) - sage: for (algo, edges) in product(algos, edges_list): + sage: for (algo, edges) in product(algos, edges_list): # needs sage.combinat ....: L = cartesian_product([S] * len(edges)) ....: O = OrderedSetPartitions([0,1,2,3]) ....: P = Permutations([0,1,2,3]) @@ -24058,11 +24123,12 @@ def is_cayley(self, return_group=False, mapping=False, Graphs with loops and multiedges will have identity and repeated elements, respectively, among the generators:: + sage: # needs sage.rings.finite_rings sage: g = Graph(graphs.PaleyGraph(9), loops=True, multiedges=True) sage: g.add_edges([(u, u) for u in g]) sage: g.add_edges([(u, u+1) for u in g]) - sage: _, S = g.is_cayley(generators=True) - sage: S # random + sage: _, S = g.is_cayley(generators=True) # needs sage.groups + sage: S # random # needs sage.groups [(), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), @@ -24075,24 +24141,27 @@ def is_cayley(self, return_group=False, mapping=False, Cayley graphs can be reconstructed from the group and generating set:: - sage: g = graphs.PaleyGraph(9) - sage: _, G, S = g.is_cayley(return_group=True, generators=True) - sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) + sage: g = graphs.PaleyGraph(9) # needs sage.rings.finite_rings + sage: _, G, S = g.is_cayley(return_group=True, generators=True) # needs sage.groups sage.rings.finite_rings + sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) # needs sage.groups sage.rings.finite_rings True A disconnected graphs may also be a Cayley graph:: + sage: # needs sage.rings.finite_rings sage: g = graphs.PaleyGraph(9) sage: h = g.disjoint_union(g) sage: h = h.disjoint_union(h) sage: h = h.disjoint_union(g) - sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, generators=True, allow_disconnected=True) - sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) for v in h) + sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, # needs sage.groups + ....: generators=True, allow_disconnected=True) + sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) # needs sage.groups + ....: for v in h) True The method also works efficiently with dense simple graphs:: - sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() + sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() # needs sage.groups True TESTS:: @@ -24198,8 +24267,8 @@ def is_self_complementary(self): Every Paley graph is self-complementary:: - sage: G = graphs.PaleyGraph(9) - sage: G.is_self_complementary() + sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari + sage: G.is_self_complementary() # needs sage.libs.pari True TESTS: @@ -24327,7 +24396,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle. :: sage: G = graphs.CycleGraph(4) - sage: G.katz_matrix(1/20) # needs sage.modules + sage: G.katz_matrix(1/20) # needs sage.modules sage.rings.number_field [1/198 5/99 1/198 5/99] [ 5/99 1/198 5/99 1/198] [1/198 5/99 1/198 5/99] @@ -24336,7 +24405,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle with all entries other than those which correspond to non-edges zeroed out. :: - sage: G.katz_matrix(1/20, True) # needs sage.modules + sage: G.katz_matrix(1/20, True) # needs sage.modules sage.rings.number_field [ 0 0 1/198 0] [ 0 0 0 1/198] [1/198 0 0 0] @@ -24348,7 +24417,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix in a fan on 6 vertices. :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.katz_matrix(1/10) # needs sage.modules + sage: H.katz_matrix(1/10) # needs sage.modules sage.rings.number_field [ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] @@ -24364,7 +24433,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): TESTS:: - sage: # needs sage.modules + sage: # needs sage.modules sage.rings.number_field sage: (graphs.CompleteGraph(4)).katz_matrix(1/4) [3/5 4/5 4/5 4/5] [4/5 3/5 4/5 4/5] @@ -24683,7 +24752,7 @@ def symmetric_edge_polytope(self, backend=None): ....: break ....: else: ....: polys.append(P) - sage: len(polys) + sage: len(polys) # needs sage.geometry.polyhedron 25 A non-trivial example of two graphs with isomorphic SEPs:: diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 45867176382..0e05f3a4ec9 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -400,7 +400,7 @@ cdef inline double sqrt_approx(double x, double y, double xx, double yy): ....: y = abs(y) ....: return max(x,y) + min(x,y)**2/(2*max(x,y)) - sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # optional - sage.plot + sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # needs sage.plot Graphics object consisting of 2 graphics primitives """ if xx < yy: @@ -651,7 +651,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: @@ -661,11 +661,11 @@ cdef class SubgraphSearch: computations with it:: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch - sage: SubgraphSearch(Graph(5), Graph(1)) # optional - sage.modules + sage: SubgraphSearch(Graph(5), Graph(1)) # needs sage.modules Traceback (most recent call last): ... ValueError: searched graph should have at least 2 vertices - sage: SubgraphSearch(Graph(5), Graph(2)) # optional - sage.modules + sage: SubgraphSearch(Graph(5), Graph(2)) # needs sage.modules """ if H.order() <= 1: @@ -691,8 +691,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: for p in S: # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: for p in S: # needs sage.modules ....: print(p) [0, 1, 2] [1, 2, 3] @@ -722,8 +722,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.cardinality() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.cardinality() # needs sage.modules 6 Check that the method is working even when vertices or edges are of @@ -734,8 +734,8 @@ cdef class SubgraphSearch: sage: G.add_cycle(['A', 1, 2, 3, ('a', 1)]) sage: H = Graph() sage: H.add_path("xyz") - sage: S = SubgraphSearch(G, H) # optional - sage.modules - sage: S.cardinality() # optional - sage.modules + sage: S = SubgraphSearch(G, H) # needs sage.modules + sage: S.cardinality() # needs sage.modules 10 """ if self.nh > self.ng: @@ -769,18 +769,18 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] - sage: S._initialization() # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S._initialization() # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] TESTS: Check that :trac:`21828` is fixed:: - sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # optional - sage.modules + sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # needs sage.modules True """ cdef int i @@ -815,7 +815,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices """ self.mem = MemoryAllocator() @@ -904,8 +904,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] """ if not self.ng: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index e2c86f69d40..fe02be46c77 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -106,16 +106,17 @@ 5: [7, 8], 6: [8,9], 7: [9]} sage: G = Graph(d); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - A NetworkX graph: :: - sage: import networkx # optional - networkx - sage: K = networkx.complete_bipartite_graph(12,7) # optional - networkx - sage: G = Graph(K) # optional - networkx - sage: G.degree() # optional - networkx + sage: # needs networkx + sage: import networkx + sage: K = networkx.complete_bipartite_graph(12,7) + sage: G = Graph(K) + sage: G.degree() [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12] - graph6 or sparse6 format: @@ -125,7 +126,7 @@ sage: s = ':I`AKGsaOs`cI]Gb~' sage: G = Graph(s, sparse=True); G Looped multi-graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot Note that the ``\`` character is an escape character in Python, and also a character used by graph6 strings: @@ -142,17 +143,18 @@ :: sage: G = Graph('Ihe\\n@GUA') - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - adjacency matrix: In an adjacency matrix, each column and each row represent a vertex. If a 1 shows up in row `i`, column `j`, there is an edge `(i,j)`. :: - sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \ - (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \ - (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \ - (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) + sage: # needs sage.modules + sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0), + ....: (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0), + ....: (1,0,0,1,0,0,0,0,0,1), (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1), + ....: (0,0,1,0,0,1,0,0,0,1), (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) sage: M [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] @@ -166,13 +168,14 @@ [0 0 0 0 1 0 1 1 0 0] sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an edge. :: + sage: # needs sage.modules sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), ....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0), ....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0), @@ -196,8 +199,8 @@ [ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1] sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot - sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix") + sage: G.plot().show() # or G.show() # needs sage.plot + sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix") Traceback (most recent call last): ... ValueError: there must be two nonzero entries (-1 & 1) per column @@ -254,10 +257,10 @@ :: sage: G = graphs.PetersenGraph() - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot sage: G.degree_histogram() [0, 0, 0, 10] - sage: G.adjacency_matrix() + sage: G.adjacency_matrix() # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -272,7 +275,7 @@ :: sage: S = G.subgraph([0,1,2,3]) - sage: S.plot().show() # or S.show() # optional - sage.plot + sage: S.plot().show() # or S.show() # needs sage.plot sage: S.density() 1/2 @@ -280,7 +283,7 @@ sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5) sage: L = G.get_graphs_list() - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot .. _Graph:labels: @@ -295,8 +298,8 @@ Note that vertex labels themselves cannot be mutable items:: - sage: M = Matrix( [[0,0],[0,0]] ) - sage: G = Graph({ 0 : { M : None } }) + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: G = Graph({ 0 : { M : None } }) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -349,7 +352,7 @@ Show each graph as you iterate through the results:: - sage: for g in Q: # optional - sage.plot + sage: for g in Q: # needs sage.plot ....: show(g) Visualization @@ -359,11 +362,11 @@ view the graph in two dimensions via matplotlib with ``show()``. :: sage: G = graphs.RandomGNP(15,.3) - sage: G.show() # optional - sage.plot + sage: G.show() # needs sage.plot And you can view it in three dimensions via jmol with ``show3d()``. :: - sage: G.show3d() # optional - sage.plot + sage: G.show3d() # needs sage.plot Or it can be rendered with `\LaTeX`. This requires the right additions to a standard `\mbox{\rm\TeX}` installation. Then standard Sage commands, such as @@ -429,8 +432,6 @@ lazy_import('sage.graphs.mcqd', ['mcqd'], feature=PythonModule('sage.graphs.mcqd', spkg='mcqd')) -from sage.misc.decorators import rename_keyword - class Graph(GenericGraph): r""" @@ -608,8 +609,8 @@ class Graph(GenericGraph): 'out' is the label for the edge on 2 and 5. Labels can be used as weights, if all the labels share some common parent.:: - sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # optional - sage.groups - sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # optional - sage.groups + sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # needs sage.groups + sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # needs sage.groups Graph on 4 vertices #. A dictionary of lists:: @@ -623,10 +624,10 @@ class Graph(GenericGraph): Construct the Paley graph over GF(13).:: - sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) - sage: g.vertices(sort=True) + sage: g = Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) # needs sage.rings.finite_rings + sage: g.vertices(sort=True) # needs sage.rings.finite_rings [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() + sage: g.adjacency_matrix() # needs sage.modules sage.rings.finite_rings [0 1 0 1 1 0 0 0 0 1 1 0 1] [1 0 1 0 1 1 0 0 0 0 1 1 0] [0 1 0 1 0 1 1 0 0 0 0 1 1] @@ -649,7 +650,7 @@ class Graph(GenericGraph): loops=False) sage: line_graph.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: line_graph.adjacency_matrix() + sage: line_graph.adjacency_matrix() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -697,7 +698,7 @@ class Graph(GenericGraph): - an adjacency matrix:: - sage: M = graphs.PetersenGraph().am(); M + sage: M = graphs.PetersenGraph().am(); M # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -708,82 +709,85 @@ class Graph(GenericGraph): [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 10 vertices :: - sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True) + sage: Graph(matrix([[1,2], [2,4]]), loops=True, sparse=True) # needs sage.modules Looped multi-graph on 2 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1/2], [-1,-1/2,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1/2] [ -1 -1/2 0] - sage: G = Graph(M,sparse=True); G + sage: G = Graph(M, sparse=True); G # needs sage.modules Graph on 3 vertices - sage: G.weighted() + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules + ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] [ 0 1 -1 0 0] [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 6 vertices - sage: Graph(Matrix([[1],[1],[1]])) + sage: Graph(Matrix([[1],[1],[1]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(Matrix([[1],[1],[0]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(Matrix([[1],[1],[0]])) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1], [-1,-1,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1] [-1 -1 0] - sage: Graph(M,sparse=True) + sage: Graph(M, sparse=True) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,1], [1,0,1], [-1,-1,0]]); M # needs sage.modules [ 0 1 1] [ 1 0 1] [-1 -1 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Traceback (most recent call last): ... ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1] in column 2 Check that :trac:`9714` is fixed:: + sage: # needs sage.modules sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) sage: GA = Graph(MA, format='adjacency_matrix') - sage: MI = GA.incidence_matrix(oriented=False) - sage: MI + sage: MI = GA.incidence_matrix(oriented=False); MI [2 1 1 0 0 0] [0 1 1 2 2 0] [0 0 0 0 0 2] sage: Graph(MI).edges(sort=True, labels=None) [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)] - sage: M = Matrix([[1], [-1]]); M + sage: M = Matrix([[1], [-1]]); M # needs sage.modules [ 1] [-1] - sage: Graph(M).edges(sort=True) + sage: Graph(M).edges(sort=True) # needs sage.modules [(0, 1, None)] #. A Seidel adjacency matrix:: - sage: from sage.combinat.matrices.hadamard_matrix import \ - ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd - sage: m=rshcd(16,1)- matrix.identity(16) - sage: Graph(m,format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) + sage: from sage.combinat.matrices.hadamard_matrix import ( # needs sage.modules + ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd) + sage: m = rshcd(16,1) - matrix.identity(16) # needs sage.modules + sage: Graph(m, # needs sage.modules + ....: format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) (16, 6, 2, 2) #. List of edges, or labelled edges:: @@ -801,16 +805,16 @@ class Graph(GenericGraph): #. A NetworkX MultiGraph:: - sage: import networkx # optional - networkx - sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: Graph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # needs networkx + sage: Graph(g) # needs networkx Multi-graph on 5 vertices #. A NetworkX graph:: - sage: import networkx # optional - networkx - sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph Graph (see also @@ -824,11 +828,12 @@ class Graph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) + sage: Graph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) + sage: Graph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -883,6 +888,7 @@ class Graph(GenericGraph): ... ValueError: An *undirected* igraph graph was expected. To build an directed graph, call the DiGraph constructor. + sage: # needs sage.modules sage: m = matrix([[0, -1], [-1, 0]]) sage: Graph(m, format="seidel_adjacency_matrix") Graph on 2 vertices @@ -892,8 +898,8 @@ class Graph(GenericGraph): ... ValueError: the adjacency matrix of a Seidel graph must be symmetric - sage: m[0,1] = -1; m[1,1] = 1 - sage: Graph(m, format="seidel_adjacency_matrix") + sage: m[0,1] = -1; m[1,1] = 1 # needs sage.modules + sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules Traceback (most recent call last): ... ValueError: the adjacency matrix of a Seidel graph must have 0s on the main diagonal @@ -907,7 +913,7 @@ class Graph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') + sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') # needs networkx Graph on 0 vertices """ _directed = False @@ -923,12 +929,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: G = Graph() sage: loads(dumps(G)) == G True - sage: a = matrix(2,2,[1,0,0,1]) - sage: Graph(a).adjacency_matrix() == a + sage: a = matrix(2,2,[1,0,0,1]) # needs sage.modules + sage: Graph(a).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[2,0,0,1]) - sage: Graph(a,sparse=True).adjacency_matrix() == a + sage: a = matrix(2,2,[2,0,0,1]) # needs sage.modules + sage: Graph(a,sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the graph is built from another graph :: @@ -973,7 +979,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Verify that the int format works as expected (:trac:`12557`):: - sage: Graph(2).adjacency_matrix() + sage: Graph(2).adjacency_matrix() # needs sage.modules [0 0] [0 0] sage: Graph(3) == Graph(3,format='int') @@ -982,10 +988,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Problem with weighted adjacency matrix (:trac:`13919`):: sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{6:7}} - sage: grafo3 = Graph(B,weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() - sage: grafo4 = Graph(matad,format = "adjacency_matrix", weighted=True) - sage: grafo4.shortest_path(0,6,by_weight=True) + sage: grafo3 = Graph(B, weighted=True) + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = Graph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Graphs returned when setting ``immutable=False`` are mutable:: @@ -1003,15 +1009,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Check error messages for graphs built from incidence matrices (see :trac:`18440`):: - sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) + sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: column 1 of the (oriented) incidence matrix contains only one nonzero value - sage: Graph(matrix([[1,1],[1,1],[1,0]])) + ValueError: column 1 of the (oriented) incidence matrix + contains only one nonzero value + sage: Graph(matrix([[1,1],[1,1],[1,0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(matrix([[3,1,1],[0,1,1]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(matrix([[3,1,1],[0,1,1]])) # needs sage.modules Traceback (most recent call last): ... ValueError: each column of a non-oriented incidence matrix must sum to 2, but column 0 does not @@ -1514,7 +1522,7 @@ def is_tree(self, certificate=False, output='vertex'): sage: G.is_tree(certificate=True) (False, [1, 2]) sage: G.is_tree(certificate=True, output='edge') - (False, [(1, 2, 'a'), (2, 1, 'b')]) + (False, [(1, 2, 'b'), (2, 1, 'a')]) TESTS: @@ -1542,6 +1550,16 @@ def is_tree(self, certificate=False, output='vertex'): (False, [0]) sage: G.is_tree(certificate=True, output='edge') (False, [(0, 0, None)]) + + Case of edges with incomparable types (see :trac:`35903`):: + + sage: G = Graph(multiedges=True) + sage: G.add_cycle(['A', 1, 2, 3]) + sage: G.add_cycle(['A', 1, 2, 3]) + sage: G.is_tree(certificate=True, output='vertex') + (False, ['A', 1]) + sage: G.is_tree(certificate=True, output='edge') + (False, [('A', 1, None), (1, 'A', None)]) """ if output not in ['vertex', 'edge']: raise ValueError('output must be either vertex or edge') @@ -1559,12 +1577,18 @@ def is_tree(self, certificate=False, output='vertex'): return False, L[:1] if self.has_multiple_edges(): + multiple_edges = self.multiple_edges(sort=False) if output == 'vertex': - return (False, list(self.multiple_edges(sort=True)[0][:2])) - edge1, edge2 = self.multiple_edges(sort=True)[:2] - if edge1[0] != edge2[0]: - return (False, [edge1, edge2]) - return (False, [edge1, (edge2[1], edge2[0], edge2[2])]) + return (False, list(multiple_edges[0][:2])) + # Search for 2 edges between u and v. + # We do this way to handle the case of edges with incomparable + # types + u1, v1, w1 = multiple_edges[0] + for u2, v2, w2 in multiple_edges[1:]: + if u1 == u2 and v1 == v2: + return (False, [(u1, v1, w1), (v2, u2, w2)]) + elif u1 == v2 and v1 == u2: + return (False, [(u1, v1, w1), (u2, v2, w2)]) if output == 'edge': if self.allows_multiple_edges(): @@ -1695,7 +1719,7 @@ def is_cactus(self): Test a graph that is not outerplanar, see :trac:`24480`:: - sage: graphs.Balaban10Cage().is_cactus() + sage: graphs.Balaban10Cage().is_cactus() # needs networkx False """ self._scream_if_not_simple() @@ -1816,7 +1840,7 @@ def is_cograph(self): sage: graphs.HouseXGraph().is_cograph() True - sage: graphs.HouseGraph().is_cograph() + sage: graphs.HouseGraph().is_cograph() # needs sage.modules False .. TODO:: @@ -1827,9 +1851,9 @@ def is_cograph(self): TESTS:: - sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] + sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] # needs sage.modules [True, True, True, True, False, False] - sage: graphs.CycleGraph(5).is_cograph() # Self-complemented + sage: graphs.CycleGraph(5).is_cograph() # Self-complemented # needs sage.modules False """ # A cograph has no 4-vertex path as an induced subgraph. @@ -2136,7 +2160,7 @@ def is_overfull(self): sage: g = graphs.ClawGraph() sage: g Claw graph: Graph on 4 vertices - sage: edge_coloring(g, value_only=True) + sage: edge_coloring(g, value_only=True) # needs sage.numerical_mip 3 sage: g.is_overfull() False @@ -2191,7 +2215,7 @@ def is_overfull(self): sage: g.is_overfull() False sage: from sage.graphs.graph_coloring import edge_coloring - sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) + sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) # needs sage.numerical_mip True """ # # A possible optimized version. But the gain in speed is very little. @@ -2226,25 +2250,25 @@ def is_even_hole_free(self, certificate=False): Is the Petersen Graph even-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules False As any chordal graph is hole-free, interval graphs behave the same way:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules True It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:: - sage: g = graphs.RandomBipartite(10, 10, .5) - sage: g.is_even_hole_free() and not g.is_forest() + sage: g = graphs.RandomBipartite(10, 10, .5) # needs numpy + sage: g.is_even_hole_free() and not g.is_forest() # needs numpy sage.modules False We can check the certificate returned is indeed an even cycle:: - sage: if not g.is_forest(): + sage: if not g.is_forest(): # needs numpy sage.modules ....: cycle = g.is_even_hole_free(certificate=True) ....: if cycle.order() % 2 == 1: ....: print("Error !") @@ -2259,17 +2283,18 @@ def is_even_hole_free(self, certificate=False): Bug reported in :trac:`9925`, and fixed by :trac:`9420`:: - sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', loops=False, multiedges=False) - sage: g.is_even_hole_free() + sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', + ....: loops=False, multiedges=False) + sage: g.is_even_hole_free() # needs sage.modules False - sage: g.is_even_hole_free(certificate=True) + sage: g.is_even_hole_free(certificate=True) # needs sage.modules Subgraph of (): Graph on 4 vertices Making sure there are no other counter-examples around :: sage: t = lambda x: (Graph(x).is_forest() or ....: isinstance(Graph(x).is_even_hole_free(certificate=True), Graph)) - sage: all( t(graphs.RandomBipartite(10, 10, .5)) for i in range(100) ) + sage: all(t(graphs.RandomBipartite(10, 10, .5)) for i in range(100)) # needs numpy sage.modules True """ girth = self.girth() @@ -2326,7 +2351,7 @@ def is_odd_hole_free(self, certificate=False): Is the Petersen Graph odd-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules False Which was to be expected, as its girth is 5 :: @@ -2336,14 +2361,14 @@ def is_odd_hole_free(self, certificate=False): We can check the certificate returned is indeed a 5-cycle:: - sage: cycle = g.is_odd_hole_free(certificate=True) - sage: cycle.is_isomorphic(graphs.CycleGraph(5)) + sage: cycle = g.is_odd_hole_free(certificate=True) # needs sage.modules + sage: cycle.is_isomorphic(graphs.CycleGraph(5)) # needs sage.modules True As any chordal graph is hole-free, no interval graph has an odd hole:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules True """ girth = self.odd_girth() @@ -2409,7 +2434,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): or a complete Bipartite Graph:: sage: G = graphs.CompleteBipartiteGraph(5,6) - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules True sage: G.is_triangle_free(algorithm='bitset') True @@ -2419,7 +2444,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): a tripartite graph, though, contains many triangles:: sage: G = (3 * graphs.CompleteGraph(5)).complement() - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules False sage: G.is_triangle_free(algorithm='bitset') False @@ -2542,8 +2567,11 @@ def is_split(self): graph if and only if does not contain the 4-cycle, 5-cycle or `2K_2` as an induced subgraph. Hence for the above graph we have:: - sage: forbidden_subgraphs = [graphs.CycleGraph(4), graphs.CycleGraph(5), 2 * graphs.CompleteGraph(2)] - sage: sum(g.subgraph_search_count(H,induced=True) for H in forbidden_subgraphs) + sage: forbidden_subgraphs = [graphs.CycleGraph(4), + ....: graphs.CycleGraph(5), + ....: 2 * graphs.CompleteGraph(2)] + sage: sum(g.subgraph_search_count(H, induced=True) # needs sage.modules + ....: for H in forbidden_subgraphs) 0 """ self._scream_if_not_simple() @@ -2593,45 +2621,45 @@ def is_perfect(self, certificate=False): A Bipartite Graph is always perfect :: - sage: g = graphs.RandomBipartite(8,4,.5) - sage: g.is_perfect() + sage: g = graphs.RandomBipartite(8,4,.5) # needs numpy + sage: g.is_perfect() # needs numpy sage.modules True So is the line graph of a bipartite graph:: - sage: g = graphs.RandomBipartite(4,3,0.7) - sage: g.line_graph().is_perfect() # long time + sage: g = graphs.RandomBipartite(4,3,0.7) # needs numpy + sage: g.line_graph().is_perfect() # long time # needs numpy sage.modules True As well as the Cartesian product of two complete graphs:: sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3)) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True Interval Graphs, which are chordal graphs, too :: sage: g = graphs.RandomIntervalGraph(7) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:: sage: g = graphs.PetersenGraph() - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False We can obtain an induced 5-cycle as a certificate:: - sage: g.is_perfect(certificate=True) + sage: g.is_perfect(certificate=True) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: Check that :trac:`13546` has been fixed:: - sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() + sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() # needs sage.modules False sage: g = Graph({0: [2, 3, 4, 5], ....: 1: [3, 4, 5, 6], @@ -2640,12 +2668,12 @@ def is_perfect(self, certificate=False): ....: 4: [0, 1, 2, 6], ....: 5: [0, 1, 2, 3], ....: 6: [1, 2, 3, 4]}) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False TESTS:: - sage: Graph(':Ab').is_perfect() + sage: Graph(':Ab').is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2654,7 +2682,7 @@ def is_perfect(self, certificate=False): sage: g.add_edge(0,0) sage: g.edges(sort=True) [(0, 0, None)] - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2701,16 +2729,16 @@ def is_edge_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap True sage: C = graphs.CubeGraph(3) - sage: C.is_edge_transitive() + sage: C.is_edge_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_edge_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_edge_transitive() # needs networkx sage.libs.gap True sage: P = graphs.PathGraph(4) - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2747,10 +2775,10 @@ def is_arc_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_arc_transitive() + sage: P.is_arc_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_arc_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_arc_transitive() # needs networkx sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2784,13 +2812,13 @@ def is_half_transitive(self): The Petersen Graph is not half-transitive:: sage: P = graphs.PetersenGraph() - sage: P.is_half_transitive() + sage: P.is_half_transitive() # needs sage.libs.gap False The smallest half-transitive graph is the Holt Graph:: sage: H = graphs.HoltGraph() - sage: H.is_half_transitive() + sage: H.is_half_transitive() # needs sage.libs.gap True """ # A half-transitive graph always has only vertices of even degree @@ -2821,19 +2849,19 @@ def is_semi_symmetric(self): The Petersen graph is not semi-symmetric:: sage: P = graphs.PetersenGraph() - sage: P.is_semi_symmetric() + sage: P.is_semi_symmetric() # needs sage.libs.gap False The Gray graph is the smallest possible cubic semi-symmetric graph:: - sage: G = graphs.GrayGraph() - sage: G.is_semi_symmetric() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_semi_symmetric() # needs networkx sage.libs.gap True Another well known semi-symmetric graph is the Ljubljana graph:: - sage: L = graphs.LjubljanaGraph() - sage: L.is_semi_symmetric() + sage: L = graphs.LjubljanaGraph() # needs networkx + sage: L.is_semi_symmetric() # needs networkx sage.libs.gap True """ # A semi-symmetric graph is always bipartite @@ -2955,8 +2983,8 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, sage: g = graphs.CycleGraph(6) sage: bounds = lambda x: [1,1] - sage: m = g.degree_constrained_subgraph(bounds=bounds) - sage: m.size() + sage: m = g.degree_constrained_subgraph(bounds=bounds) # needs sage.numerical.mip + sage: m.size() # needs sage.numerical.mip 3 """ self._scream_if_not_simple() @@ -3161,8 +3189,8 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`:: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: o = g.minimum_outdegree_orientation() - sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) + sage: o = g.minimum_outdegree_orientation() # needs sage.numerical.mip + sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -3632,23 +3660,23 @@ def chromatic_index(self, solver=None, verbose=0, *, integrality_tolerance=1e-3) The path `P_n` with `n \geq 2` has chromatic index 2:: - sage: graphs.PathGraph(5).chromatic_index() + sage: graphs.PathGraph(5).chromatic_index() # needs sage.numerical.mip 2 The windmill graph with parameters `k,n` has chromatic index `(k-1)n`:: sage: k,n = 3,4 sage: G = graphs.WindmillGraph(k,n) - sage: G.chromatic_index() == (k-1)*n + sage: G.chromatic_index() == (k-1)*n # needs sage.numerical.mip True TESTS: Graphs without vertices or edges:: - sage: Graph().chromatic_index() + sage: Graph().chromatic_index() # needs sage.numerical.mip 0 - sage: Graph(2).chromatic_index() + sage: Graph(2).chromatic_index() # needs sage.numerical.mip 0 """ if not self.order() or not self.size(): @@ -3725,7 +3753,7 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0, A bipartite graph has (by definition) chromatic number 2:: - sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() + sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() # needs numpy 2 A complete multipartite graph with k parts has chromatic number `k`:: @@ -3855,14 +3883,15 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0, True sage: are_equal_colorings(P, Q) True - sage: G.plot(partition=P) # optional - sage.plot + + sage: # needs sage.plot + sage: G.plot(partition=P) Graphics object consisting of 16 graphics primitives sage: G.coloring(hex_colors=True, algorithm="MILP") {'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]} - sage: H = G.coloring(hex_colors=True, algorithm="DLX") - sage: H + sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H {'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]} - sage: G.plot(vertex_colors=H) # optional - sage.plot + sage: G.plot(vertex_colors=H) Graphics object consisting of 16 graphics primitives .. PLOT:: @@ -3911,25 +3940,26 @@ def chromatic_symmetric_function(self, R=None): EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() + sage: s = SymmetricFunctions(ZZ).s() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1] Not all graphs have a positive Schur expansion:: sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1] We show that given a triangle `\{e_1, e_2, e_3\}`, we have `X_G = X_{G - e_1} + X_{G - e_2} - X_{G - e_1 - e_2}`:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2],[1,3],[2,3]]) sage: XG = G.chromatic_symmetric_function() sage: G1 = copy(G) @@ -3987,6 +4017,7 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2,3], [[1,3], [2,3]]]) sage: G.chromatic_quasisymmetric_function() (2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1] @@ -4005,27 +4036,27 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): Not all chromatic quasisymmetric functions are symmetric:: sage: G = Graph([[1,2], [1,5], [3,4], [3,5]]) - sage: G.chromatic_quasisymmetric_function().is_symmetric() + sage: G.chromatic_quasisymmetric_function().is_symmetric() # needs sage.combinat sage.modules False We check that at `t = 1`, we recover the usual chromatic symmetric function:: - sage: p = SymmetricFunctions(QQ).p() + sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1] + 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1] + 10*M[2, 1, 2] + 10*M[2, 2, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3] + 6*M[2, 1, 1] + M[3, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions @@ -4129,7 +4160,7 @@ def matching(self, value_only=False, algorithm="Edmonds", Maximum matching in a Pappus Graph:: sage: g = graphs.PappusGraph() - sage: g.matching(value_only=True) + sage: g.matching(value_only=True) # needs sage.networkx 9 Same test with the Linear Program formulation:: @@ -4149,7 +4180,7 @@ def matching(self, value_only=False, algorithm="Edmonds", and LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: sorted(g.matching()) + sage: sorted(g.matching()) # needs sage.networkx [(0, 1, 0), (2, 3, -5)] sage: sorted(g.matching(algorithm="LP")) [(0, 1, 0), (2, 3, -5)] @@ -4158,7 +4189,7 @@ def matching(self, value_only=False, algorithm="Edmonds", LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: g.matching(use_edge_labels=True) + sage: g.matching(use_edge_labels=True) # needs sage.networkx [(1, 2, 999)] sage: g.matching(algorithm="LP", use_edge_labels=True) [(1, 2, 999)] @@ -4168,10 +4199,10 @@ def matching(self, value_only=False, algorithm="Edmonds", sage: edge_list = [(0,0,5), (0,1,1), (0,2,2), (0,3,3), (1,2,6) ....: , (1,2,3), (1,3,3), (2,3,3)] sage: g = Graph(edge_list, loops=True, multiedges=True) - sage: m = g.matching(use_edge_labels=True) - sage: type(m) + sage: m = g.matching(use_edge_labels=True) # needs sage.networkx + sage: type(m) # needs sage.networkx - sage: sorted(m) + sage: sorted(m) # needs sage.networkx [(0, 3, 3), (1, 2, 6)] TESTS: @@ -4306,9 +4337,9 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve Odd length cycles and odd cliques of order at least 3 are factor-critical graphs:: - sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] - sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] More generally, every Hamiltonian graph with an odd number of vertices @@ -4319,18 +4350,18 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G.add_edge(14, 0) sage: G.is_hamiltonian() True - sage: G.is_factor_critical() + sage: G.is_factor_critical() # needs networkx True Friendship graphs are non-Hamiltonian factor-critical graphs:: - sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] + sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] # needs networkx [True, True, True, True] Bipartite graphs are not factor-critical:: - sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) - sage: G.is_factor_critical() + sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) # needs numpy + sage: G.is_factor_critical() # needs numpy False Graphs with even order are not factor critical:: @@ -4342,10 +4373,10 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve One can specify a matching:: sage: F = graphs.FriendshipGraph(4) - sage: M = F.matching() - sage: F.is_factor_critical(matching=M) + sage: M = F.matching() # needs networkx + sage: F.is_factor_critical(matching=M) # needs networkx True - sage: F.is_factor_critical(matching=Graph(M)) + sage: F.is_factor_critical(matching=Graph(M)) # needs networkx True TESTS: @@ -4355,8 +4386,8 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G = graphs.RandomGNP(15, .3) sage: while not G.is_biconnected(): ....: G = graphs.RandomGNP(15, .3) - sage: M = G.matching() - sage: G.is_factor_critical(matching=M[:-1]) + sage: M = G.matching() # needs networkx + sage: G.is_factor_critical(matching=M[:-1]) # needs networkx Traceback (most recent call last): ... ValueError: the input is not a near perfect matching of the graph @@ -4498,8 +4529,8 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, with this method :: sage: g = graphs.CycleGraph(10) - sage: mapping = g.has_homomorphism_to(g, core = True) - sage: print("The size of the core is {}".format(len(set(mapping.values())))) + sage: mapping = g.has_homomorphism_to(g, core=True) # needs sage.numerical.mip + sage: print("The size of the core is {}".format(len(set(mapping.values())))) # needs sage.numerical.mip The size of the core is 2 OUTPUT: @@ -4513,18 +4544,18 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, Is Petersen's graph 3-colorable:: sage: P = graphs.PetersenGraph() - sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False + sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False # needs sage.numerical.mip True An odd cycle admits a homomorphism to a smaller odd cycle, but not to an even cycle:: sage: g = graphs.CycleGraph(9) - sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -4616,7 +4647,7 @@ def fractional_clique_number(self, solver='PPL', verbose=0, The fractional clique number of a `C_7` is `7/3`:: sage: g = graphs.CycleGraph(7) - sage: g.fractional_clique_number() + sage: g.fractional_clique_number() # needs sage.numerical.mip 7/3 """ return self.fractional_chromatic_number(solver=solver, verbose=verbose, @@ -4660,37 +4691,38 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): In any graph, the `Mad` is always larger than the average degree:: sage: g = graphs.RandomGNP(20,.3) - sage: mad_g = g.maximum_average_degree() - sage: g.average_degree() <= mad_g + sage: mad_g = g.maximum_average_degree() # needs sage.numerical.mip + sage: g.average_degree() <= mad_g # needs sage.numerical.mip True Unlike the average degree, the `Mad` of the disjoint union of two graphs is the maximum of the `Mad` of each graphs:: sage: h = graphs.RandomGNP(20,.3) - sage: mad_h = h.maximum_average_degree() - sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) + sage: mad_h = h.maximum_average_degree() # needs sage.numerical.mip + sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) # needs sage.numerical.mip True The subgraph of a regular graph realizing the maximum average degree is always the whole graph :: sage: g = graphs.CompleteGraph(5) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True This also works for complete bipartite graphs :: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True TESTS: Check corner cases:: + sage: # needs sage.numerical.mip sage: Graph().maximum_average_degree(value_only=True) 0 sage: Graph().maximum_average_degree(value_only=False) @@ -4794,7 +4826,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, sage: g = graphs.CompleteBipartiteGraph(3,3) sage: g.delete_edge(1,4) - sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) + sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) # needs sage.numerical.mip [1, 4] The Petersen Graph is 3-colorable, which can be expressed as an @@ -4803,6 +4835,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, partition of the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a 3-coloring:: + sage: # needs sage.numerical.mip sage: g = 3 * graphs.PetersenGraph() sage: n = g.order() / 3 sage: f = [[i, i + n, i + 2*n] for i in range(n)] @@ -4923,6 +4956,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): Trying to find a minor isomorphic to `K_4` in the `4\times 4` grid:: + sage: # needs sage.numerical.mip sage: g = graphs.GridGraph([4,4]) sage: h = graphs.CompleteGraph(4) sage: L = g.minor(h) @@ -4935,11 +4969,11 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): as it has a `K_5` minor:: sage: g = graphs.PetersenGraph() - sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time + sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time # needs sage.numerical.mip And even a `K_{3,3}` minor:: - sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time + sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time, needs sage.numerical.mip (It is much faster to use the linear-time test of planarity in this situation, though.) @@ -4951,7 +4985,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: g = g.subgraph(edges = g.min_spanning_tree()) sage: g.is_tree() True - sage: L = g.minor(graphs.CompleteGraph(3)) + sage: L = g.minor(graphs.CompleteGraph(3)) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: This graph has no minor isomorphic to H ! @@ -5234,7 +5268,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, [1, 1, 1] sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython') [1, 1, 1] - sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX') + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [2, 1, 2] sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost') [2, 1, 2] @@ -5769,7 +5803,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.cartesian_product(graphs.CompleteGraph(2)) sage: K = H.distance_graph(2) - sage: K.am() + sage: K.am() # needs sage.modules [0 0 0 1 0 1] [0 0 1 0 1 0] [0 1 0 0 0 1] @@ -5797,8 +5831,8 @@ def distance_graph(self, dist): that sum to the matrix of all ones:: sage: P = graphs.PathGraph(20) - sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) - sage: all_ones == matrix(ZZ, 20, 20, [1]*400) + sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) # needs sage.modules + sage: all_ones == matrix(ZZ, 20, 20, [1]*400) # needs sage.modules True Four-bit strings differing in one bit is the same as @@ -5812,11 +5846,12 @@ def distance_graph(self, dist): The graph of eight-bit strings, adjacent if different in an odd number of bits:: - sage: G = graphs.CubeGraph(8) # long time - sage: H = G.distance_graph([1,3,5,7]) # long time - sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) # long time - sage: degrees.append(2^8) # long time - sage: degrees == H.degree_histogram() # long time + sage: # long time + sage: G = graphs.CubeGraph(8) + sage: H = G.distance_graph([1,3,5,7]) + sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) + sage: degrees.append(2^8) + sage: degrees == H.degree_histogram() True An example of using ``Infinity`` as the distance in a graph that is not @@ -5825,7 +5860,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.disjoint_union(graphs.CompleteGraph(2)) sage: L = H.distance_graph(Infinity) - sage: L.am() + sage: L.am() # needs sage.modules [0 0 0 1 1] [0 0 0 1 1] [0 0 0 1 1] @@ -5950,12 +5985,12 @@ def to_directed(self, data_structure=None, sparse=None): :trac:`22424`:: sage: G1 = graphs.RandomGNP(5,0.5) - sage: gp1 = G1.graphplot(save_pos=True) # optional - sage.plot + sage: gp1 = G1.graphplot(save_pos=True) # needs sage.plot sage: G2 = G1.to_directed() sage: G2.delete_vertex(0) sage: G2.add_vertex(5) - sage: gp2 = G2.graphplot() # optional - sage.plot - sage: gp1 = G1.graphplot() # optional - sage.plot + sage: gp2 = G2.graphplot() # needs sage.plot + sage: gp1 = G1.graphplot() # needs sage.plot Vertex labels will be retained (:trac:`14708`):: @@ -6114,14 +6149,14 @@ def seidel_adjacency_matrix(self, vertices=None, *, base_ring=None, **kwds): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 Selecting the base ring:: - sage: G.seidel_adjacency_matrix()[0, 0].parent() + sage: G.seidel_adjacency_matrix()[0, 0].parent() # needs sage.modules Integer Ring - sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() + sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field """ set_immutable = kwds.pop('immutable', False) @@ -6161,7 +6196,7 @@ def seidel_switching(self, s, inplace=True): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) sage: G.seidel_switching([(0,1),(1,0),(0,0)]) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 sage: G.is_connected() True @@ -6192,13 +6227,14 @@ def twograph(self): EXAMPLES:: - sage: p=graphs.PetersenGraph() - sage: p.twograph() + sage: p = graphs.PetersenGraph() + sage: p.twograph() # needs sage.modules Incidence structure with 10 points and 60 blocks sage: p=graphs.chang_graphs() sage: T8 = graphs.CompleteGraph(8).line_graph() - sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],inplace=False) - sage: T8.twograph() == C.twograph() + sage: C = T8.seidel_switching([(0,1,None), (2,3,None), (4,5,None), (6,7,None)], + ....: inplace=False) + sage: T8.twograph() == C.twograph() # needs sage.modules True sage: T8.is_isomorphic(C) False @@ -6206,8 +6242,8 @@ def twograph(self): TESTS:: sage: from sage.combinat.designs.twographs import TwoGraph - sage: p=graphs.PetersenGraph().twograph() - sage: TwoGraph(p, check=True) + sage: p = graphs.PetersenGraph().twograph() # needs sage.modules + sage: TwoGraph(p, check=True) # needs sage.modules Incidence structure with 10 points and 60 blocks .. SEEALSO:: @@ -6341,19 +6377,19 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose Petersen's graph has a topological `K_4`-minor:: sage: g = graphs.PetersenGraph() - sage: g.topological_minor(graphs.CompleteGraph(4)) + sage: g.topological_minor(graphs.CompleteGraph(4)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And a topological `K_{3,3}`-minor:: - sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) + sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And of course, a tree has no topological `C_3`-minor:: sage: g = graphs.RandomGNP(15,.3) - sage: g = g.subgraph(edges = g.min_spanning_tree()) - sage: g.topological_minor(graphs.CycleGraph(3)) + sage: g = g.subgraph(edges=g.min_spanning_tree()) + sage: g.topological_minor(graphs.CycleGraph(3)) # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -6545,7 +6581,7 @@ def cliques_maximal(self, algorithm="native"): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2, 2]) # optional - sage.plot + sage: G.show(figsize=[2, 2]) # needs sage.plot sage: G.cliques_maximal() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -6559,9 +6595,9 @@ def cliques_maximal(self, algorithm="native"): Comparing the two implementations:: sage: g = graphs.RandomGNP(20,.7) - sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) + sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) # needs networkx sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native"))) - sage: s1 == s2 + sage: s1 == s2 # needs networkx True """ if algorithm == "native": @@ -6720,7 +6756,7 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 @@ -6744,9 +6780,9 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= TESTS:: sage: g = graphs.PetersenGraph() - sage: g.clique_number(algorithm="MILP") + sage: g.clique_number(algorithm="MILP") # needs sage.numerical.mip 2 - sage: for i in range(10): # optional - mcqd + sage: for i in range(10): # optional - mcqd # needs sage.numerical.mip ....: g = graphs.RandomGNP(15,.5) ....: if g.clique_number() != g.clique_number(algorithm="mcqd"): ....: print("This is dead wrong !") @@ -6789,23 +6825,23 @@ def cliques_number_of(self, vertices=None, cliques=None): EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_number_of() + sage: C.cliques_number_of() # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: E = C.cliques_maximal() sage: E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_number_of(cliques=E) + sage: C.cliques_number_of(cliques=E) # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_number_of() + sage: F.cliques_number_of() # needs networkx {(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2} - sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) + sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) # needs networkx {(0, 1): 3, (1, 2): 2} sage: F.cliques_number_of(vertices=(0, 1)) 3 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_number_of() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_number_of() # needs networkx {0: 2, 1: 2, 2: 1, 3: 1} """ if cliques is None: @@ -6840,14 +6876,14 @@ def cliques_get_max_clique_graph(self): EXAMPLES:: - sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG + sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG # needs networkx Graph on 24 vertices - sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot + sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_get_max_clique_graph() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_max_clique_graph() # needs networkx Graph on 2 vertices - sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # optional - sage.plot + sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # needs networkx sage.plot """ import networkx return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph()), @@ -6868,21 +6904,20 @@ def cliques_get_clique_bipartite(self, **kwds): EXAMPLES:: - sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG + sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG # needs networkx Bipartite graph on 36 vertices - sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot + sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_get_clique_bipartite() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_clique_bipartite() # needs networkx Bipartite graph on 6 vertices - sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # optional - sage.plot + sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # needs networkx sage.plot """ from .bipartite_graph import BipartiteGraph import networkx return BipartiteGraph(networkx.make_clique_bipartite(self.networkx_graph(), **kwds)) @doc_index("Algorithmically hard stuff") - @rename_keyword(deprecation=32238, verbosity='verbose') def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -6958,7 +6993,7 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules As a linear program:: sage: C = graphs.PetersenGraph() - sage: len(C.independent_set(algorithm="MILP")) + sage: len(C.independent_set(algorithm="MILP")) # needs sage.numerical.mip 4 .. PLOT:: @@ -6977,7 +7012,6 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules return [u for u in self if u not in my_cover] @doc_index("Algorithmically hard stuff") - @rename_keyword(deprecation=32238, verbosity='verbose') def vertex_cover(self, algorithm="Cliquer", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -7057,9 +7091,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, The two algorithms should return the same result:: sage: g = graphs.RandomGNP(10, .5) - sage: vc1 = g.vertex_cover(algorithm="MILP") + sage: vc1 = g.vertex_cover(algorithm="MILP") # needs sage.numerical.mip sage: vc2 = g.vertex_cover(algorithm="Cliquer") - sage: len(vc1) == len(vc2) + sage: len(vc1) == len(vc2) # needs sage.numerical.mip True The cardinality of the vertex cover is unchanged when reduction rules @@ -7110,9 +7144,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, Issue :trac:`24287` is fixed:: sage: G = Graph([(0,1)]*5 + [(1,2)]*2, multiedges=True) - sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') + sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') # needs sage.numerical.mip [1] - sage: G.vertex_cover(reduction_rules=False) + sage: G.vertex_cover(reduction_rules=False) # needs sage.numerical.mip [1] Issue :trac:`25988` is fixed:: @@ -7466,20 +7500,22 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_vertex_clique_number() # optional - sage.plot + sage: C.cliques_vertex_clique_number() {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # optional - sage.plot + sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} + sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_vertex_clique_number(algorithm="networkx") # optional - sage.plot + sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx {(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2} - sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) # optional - sage.plot + sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) {(0, 1): 2, (1, 2): 2} + sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_vertex_clique_number() # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_vertex_clique_number() {0: 3, 1: 3, 2: 3, 3: 3} """ if algorithm == "cliquer": @@ -7518,6 +7554,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): EXAMPLES:: + sage: # needs networkx sage: C = Graph('DJ{') sage: C.cliques_containing_vertex() {0: [[0, 4]], @@ -7529,8 +7566,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex([0, 1]) {0: [[0, 4]], 1: [[1, 2, 3, 4]]} - sage: E = C.cliques_maximal() - sage: E + sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex(cliques=E) {0: [[0, 4]], @@ -7540,8 +7576,8 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): 4: [[0, 4], [1, 2, 3, 4]]} sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_containing_vertex() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_containing_vertex() # needs networkx {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], @@ -7550,6 +7586,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex is involved equals its degree:: + sage: # needs networkx sage: F = graphs.Grid2dGraph(2,3) sage: d = F.cliques_containing_vertex() sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) @@ -7716,20 +7753,23 @@ def cores(self, k=None, with_labels=False): [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] sage: (graphs.FruchtGraph()).cores(with_labels=True) {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3} + + sage: # needs sage.modules sage: set_random_seed(0) sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) sage: b = Graph(20) sage: b.add_edges(a.nonzero_positions(), loops=False) sage: cores = b.cores(with_labels=True); cores - {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} - sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core + {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, + 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} + sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Checking the 2-core of a random lobster is indeed the empty set:: - sage: g = graphs.RandomLobster(20, .5, .5) - sage: ordering, core = g.cores(2) - sage: len(core) == 0 + sage: g = graphs.RandomLobster(20, .5, .5) # needs networkx + sage: ordering, core = g.cores(2) # needs networkx + sage: len(core) == 0 # needs networkx True Checking the cores of a bull graph:: @@ -8127,22 +8167,22 @@ def is_circumscribable(self, solver="ppl", verbose=0): EXAMPLES:: sage: C = graphs.CubeGraph(3) - sage: C.is_circumscribable() + sage: C.is_circumscribable() # needs sage.numerical.mip True sage: O = graphs.OctahedralGraph() - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip True - sage: TT = polytopes.truncated_tetrahedron().graph() - sage: TT.is_circumscribable() + sage: TT = polytopes.truncated_tetrahedron().graph() # needs sage.geometry.polyhedron + sage: TT.is_circumscribable() # needs sage.geometry.polyhedron sage.numerical.mip False Stellating in a face of the octahedral graph is not circumscribable:: sage: f = set(flatten(choice(O.faces()))) sage: O.add_edges([[6, i] for i in f]) - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip False .. SEEALSO:: @@ -8249,7 +8289,7 @@ def is_inscribable(self, solver="ppl", verbose=0): True sage: C = graphs.CubeGraph(3) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip True Cutting off a vertex from the cube yields an uninscribable graph:: @@ -8260,7 +8300,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C.add_edges(Combinations(triangle, 2)) sage: C.add_edges(zip(triangle, C.neighbors(v))) sage: C.delete_vertex(v) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False Breaking a face of the cube yields an uninscribable graph:: @@ -8268,7 +8308,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C = graphs.CubeGraph(3) sage: face = choice(C.faces()) sage: C.add_edge([face[0][0], face[2][0]]) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False @@ -8554,22 +8594,24 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1 edge-partitionned into `2`-regular graphs:: sage: g = graphs.CompleteGraph(7) - sage: classes = g.two_factor_petersen() - sage: for c in classes: + sage: classes = g.two_factor_petersen() # needs sage.numerical.mip + sage: for c in classes: # needs sage.numerical.mip ....: gg = Graph() ....: gg.add_edges(c) ....: print(max(gg.degree())<=2) True True True - sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size() + sage: Set(set(classes[0]) # needs sage.numerical.mip + ....: | set(classes[1]) + ....: | set(classes[2])).cardinality() == g.size() True :: sage: g = graphs.CirculantGraph(24, [7, 11]) - sage: cl = g.two_factor_petersen() - sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # optional - sage.plot + sage: cl = g.two_factor_petersen() # needs sage.numerical.mip + sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # needs sage.numerical.mip sage.plot Graphics object consisting of 73 graphics primitives """ @@ -8641,30 +8683,30 @@ def kirchhoff_symanzik_polynomial(self, name='t'): For the cycle of length 5:: sage: G = graphs.CycleGraph(5) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0 + t1 + t2 + t3 + t4 One can use another letter for variables:: - sage: G.kirchhoff_symanzik_polynomial(name='u') + sage: G.kirchhoff_symanzik_polynomial(name='u') # needs networkx sage.modules u0 + u1 + u2 + u3 + u4 For the 'coffee bean' graph:: sage: G = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 For the 'parachute' graph:: sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3 For the complete graph with 4 vertices:: sage: G = graphs.CompleteGraph(4) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4 + t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5 + t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5 @@ -8714,44 +8756,44 @@ def magnitude_function(self): EXAMPLES:: sage: g = Graph({1:[], 2:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 2 sage: g = graphs.CycleGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 4/(q^2 + 2*q + 1) sage: g = graphs.CycleGraph(5) - sage: m = g.magnitude_function(); m + sage: m = g.magnitude_function(); m # needs sage.modules 5/(2*q^2 + 2*q + 1) One can expand the magnitude as a power series in `q` as follows:: sage: q = QQ[['q']].gen() - sage: m(q) + sage: m(q) # needs sage.modules 5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ... One can also use the substitution `q = exp(-t)` to obtain the magnitude function as a function of `t`:: sage: g = graphs.CycleGraph(6) - sage: m = g.magnitude_function() - sage: t = var('t') # optional - sage.symbolic - sage: m(exp(-t)) # optional - sage.symbolic + sage: m = g.magnitude_function() # needs sage.modules + sage: t = var('t') # needs sage.modules sage.symbolic + sage: m(exp(-t)) # needs sage.modules sage.symbolic 6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1) TESTS:: sage: g = Graph() - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 0 sage: g = Graph({1:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 1 sage: g = graphs.PathGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules (-2*q + 4)/(q + 1) REFERENCES: @@ -8805,20 +8847,20 @@ def ihara_zeta_function_inverse(self): EXAMPLES:: sage: G = graphs.CompleteGraph(4) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3 sage: G = graphs.CompleteGraph(5) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4 sage: G = graphs.PetersenGraph() - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4 * (2*t^2 - t + 1)^5 sage: G = graphs.RandomTree(10) - sage: G.ihara_zeta_function_inverse() + sage: G.ihara_zeta_function_inverse() # needs sage.libs.pari sage.modules 1 REFERENCES: @@ -9001,11 +9043,11 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, EXAMPLES:: - sage: graphs.PetersenGraph().has_perfect_matching() + sage: graphs.PetersenGraph().has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(6).has_perfect_matching() + sage: graphs.WheelGraph(6).has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(5).has_perfect_matching() + sage: graphs.WheelGraph(5).has_perfect_matching() # needs networkx False sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching") True @@ -9023,14 +9065,16 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, TESTS:: sage: G = graphs.EmptyGraph() - sage: all(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: all(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) True Be careful with isolated vertices:: sage: G = graphs.PetersenGraph() sage: G.add_vertex(11) - sage: any(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: any(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) False """ if self.order() % 2: @@ -9088,6 +9132,7 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a straight linear 2-tree on 6 vertices :: + sage: # needs sage.modules sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) sage: G.effective_resistance(0,1) 34/55 @@ -9100,6 +9145,7 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a fan on 6 vertices :: + sage: # needs sage.modules sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) sage: H.effective_resistance(1,5) 6/5 @@ -9110,9 +9156,9 @@ def effective_resistance(self, i, j, *, base_ring=None): Using a different base ring:: - sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 + sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 # needs sage.modules 1.2000000000000000 - sage: H.effective_resistance(1, 1, base_ring=RDF) + sage: H.effective_resistance(1, 1, base_ring=RDF) # needs sage.modules 0.0 .. SEEALSO:: @@ -9128,8 +9174,10 @@ def effective_resistance(self, i, j, *, base_ring=None): TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) - sage: all(G.effective_resistance(u, v) == 1/2 for u,v in G.edge_iterator(labels=False)) + sage: all(G.effective_resistance(u, v) == 1/2 + ....: for u,v in G.edge_iterator(labels=False)) True sage: Graph(1).effective_resistance(0,0) 0 @@ -9221,7 +9269,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, only non-adjacent vertex pairs :: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules [ 0 0 0 49/55 59/55 15/11] [ 0 0 0 0 9/11 59/55] [ 0 0 0 0 0 49/55] @@ -9232,7 +9280,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, The same effective resistance matrix, this time including adjacent vertices :: - sage: G.effective_resistance_matrix(nonedgesonly=False) + sage: G.effective_resistance_matrix(nonedgesonly=False) # needs sage.modules [ 0 34/55 34/55 49/55 59/55 15/11] [34/55 0 26/55 31/55 9/11 59/55] [34/55 26/55 0 5/11 31/55 49/55] @@ -9244,7 +9292,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.effective_resistance_matrix() + sage: H.effective_resistance_matrix() # needs sage.modules [ 0 0 0 0 0 0 0] [ 0 0 0 49/55 56/55 6/5 89/55] [ 0 0 0 0 4/5 56/55 81/55] @@ -9255,7 +9303,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() + sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field .. SEEALSO:: @@ -9270,7 +9318,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, TESTS:: - sage: graphs.CompleteGraph(4).effective_resistance_matrix() + sage: graphs.CompleteGraph(4).effective_resistance_matrix() # needs sage.modules [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -9278,7 +9326,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1)] * 3) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with @@ -9286,6 +9334,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). + sage: # needs sage.modules sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) [ 0 1/2 1/2 1/2] [1/2 0 1/2 1/2] @@ -9305,11 +9354,12 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, [0 1 0 0] sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari True Ask for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) sage: M = G.effective_resistance_matrix(immutable=False) sage: M.is_immutable() @@ -9375,20 +9425,20 @@ def least_effective_resistance(self, nonedgesonly=True): straight linear 2-tree on 6 vertices:: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.least_effective_resistance() + sage: G.least_effective_resistance() # needs sage.modules [(1, 4)] Pairs of (adjacent or non-adjacent) nodes with least effective resistance in a straight linear 2-tree on 6 vertices :: - sage: G.least_effective_resistance(nonedgesonly = False) + sage: G.least_effective_resistance(nonedgesonly=False) # needs sage.modules [(2, 3)] Pairs of non-adjacent nodes with least effective resistance in a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.least_effective_resistance() + sage: H.least_effective_resistance() # needs sage.modules [(2, 4)] .. SEEALSO:: @@ -9405,6 +9455,7 @@ def least_effective_resistance(self, nonedgesonly=True): TESTS:: + sage: # needs sage.modules sage: graphs.CompleteGraph(4).least_effective_resistance() [] sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) @@ -9470,7 +9521,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, sage: G1 = Graph() sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.common_neighbors_matrix(nonedgesonly = True) + sage: G1.common_neighbors_matrix(nonedgesonly=True) # needs sage.modules [0 0 0 2 1 0] [0 0 0 0 2 1] [0 0 0 0 0 2] @@ -9481,7 +9532,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, We now show the common neighbors matrix which includes adjacent vertices :: - sage: G1.common_neighbors_matrix(nonedgesonly = False) + sage: G1.common_neighbors_matrix(nonedgesonly=False) # needs sage.modules [0 1 1 2 1 0] [1 0 2 1 2 1] [1 2 0 2 1 2] @@ -9493,7 +9544,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.common_neighbors_matrix() + sage: H.common_neighbors_matrix() # needs sage.modules [0 0 0 0 0 0 0] [0 0 0 2 1 1 1] [0 0 0 0 2 1 1] @@ -9504,7 +9555,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.common_neighbors_matrix(base_ring=RDF) + sage: H.common_neighbors_matrix(base_ring=RDF) # needs sage.modules [0.0 0.0 0.0 0.0 0.0 0.0 0.0] [0.0 0.0 0.0 2.0 1.0 1.0 1.0] [0.0 0.0 0.0 0.0 2.0 1.0 1.0] @@ -9515,8 +9566,8 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, It is an error to input anything other than a simple graph:: - sage: G = Graph([(0,0)],loops=True) - sage: G.common_neighbors_matrix() + sage: G = Graph([(0,0)], loops=True) + sage: G.common_neighbors_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with loops. @@ -9531,6 +9582,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) sage: M = G.common_neighbors_matrix() sage: M.is_zero() @@ -9548,6 +9600,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, Asking for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) sage: M = G.common_neighbors_matrix() sage: M.is_immutable() @@ -9593,19 +9646,19 @@ def most_common_neighbors(self, nonedgesonly=True): linear 2-tree :: sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.most_common_neighbors() + sage: G1.most_common_neighbors() # needs sage.modules [(0, 3), (1, 4), (2, 5)] If we include non-adjacent pairs :: - sage: G1.most_common_neighbors(nonedgesonly = False) + sage: G1.most_common_neighbors(nonedgesonly=False) # needs sage.modules [(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)] The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.most_common_neighbors() + sage: H.most_common_neighbors() # needs sage.modules [(1, 3), (2, 4), (3, 5)] .. SEEALSO:: @@ -9615,7 +9668,8 @@ def most_common_neighbors(self, nonedgesonly=True): TESTS:: - sage: G=graphs.CompleteGraph(4) + sage: # needs sage.modules + sage: G = graphs.CompleteGraph(4) sage: G.most_common_neighbors() [] sage: G.most_common_neighbors(nonedgesonly=False) @@ -9682,18 +9736,18 @@ def arboricity(self, certificate=False): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: a,F = G.arboricity(True) - sage: a + sage: a, F = G.arboricity(True) # needs sage.modules + sage: a # needs sage.modules 2 - sage: all([f.is_forest() for f in F]) + sage: all([f.is_forest() for f in F]) # needs sage.modules True - sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() + sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() # needs sage.modules True TESTS:: sage: g = Graph() - sage: g.arboricity(True) + sage: g.arboricity(True) # needs sage.modules (0, []) """ from sage.matroids.constructor import Matroid diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 60abd45d4d1..f11bc3c4a05 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -104,11 +104,12 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict= 3 sage: format_coloring(color_classes, value_only=False) {0: ['a', 'b'], 1: ['c'], 2: ['d']} - sage: format_coloring(color_classes, value_only=False, hex_colors=True) + sage: format_coloring(color_classes, value_only=False, hex_colors=True) # needs sage.plot {'#0000ff': ['d'], '#00ff00': ['c'], '#ff0000': ['a', 'b']} sage: format_coloring(color_classes, value_only=False, hex_colors=False, vertex_color_dict=True) {'a': 0, 'b': 0, 'c': 1, 'd': 2} - sage: format_coloring(color_classes, value_only=False, hex_colors=True, vertex_color_dict=True) + sage: format_coloring(color_classes, value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) {'a': '#ff0000', 'b': '#ff0000', 'c': '#00ff00', 'd': '#0000ff'} TESTS:: @@ -116,9 +117,10 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict= sage: from sage.graphs.graph_coloring import format_coloring sage: format_coloring([], value_only=True) [] - sage: format_coloring([], value_only=False, hex_colors=True) + sage: format_coloring([], value_only=False, hex_colors=True) # needs sage.plot {} - sage: format_coloring([], value_only=False, hex_colors=True, vertex_color_dict=True) + sage: format_coloring([], value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) {} sage: format_coloring([], value_only=False, hex_colors=False, vertex_color_dict=True) {} @@ -210,7 +212,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, sage: from sage.graphs.graph_coloring import all_graph_colorings sage: G = Graph({0: [1, 2, 3], 1: [2]}) sage: n = 0 - sage: for C in all_graph_colorings(G, 3, hex_colors=True): + sage: for C in all_graph_colorings(G, 3, hex_colors=True): # needs sage.plot ....: parts = [C[k] for k in C] ....: for P in parts: ....: l = len(P) @@ -218,8 +220,8 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, ....: for j in range(i + 1, l): ....: if G.has_edge(P[i], P[j]): ....: raise RuntimeError("Coloring Failed.") - ....: n+=1 - sage: print("G has %s 3-colorings." % n) + ....: n += 1 + sage: print("G has %s 3-colorings." % n) # needs sage.plot G has 12 3-colorings. TESTS:: @@ -237,11 +239,12 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, ....: print(c) {0: 0, 2: 0, 1: 1} {1: 0, 0: 1, 2: 1} - sage: for c in all_graph_colorings(G, 2, hex_colors=True): + sage: for c in all_graph_colorings(G, 2, hex_colors=True): # needs sage.plot ....: print(sorted(c.items())) [('#00ffff', [1]), ('#ff0000', [0, 2])] [('#00ffff', [0, 2]), ('#ff0000', [1])] - sage: for c in all_graph_colorings(G, 2, hex_colors=True, vertex_color_dict=True): + sage: for c in all_graph_colorings(G, 2, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True): ....: print(c) {0: '#ff0000', 2: '#ff0000', 1: '#00ffff'} {1: '#ff0000', 0: '#00ffff', 2: '#00ffff'} @@ -513,7 +516,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, sage: from sage.graphs.graph_coloring import vertex_coloring sage: g = graphs.PetersenGraph() - sage: vertex_coloring(g, value_only=True) + sage: vertex_coloring(g, value_only=True) # needs sage.numerical.mip 3 TESTS: @@ -532,7 +535,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, :trac:`33559` is fixed:: sage: G = Graph('MgCgS?_O@IeTHKG??') - sage: len(G.coloring(algorithm='MILP')) + sage: len(G.coloring(algorithm='MILP')) # needs sage.numerical.mip 4 """ g._scream_if_not_simple(allow_multiple_edges=True) @@ -775,15 +778,15 @@ def fractional_chromatic_number(G, solver='PPL', verbose=0, The fractional chromatic number of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_number() + sage: g.fractional_chromatic_number() # needs sage.numerical.mip 5/2 TESTS:: sage: G = graphs.RandomGNP(20, .2) - sage: a = G.fractional_chromatic_number(check_components=True) - sage: b = G.fractional_chromatic_number(check_components=False) - sage: a == b + sage: a = G.fractional_chromatic_number(check_components=True) # needs sage.numerical.mip + sage: b = G.fractional_chromatic_number(check_components=False) # needs sage.numerical.mip + sage: a == b # needs sage.numerical.mip True """ G._scream_if_not_simple() @@ -884,7 +887,7 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo The fractional chromatic index of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_index() + sage: g.fractional_chromatic_index() # needs sage.numerical.mip 5/2 TESTS: @@ -893,9 +896,9 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo solvers:: sage: g = graphs.PetersenGraph() - sage: g.fractional_chromatic_index(solver='GLPK') # known bug (#23798) + sage: g.fractional_chromatic_index(solver='GLPK') # known bug # needs sage.numerical.mip 3.0 - sage: g.fractional_chromatic_index(solver='PPL') + sage: g.fractional_chromatic_index(solver='PPL') # needs sage.numerical.mip 3 """ G._scream_if_not_simple() @@ -1025,13 +1028,13 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import grundy_coloring sage: g = graphs.PathGraph(4) - sage: grundy_coloring(g, 4) + sage: grundy_coloring(g, 4) # needs sage.numerical.mip 3 The Grundy number of the PetersenGraph is equal to 4:: sage: g = graphs.PetersenGraph() - sage: grundy_coloring(g, 5) + sage: grundy_coloring(g, 5) # needs sage.numerical.mip 4 It would have been sufficient to set the value of ``k`` to 4 in @@ -1179,13 +1182,13 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import b_coloring sage: g = graphs.PathGraph(5) - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 The b-chromatic number of the Petersen Graph is equal to 3:: sage: g = graphs.PetersenGraph() - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 It would have been sufficient to set the value of ``k`` to 4 in this case, @@ -1378,47 +1381,49 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No The Petersen graph has chromatic index 4:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: g = graphs.PetersenGraph() - sage: edge_coloring(g, value_only=True, solver='GLPK') - 4 - sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') - sage: len(color_classes) - 4 - sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() - True - sage: all(g.has_edge(e) for C in color_classes for e in C) - True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) - True - sage: color_classes = edge_coloring(g, value_only=False, hex_colors=True, solver='GLPK') - sage: sorted(color_classes.keys()) - ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] + sage: # needs sage.numerical.mip + sage: from sage.graphs.graph_coloring import edge_coloring + sage: g = graphs.PetersenGraph() + sage: edge_coloring(g, value_only=True, solver='GLPK') + 4 + sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') + sage: len(color_classes) + 4 + sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() + True + sage: all(g.has_edge(e) for C in color_classes for e in C) + True + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx + True + sage: color_classes = edge_coloring(g, value_only=False, + ....: hex_colors=True, solver='GLPK') + sage: sorted(color_classes.keys()) + ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] Complete graphs are colored using the linear-time round-robin coloring:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: len(edge_coloring(graphs.CompleteGraph(20))) - 19 + sage: from sage.graphs.graph_coloring import edge_coloring + sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip + 19 The chromatic index of a non connected graph is the maximum over its connected components:: - sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) - sage: edge_coloring(g, value_only=True) - 9 + sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 9 TESTS: Graph without edge:: - sage: g = Graph(2) - sage: edge_coloring(g) - [] - sage: edge_coloring(g, value_only=True) - 0 - sage: edge_coloring(g, hex_colors=True) - {} + sage: g = Graph(2) + sage: edge_coloring(g) # needs sage.numerical.mip + [] + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 0 + sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + {} """ g._scream_if_not_simple() @@ -1564,7 +1569,7 @@ def _vizing_edge_coloring(g): True sage: all(g.has_edge(e) for C in color_classes for e in C) True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx True Coloring the edges of the Star Graph:: @@ -1832,22 +1837,23 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, horizontal lines and the set of vertical lines are an admissible partition:: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: g = graphs.Grid2dGraph(4, 4) - sage: g1,g2 = linear_arboricity(g) + sage: g = graphs.Grid2dGraph(4, 4) # needs sage.numerical.mip + sage: g1,g2 = linear_arboricity(g) # needs sage.numerical.mip Each graph is of course a forest:: - sage: g1.is_forest() and g2.is_forest() + sage: g1.is_forest() and g2.is_forest() # needs sage.numerical.mip True Of maximum degree 2:: - sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 + sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 # needs sage.numerical.mip True Which constitutes a partition of the whole edge set:: - sage: all((g1.has_edge(e) or g2.has_edge(e)) for e in g.edge_iterator(labels=None)) + sage: all((g1.has_edge(e) or g2.has_edge(e)) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=None)) True TESTS: @@ -1855,15 +1861,15 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, Asking for the value of the linear arboricity only (:trac:`24991`):: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) + sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import linear_arboricity sage: g = graphs.Grid2dGraph(4, 4) - sage: d = linear_arboricity(g, hex_colors=True) - sage: sorted(d) + sage: d = linear_arboricity(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#00ffff', '#ff0000'] """ g._scream_if_not_simple() @@ -2036,21 +2042,22 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(8) - sage: colors = acyclic_edge_coloring(g) + sage: colors = acyclic_edge_coloring(g) # needs sage.numerical.mip Each color class is of course a matching :: - sage: all(max(gg.degree()) <= 1 for gg in colors) + sage: all(max(gg.degree()) <= 1 for gg in colors) # needs sage.numerical.mip True These matchings being a partition of the edge set:: - sage: all(any(gg.has_edge(e) for gg in colors) for e in g.edge_iterator(labels=False)) + sage: all(any(gg.has_edge(e) for gg in colors) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=False)) True Besides, the union of any two of them is a forest :: - sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) + sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) # needs sage.numerical.mip True If one wants to acyclically color a cycle on `4` vertices, at least 3 colors @@ -2058,15 +2065,15 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, with only 2:: sage: g = graphs.CycleGraph(4) - sage: acyclic_edge_coloring(g, k=2) + sage: acyclic_edge_coloring(g, k=2) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: this graph cannot be colored with the given number of colors The optimal coloring give us `3` classes:: - sage: colors = acyclic_edge_coloring(g, k=None) - sage: len(colors) + sage: colors = acyclic_edge_coloring(g, k=None) # needs sage.numerical.mip + sage: len(colors) # needs sage.numerical.mip 3 TESTS: @@ -2074,32 +2081,32 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, Issue :trac:`24991` is fixed:: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) + sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(4) - sage: d = acyclic_edge_coloring(g, hex_colors=True) - sage: sorted(d) + sage: d = acyclic_edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#0066ff', '#00ff66', '#cbff00', '#cc00ff', '#ff0000'] The acyclic chromatic index of a graph without edge is 0 (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = Graph(3) - sage: acyclic_edge_coloring(g, k=None, value_only=True) + sage: acyclic_edge_coloring(g, k=None, value_only=True) # needs sage.numerical.mip 0 - sage: acyclic_edge_coloring(g, k=None, hex_colors=True) + sage: acyclic_edge_coloring(g, k=None, hex_colors=True) # needs sage.numerical.mip {} - sage: acyclic_edge_coloring(g, k=None, hex_colors=False) + sage: acyclic_edge_coloring(g, k=None, hex_colors=False) # needs sage.numerical.mip [] Empty graph (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) + sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) # needs sage.numerical.mip 0 """ g._scream_if_not_simple(allow_multiple_edges=True) diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 9274ca13452..b8e9226bc2c 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -120,7 +120,7 @@ def graph6_to_plot(graph6): EXAMPLES:: sage: from sage.graphs.graph_database import graph6_to_plot - sage: type(graph6_to_plot('D??')) # optional - sage.plot + sage: type(graph6_to_plot('D??')) # needs sage.plot """ g = Graph(str(graph6)) diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx index d72c6e5ff80..bbd3916ac2b 100644 --- a/src/sage/graphs/graph_decompositions/bandwidth.pyx +++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx @@ -160,7 +160,7 @@ def bandwidth(G, k=None): False sage: bandwidth(G) (5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) - sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # optional - sage.modules + sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # needs sage.modules [0 1 1 0 1 0 0 0 0 0] [1 0 0 0 0 1 1 0 0 0] [1 0 0 1 0 0 0 1 0 0] @@ -174,7 +174,7 @@ def bandwidth(G, k=None): sage: G = graphs.ChvatalGraph() sage: bandwidth(G) (6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) - sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # optional - sage.modules + sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # needs sage.modules [0 0 1 1 0 1 1 0 0 0 0 0] [0 0 0 1 1 1 0 1 0 0 0 0] [1 0 0 0 1 0 0 1 1 0 0 0] diff --git a/src/sage/graphs/graph_decompositions/cutwidth.pyx b/src/sage/graphs/graph_decompositions/cutwidth.pyx index 440d80ee2f6..208bd69dea4 100644 --- a/src/sage/graphs/graph_decompositions/cutwidth.pyx +++ b/src/sage/graphs/graph_decompositions/cutwidth.pyx @@ -372,7 +372,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G = Graph([(0, 1)]) sage: cutwidth(G, algorithm="exponential") (1, [0, 1]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [0, 1]) Cutwidth of a disconnected graph:: @@ -382,7 +382,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G.add_edge(2, 3) sage: cutwidth(G, algorithm="exponential") (1, [2, 3, 0, 1, 4]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [2, 3, 0, 1, 4]) """ from sage.graphs.graph import Graph @@ -643,9 +643,9 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CycleGraph(5) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 2 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe 2 @@ -654,18 +654,18 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CompleteGraph(4) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 4 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True Cutwidth of a Path graph:: sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.PathGraph(3) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 1 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True TESTS: @@ -673,7 +673,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import cutwidth - sage: for i in range(2): # long time + sage: for i in range(2): # long time # needs sage.numerical.mip ....: G = graphs.RandomGNP(7, 0.3) ....: ve, le = cutwidth.cutwidth_dyn(G) ....: vm, lm = cutwidth.cutwidth_MILP(G, solver='GLPK') @@ -684,7 +684,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth_MILP sage: G = graphs.CycleGraph(3) - sage: cutwidth_MILP(G, lower_bound=G.size()+1) + sage: cutwidth_MILP(G, lower_bound=G.size()+1) # needs sage.numerical.mip Traceback (most recent call last): ... MIPSolverException: ... diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pyx b/src/sage/graphs/graph_decompositions/fast_digraph.pyx index fd75e5e63c3..3d7c4b2fea7 100644 --- a/src/sage/graphs/graph_decompositions/fast_digraph.pyx +++ b/src/sage/graphs/graph_decompositions/fast_digraph.pyx @@ -41,7 +41,7 @@ cdef class FastDigraph: ....: 'cdef FastDigraph F = FastDigraph(G)', ....: 'cdef int i', ....: 'print([F.degree[i] for i in range(F.n)])'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython [1, 2, 1] """ if D.order() > 8*sizeof(int): @@ -98,7 +98,7 @@ cdef class FastDigraph: ....: 'from sage.graphs.graph import Graph', ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph', ....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython 010 101 010 @@ -128,7 +128,7 @@ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S): ....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))', ....: 'cdef int i', ....: 'print([compute_out_neighborhood_cardinality(F, 1<> 1) & 0x55555555) @@ -198,7 +198,7 @@ cdef inline int slow_popcount32(int i): ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32', ....: 'cdef int i', ....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython True """ # Slow popcount for 32bits integers diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index 7042eabbfaf..31f49206586 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -206,8 +206,8 @@ def is_cartesian_product(g, certificate=False, relabeling=False): Wagner's Graph (:trac:`13599`):: - sage: g = graphs.WagnerGraph() # optional - networkx - sage: g.is_cartesian_product() # optional - networkx + sage: g = graphs.WagnerGraph() # needs networkx + sage: g.is_cartesian_product() # needs networkx False Empty and one-element graph (:trac:`19546`):: diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.py index 230525e00e1..7a0c71c2fb1 100644 --- a/src/sage/graphs/graph_decompositions/modular_decomposition.py +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.py @@ -610,7 +610,7 @@ def habib_maurer_algorithm(graph, g_classes=None): decompositions. :: sage: from sage.graphs.graph_decompositions.modular_decomposition import permute_decomposition - sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # optional - sage.groups + sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # needs sage.groups """ if graph.is_directed(): raise ValueError("Graph must be undirected") diff --git a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp index ad1e3fb1f03..3644edf6ac7 100644 --- a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp +++ b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp @@ -1,3 +1,5 @@ +// sage.setup: distribution = sagemath-tdlib + #include #include diff --git a/src/sage/graphs/graph_decompositions/tdlib.pyx b/src/sage/graphs/graph_decompositions/tdlib.pyx index 017b120abd3..ad3ded3e876 100644 --- a/src/sage/graphs/graph_decompositions/tdlib.pyx +++ b/src/sage/graphs/graph_decompositions/tdlib.pyx @@ -125,18 +125,20 @@ def treedecomposition_exact(G, lb=-1): EXAMPLES:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.HouseGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: T.show(vertex_size=2000) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.HouseGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: T.show(vertex_size=2000) TESTS:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.HouseGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: G = graphs.PetersenGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.HouseGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: G = graphs.PetersenGraph() + sage: T = tdlib.treedecomposition_exact(G) """ cdef vector[unsigned int] V_G, E_G, E_T @@ -175,10 +177,11 @@ def get_width(T): EXAMPLES:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.PetersenGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: tdlib.get_width(T) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.PetersenGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: tdlib.get_width(T) 4 """ return (max(len(x) for x in T) - 1) if T else -1 diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index bf6070e9c8f..90fb086e1ae 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -271,7 +271,6 @@ from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph, compute_ from libc.stdint cimport uint8_t from sage.data_structures.binary_matrix cimport * from sage.graphs.base.static_dense_graph cimport dense_graph_init -from sage.misc.decorators import rename_keyword ############### @@ -665,7 +664,7 @@ def path_decomposition(G, algorithm="BAB", cut_off=None, upper_bound=None, verbo 2 sage: pw, L = path_decomposition(g, algorithm = "exponential"); pw 2 - sage: pw, L = path_decomposition(g, algorithm = "MILP"); pw + sage: pw, L = path_decomposition(g, algorithm="MILP"); pw # needs sage.numerical.mip 2 TESTS: @@ -766,19 +765,22 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos Comparison of methods:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vs,L = vertex_separation(G, algorithm="BAB"); vs # optional - sage.combinat + + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 2 - sage: vs,L = vertex_separation(G, algorithm="exponential"); vs # optional - sage.combinat + sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 2 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # optional - sage.combinat + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 2 + sage: G = graphs.Grid2dGraph(3,3) sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 3 sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 3 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 3 Digraphs with multiple strongly connected components:: @@ -805,7 +807,7 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation sage: G = graphs.PetersenGraph() - sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt + sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt, needs sage.numerical.mip 5 TESTS: @@ -954,8 +956,8 @@ def vertex_separation_exp(G, verbose=False): Graphs with non-integer vertices:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation_exp - sage: D = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vertex_separation_exp(D) # optional - sage.combinat + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: vertex_separation_exp(D) # needs sage.combinat (2, ['000', '001', '100', '010', '101', '011', '110', '111']) Given a too large graph:: @@ -1210,13 +1212,14 @@ def width_of_path_decomposition(G, L): Path decomposition of a BalancedTree:: + sage: # needs networkx sage: from sage.graphs.graph_decompositions import vertex_separation - sage: G = graphs.BalancedTree(3,2) # optional - networkx - sage: pw, L = vertex_separation.path_decomposition(G) # optional - networkx - sage: pw == vertex_separation.width_of_path_decomposition(G, L) # optional - networkx + sage: G = graphs.BalancedTree(3,2) + sage: pw, L = vertex_separation.path_decomposition(G) + sage: pw == vertex_separation.width_of_path_decomposition(G, L) True - sage: L.reverse() # optional - networkx - sage: pw == vertex_separation.width_of_path_decomposition(G, L) # optional - networkx + sage: L.reverse() + sage: pw == vertex_separation.width_of_path_decomposition(G, L) False Directed path decomposition of a circuit:: @@ -1305,9 +1308,9 @@ def _vertex_separation_MILP_formulation(G, integrality=False, solver=None): EXAMPLES:: sage: from sage.graphs.graph_decompositions.vertex_separation import _vertex_separation_MILP_formulation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) # optional - sage.combinat - sage: p # optional - sage.combinat + sage: G = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) # needs sage.combinat sage.numerical.mip + sage: p # needs sage.combinat sage.numerical.mip Mixed Integer Program (minimization, 193 variables, 449 constraints) """ from sage.graphs.graph import Graph @@ -1373,7 +1376,6 @@ def _vertex_separation_MILP_formulation(G, integrality=False, solver=None): return p, x, u, y, z -@rename_keyword(deprecation=32222, verbosity='verbose') def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -1419,20 +1421,21 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Vertex separation of a De Bruijn digraph:: + sage: # needs sage.combinat sage: from sage.graphs.graph_decompositions import vertex_separation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # optional - sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 2 - sage: vs == vertex_separation.width_of_path_decomposition(G, L) # optional - sage.combinat + sage: vs == vertex_separation.width_of_path_decomposition(G, L) # needs sage.numerical.mip True - sage: vse, Le = vertex_separation.vertex_separation(G); vse # optional - sage.combinat + sage: vse, Le = vertex_separation.vertex_separation(G); vse 2 The vertex separation of a circuit is 1:: sage: from sage.graphs.graph_decompositions import vertex_separation sage: G = digraphs.Circuit(6) - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 1 TESTS: @@ -1440,7 +1443,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): + sage: for i in range(10): # needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: ve, le = vertex_separation.vertex_separation(G) ....: vm, lm = vertex_separation.vertex_separation_MILP(G) @@ -1450,7 +1453,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with different values of the integrality parameter:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): # long time (11s on sage.math, 2012) + sage: for i in range(10): # long time (11s on sage.math, 2012), needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: va, la = vertex_separation.vertex_separation_MILP(G, integrality=False) ....: vb, lb = vertex_separation.vertex_separation_MILP(G, integrality=True) @@ -1460,7 +1463,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: vertex_separation.vertex_separation_MILP([]) + sage: vertex_separation.vertex_separation_MILP([]) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the first input parameter must be a Graph or a DiGraph diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index ba6992f5070..f1d53f31e95 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -651,9 +651,9 @@ class GraphGenerators(): except for appropriately inheritable properties:: sage: property = lambda G: G.is_vertex_transitive() - sage: len(list(graphs(4, property))) + sage: len(list(graphs(4, property))) # needs sage.groups 1 - sage: sum(1 for g in graphs(4) if property(g)) + sage: sum(1 for g in graphs(4) if property(g)) # needs sage.groups 4 sage: property = lambda G: G.is_bipartite() @@ -1231,15 +1231,16 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr EXAMPLES:: - sage: g=graphs.cospectral_graphs(5) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dr?', 'Ds_']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs on six vertices with no isolated vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Ep__', 'Er?G'], ['ExGg', 'ExoG']] sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() @@ -1249,16 +1250,17 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr There is one pair of cospectral trees on eight vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=graphs.trees(8)) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(6, graphs=graphs.trees(8)) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['GiPC?C', 'GiQCC?']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:: - sage: g=graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Edq_', 'ErcG'], ['Exoo', 'EzcG']] sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() @@ -1278,10 +1280,12 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr ....: for i in range(g.order()): ....: A.rescale_row(i, 1 / len(A.nonzero_positions_in_row(i))) ....: return A - sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, graphs=lambda g: min(g.degree()) > 0) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, # needs sage.modules + ....: graphs=lambda g: min(g.degree()) > 0) + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dlg', 'Ds_']] - sage: g[0][1].laplacian_matrix(normalized=True).charpoly()==g[0][1].laplacian_matrix(normalized=True).charpoly() # optional - sage.symbolic + sage: (g[0][1].laplacian_matrix(normalized=True).charpoly() # needs sage.modules sage.symbolic + ....: == g[0][1].laplacian_matrix(normalized=True).charpoly()) True """ from sage.graphs.graph_generators import graphs as graph_gen @@ -1461,11 +1465,12 @@ def fullerenes(self, order, ipr=False): The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron graph. :: - sage: gen = graphs.fullerenes(20) # optional buckygen - sage: g = next(gen) # optional buckygen - sage: g.is_isomorphic(graphs.DodecahedralGraph()) # optional buckygen + sage: # optional - buckygen + sage: gen = graphs.fullerenes(20) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.DodecahedralGraph()) True - sage: g.get_embedding() # optional buckygen + sage: g.get_embedding() {1: [2, 3, 4], 2: [1, 5, 6], 3: [1, 7, 8], @@ -1486,7 +1491,7 @@ def fullerenes(self, order, ipr=False): 18: [12, 20, 13], 19: [14, 20, 15], 20: [17, 19, 18]} - sage: g.plot3d(layout='spring') # optional buckygen + sage: g.plot3d(layout='spring') Graphics3d Object """ # number of vertices should be positive @@ -1739,12 +1744,13 @@ def plantri_gen(self, options=""): (usually inside a loop). Or it can be used to create an entire list all at once if there is sufficient memory to contain it:: - sage: gen = graphs.plantri_gen("6") # optional plantri - sage: next(gen) # optional plantri + sage: # optional - plantri + sage: gen = graphs.plantri_gen("6") + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration @@ -1913,13 +1919,14 @@ def planar_graphs(self, order, minimum_degree=None, Specifying lower and upper bounds on the number of edges:: - sage: len(list(graphs.planar_graphs(4))) # optional plantri + sage: # optional - plantri + sage: len(list(graphs.planar_graphs(4))) 6 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) 2 Specifying the maximum size of a face:: @@ -1934,11 +1941,12 @@ def planar_graphs(self, order, minimum_degree=None, The number of edges in a planar graph is equal to the number of edges in its dual:: - sage: planar = list(graphs.planar_graphs(5,dual=True)) # optional -- plantri - sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) # optional -- plantri - sage: planar_sizes = [g.size() for g in planar] # optional -- plantri - sage: dual_planar_sizes = [g.size() for g in dual_planar] # optional -- plantri - sage: planar_sizes == dual_planar_sizes # optional -- plantri + sage: # optional - plantri + sage: planar = list(graphs.planar_graphs(5,dual=True)) + sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) + sage: planar_sizes = [g.size() for g in planar] + sage: dual_planar_sizes = [g.size() for g in dual_planar] + sage: planar_sizes == dual_planar_sizes True """ if order < 0: @@ -2260,11 +2268,12 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None The cube is the only 3-connected planar quadrangulation on 8 vertices:: - sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) # optional plantri - sage: g = next(gen) # optional plantri - sage: g.is_isomorphic(graphs.CubeGraph(3)) # optional plantri + sage: # optional - plantri + sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.CubeGraph(3)) True - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration diff --git a/src/sage/graphs/graph_generators_pyx.pyx b/src/sage/graphs/graph_generators_pyx.pyx index 716f4e5975a..060ea9275c6 100644 --- a/src/sage/graphs/graph_generators_pyx.pyx +++ b/src/sage/graphs/graph_generators_pyx.pyx @@ -55,8 +55,8 @@ def RandomGNP(n, p, bint directed=False, bint loops=False, seed=None): TESTS:: - sage: from numpy import mean # optional - numpy - sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 # optional - numpy + sage: from numpy import mean # needs numpy + sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 # needs numpy True sage: RandomGNP(150, .2, loops=True) Traceback (most recent call last): diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 39b22a44b56..193afc9c4eb 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -185,9 +185,9 @@ def from_seidel_adjacency_matrix(G, M): sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix sage: g = Graph() - sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # optional - sage.modules - sage: from_seidel_adjacency_matrix(g, sam) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # needs sage.modules + sage: from_seidel_adjacency_matrix(g, sam) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -236,8 +236,8 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_adjacency_matrix sage: g = Graph() - sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -312,8 +312,8 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_incidence_matrix sage: g = Graph() - sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -378,37 +378,37 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted sage: from sage.graphs.graph_input import from_oriented_incidence_matrix sage: g = DiGraph() - sage: im = digraphs.Circuit(10).incidence_matrix() # optional - sage.modules - sage: from_oriented_incidence_matrix(g, im) # optional - sage.modules - sage: g.is_isomorphic(digraphs.Circuit(10)) # optional - sage.modules + sage: im = digraphs.Circuit(10).incidence_matrix() # needs sage.modules + sage: from_oriented_incidence_matrix(g, im) # needs sage.modules + sage: g.is_isomorphic(digraphs.Circuit(10)) # needs sage.modules True TESTS: Fix bug reported in :trac:`22985`:: - sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # optional - sage.modules + sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # needs sage.modules Traceback (most recent call last): ... ValueError: each column represents an edge: -1 goes to 1 Handle incidence matrix containing a column with only zeros (:trac:`29275`):: - sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # optional - sage.modules + sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # needs sage.modules [ 0 1] [ 0 -1] [ 0 0] - sage: G = DiGraph(m, format='incidence_matrix') # optional - sage.modules - sage: list(G.edges(sort=True, labels=False)) # optional - sage.modules + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] Handle incidence matrix [[1],[-1]] (:trac:`29275`):: - sage: m = Matrix([[1],[-1]]); m # optional - sage.modules + sage: m = Matrix([[1],[-1]]); m # needs sage.modules [ 1] [-1] - sage: G = DiGraph(m, format='incidence_matrix') # optional - sage.modules - sage: list(G.edges(sort=True, labels=False)) # optional - sage.modules + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] """ from sage.structure.element import is_Matrix @@ -613,113 +613,121 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`Graph` with a NetworkX ``Graph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # optional - networkx + sage: import networkx sage: G = Graph() - sage: _ = gnx = networkx.Graph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(1, 2) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = gnx = networkx.Graph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (1, 2)] Feeding a :class:`Graph` with a NetworkX ``MultiGraph``:: + sage: # needs networkx sage: G = Graph() - sage: gnx = networkx.MultiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: gnx = networkx.MultiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] sage: G = Graph() - sage: from_networkx_graph(G, gnx, multiedges=False) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both:: + sage: # needs networkx sage: G = Graph() - sage: D = networkx.DiGraph() # optional - networkx - sage: _ = D.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: D = networkx.DiGraph() + sage: _ = D.add_edge(0, 1) + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1)] sage: G = Graph() - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = D.add_edge(1, 0) + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``MultiDiGraph`` `D`, the number of edges between `u` and `v` in `G` is the maximum between the number of arcs `(u, v)` and the number of arcs `(v, u)` in D`:: + sage: # needs networkx sage: G = Graph() - sage: D = networkx.MultiDiGraph() # optional - networkx - sage: _ = D.add_edge(0, 1) # optional - networkx - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: D.edges() # optional - networkx + sage: D = networkx.MultiDiGraph() + sage: _ = D.add_edge(0, 1) + sage: _ = D.add_edge(1, 0) + sage: _ = D.add_edge(1, 0) + sage: D.edges() OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)]) - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # optional - networkx + sage: import networkx sage: G = DiGraph() - sage: _ = gnx = networkx.DiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(1, 2) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = gnx = networkx.DiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (1, 2)] Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``:: + sage: # needs networkx sage: G = DiGraph() - sage: gnx = networkx.MultiDiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: gnx = networkx.MultiDiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] sage: G = DiGraph() - sage: from_networkx_graph(G, gnx, multiedges=False) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`:: + sage: # needs networkx sage: G = DiGraph() - sage: H = networkx.Graph() # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, H) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: H = networkx.Graph() + sage: _ = H.add_edge(0, 1) + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) [(0, 1), (1, 0)] When feeding a :class:`DiGraph` `G` with a NetworkX ``MultiGraph`` `H`, `G` has `k` arcs `(u, v)` and `k` arcs `(v, u)` if `H` has `k` edges `(u, v)`, unless parameter ``multiedges`` is set to ``False``:: + sage: # needs networkx sage: G = DiGraph() - sage: H = networkx.MultiGraph() # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: H.edges() # optional - networkx + sage: H = networkx.MultiGraph() + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: H.edges() MultiEdgeDataView([(0, 1), (0, 1), (0, 1)]) - sage: from_networkx_graph(G, H) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) [(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)] sage: G = DiGraph() - sage: from_networkx_graph(G, H, multiedges=False) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: from_networkx_graph(G, H, multiedges=False) + sage: G.edges(labels=False, sort=True) [(0, 1), (1, 0)] TESTS: @@ -736,7 +744,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, ``DiGraph`` or ``MultiDiGraph``:: sage: from sage.graphs.graph_input import from_networkx_graph - sage: from_networkx_graph(Graph(), "bar") # optional - networkx + sage: from_networkx_graph(Graph(), "bar") # needs networkx Traceback (most recent call last): ... ValueError: the second parameter must be a NetworkX (Multi)(Di)Graph diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 7666151fb50..e495ca160a4 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -84,12 +84,12 @@ sage: H = graphs.HeawoodGraph() sage: H.set_latex_options( - ....: graphic_size=(5,5), - ....: vertex_size=0.2, - ....: edge_thickness=0.04, - ....: edge_color='green', - ....: vertex_color='green', - ....: vertex_label_color='red' + ....: graphic_size=(5,5), + ....: vertex_size=0.2, + ....: edge_thickness=0.04, + ....: edge_color='green', + ....: vertex_color='green', + ....: vertex_label_color='red' ....: ) At this point, ``view(H)`` should call ``pdflatex`` to process the string @@ -265,49 +265,50 @@ package. So it is worth viewing this in the notebook to see the effects of various defaults and choices.:: - sage: var('x y u w') # optional - sage.symbolic + sage: # needs sage.symbolic + sage: var('x y u w') (x, y, u, w) sage: G = Graph(loops=True) - sage: for i in range(5): # optional - sage.symbolic + sage: for i in range(5): ....: for j in range(i+1, 5): ....: G.add_edge((i, j), label=(x^i*y^j).expand()) - sage: G.add_edge((0,0), label=sin(u)) # optional - sage.symbolic - sage: G.add_edge((4,4), label=w^5) # optional - sage.symbolic + sage: G.add_edge((0,0), label=sin(u)) + sage: G.add_edge((4,4), label=w^5) sage: G.set_pos(G.layout_circular()) sage: G.set_latex_options( - ....: units='in', - ....: graphic_size=(8,8), - ....: margins=(1,2,2,1), - ....: scale=0.5, - ....: vertex_color='0.8', - ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, - ....: vertex_fill_color='blue', - ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, - ....: vertex_label_color='brown', - ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, - ....: vertex_shape='diamond', - ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, - ....: vertex_size=0.3, - ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, - ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, - ....: edge_color='purple', - ....: edge_colors={(0,2):'g',(3,4):'red'}, - ....: edge_fills=True, - ....: edge_fill_color='green', - ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, - ....: edge_thickness=0.05, - ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, - ....: edge_labels=True, - ....: edge_label_sloped=True, - ....: edge_label_slopes={(0,3):False, (2,4):False}, - ....: edge_label_placement=0.50, - ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, - ....: loop_placement=(2.0, 'NO'), - ....: loop_placements={4:(8.0, 'EA')} + ....: units='in', + ....: graphic_size=(8,8), + ....: margins=(1,2,2,1), + ....: scale=0.5, + ....: vertex_color='0.8', + ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, + ....: vertex_fill_color='blue', + ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, + ....: vertex_label_color='brown', + ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, + ....: vertex_shape='diamond', + ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, + ....: vertex_size=0.3, + ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, + ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, + ....: edge_color='purple', + ....: edge_colors={(0,2):'g',(3,4):'red'}, + ....: edge_fills=True, + ....: edge_fill_color='green', + ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, + ....: edge_thickness=0.05, + ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, + ....: edge_labels=True, + ....: edge_label_sloped=True, + ....: edge_label_slopes={(0,3):False, (2,4):False}, + ....: edge_label_placement=0.50, + ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, + ....: loop_placement=(2.0, 'NO'), + ....: loop_placements={4:(8.0, 'EA')} ....: ) sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph() # random - depends on TeX installation - sage: print(latex(G)) # optional - sage.symbolic + sage: print(latex(G)) \begin{tikzpicture} \definecolor{cv0}{rgb}{0.8,0.8,0.8} \definecolor{cfv0}{rgb}{0.0,0.0,1.0} diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index 4a43987a79b..6994a821948 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -258,17 +258,17 @@ def to_graphics_array(graph_list, **kwds): sage: glist = [] sage: for i in range(999): ....: glist.append(graphs.RandomGNP(6, .45)) - sage: garray = graphs_list.to_graphics_array(glist) # optional - sage.plot - sage: garray.nrows(), garray.ncols() # optional - sage.plot + sage: garray = graphs_list.to_graphics_array(glist) # needs sage.plot + sage: garray.nrows(), garray.ncols() # needs sage.plot (250, 4) See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): # optional - networkx + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) # optional - networkx sage.plot + sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) # needs networkx sage.plot Graphics Array of size 3 x 4 """ from sage.graphs import graph @@ -342,7 +342,7 @@ def show_graphs(graph_list, **kwds): Show the graphs in a graphics array:: - sage: graphs_list.show_graphs(glist) # optional - sage.plot + sage: graphs_list.show_graphs(glist) # needs sage.plot Example where more than one graphics array is used:: @@ -350,15 +350,15 @@ def show_graphs(graph_list, **kwds): sage: g = gq.get_graphs_list() sage: len(g) 34 - sage: graphs_list.show_graphs(g) # optional - sage.plot + sage: graphs_list.show_graphs(g) # needs sage.plot See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) # optional - sage.plot + sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) # needs sage.plot """ graph_list = list(graph_list) for i in range(len(graph_list) // 20 + 1): diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index ad846d7a474..3bcabb58152 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -164,24 +164,25 @@ def gen_html_code(G, EXAMPLES:: - sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage.plot + sage: graphs.RandomTree(50).show(method="js") # optional - internet, needs sage.plot sage: g = graphs.PetersenGraph() - sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet sage.plot + sage: g.show(method="js", vertex_partition=g.coloring()) # optional - internet, needs sage.plot - sage: graphs.DodecahedralGraph().show(method="js", # optional -- internet sage.plot + sage: graphs.DodecahedralGraph().show(method="js", # optional - internet, needs sage.plot ....: force_spring_layout=True) - sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage.plot - - sage: g = digraphs.DeBruijn(2, 2) # optional - sage.combinat - sage: g.allow_multiple_edges(True) # optional - sage.combinat - sage: g.add_edge("10", "10", "a") # optional - sage.combinat - sage: g.add_edge("10", "10", "b") # optional - sage.combinat - sage: g.add_edge("10", "10", "c") # optional - sage.combinat - sage: g.add_edge("10", "10", "d") # optional - sage.combinat - sage: g.add_edge("01", "11", "1") # optional - sage.combinat - sage: g.show(method="js", vertex_labels=True,edge_labels=True, # optional - sage.combinat sage.plot + sage: graphs.DodecahedralGraph().show(method="js") # optional - internet, needs sage.plot + + sage: # needs sage.combinat + sage: g = digraphs.DeBruijn(2, 2) + sage: g.allow_multiple_edges(True) + sage: g.add_edge("10", "10", "a") + sage: g.add_edge("10", "10", "b") + sage: g.add_edge("10", "10", "c") + sage: g.add_edge("10", "10", "d") + sage: g.add_edge("01", "11", "1") + sage: g.show(method="js", vertex_labels=True, edge_labels=True, # optional - internet, needs sage.plot ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], ....: edge_thickness=4) diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index c3e42da9565..3d6a7d28cd6 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -217,7 +217,7 @@ def CompleteUniform(self, n, k): sage: h = hypergraphs.CompleteUniform(5, 2); h Incidence structure with 5 points and 10 blocks - sage: len(h.packing()) + sage: len(h.packing()) # needs sage.numerical.mip 2 """ from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -306,34 +306,35 @@ def BinomialRandomUniform(self, n, k, p): EXAMPLES:: - sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() # needs numpy 19600 - sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() # needs numpy 0 TESTS:: - sage: hypergraphs.BinomialRandomUniform(50, 3, -0.1) # optional - numpy + sage: # needs numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, -0.1) Traceback (most recent call last): ... ValueError: edge probability should be in [0,1] - sage: hypergraphs.BinomialRandomUniform(50, 3, 1.1) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 1.1) Traceback (most recent call last): ... ValueError: edge probability should be in [0,1] - sage: hypergraphs.BinomialRandomUniform(-50, 3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(-50, 3, 0.17) Traceback (most recent call last): ... ValueError: number of vertices should be non-negative - sage: hypergraphs.BinomialRandomUniform(50.9, 3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50.9, 3, 0.17) Traceback (most recent call last): ... ValueError: number of vertices should be an integer - sage: hypergraphs.BinomialRandomUniform(50, -3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, -3, 0.17) Traceback (most recent call last): ... ValueError: the uniformity should be non-negative - sage: hypergraphs.BinomialRandomUniform(50, I, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, I, 0.17) Traceback (most recent call last): ... ValueError: the uniformity should be an integer diff --git a/src/sage/graphs/independent_sets.pyx b/src/sage/graphs/independent_sets.pyx index d894f1706ed..23c8677b34a 100644 --- a/src/sage/graphs/independent_sets.pyx +++ b/src/sage/graphs/independent_sets.pyx @@ -162,7 +162,7 @@ cdef class IndependentSets: ....: IS2.extend(map(Set, list(G.subgraph_search_iterator(Graph(n), induced=True, return_graphs=False)))) ....: if len(IS) != len(set(IS2)): ....: raise ValueError("something goes wrong") - sage: for i in range(5): + sage: for i in range(5): # needs sage.modules ....: check_with_subgraph_search(graphs.RandomGNP(11, .3)) Empty graph:: diff --git a/src/sage/graphs/isoperimetric_inequalities.pyx b/src/sage/graphs/isoperimetric_inequalities.pyx index b6dfa40d06d..1d01e311c1c 100644 --- a/src/sage/graphs/isoperimetric_inequalities.pyx +++ b/src/sage/graphs/isoperimetric_inequalities.pyx @@ -209,8 +209,8 @@ def edge_isoperimetric_number(g): In general, for `d`-regular graphs the edge-isoperimetric number is `d` times larger than the Cheeger constant of the graph:: - sage: g = graphs.RandomRegular(3, 10) # optional - networkx - sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # optional - networkx + sage: g = graphs.RandomRegular(3, 10) # needs networkx + sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # needs networkx True And the edge-isoperimetric constant of a disconnected graph is `0`:: diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 656c9c08909..a30055e891c 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -176,8 +176,8 @@ def is_line_graph(g, certificate=False): This is indeed the subgraph returned:: - sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # optional - sage.modules - sage: C.is_isomorphic(graphs.ClawGraph()) # optional - sage.modules + sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # needs sage.modules + sage: C.is_isomorphic(graphs.ClawGraph()) # needs sage.modules True The house graph is a line graph:: @@ -188,11 +188,12 @@ def is_line_graph(g, certificate=False): But what is the graph whose line graph is the house ?:: - sage: is_line, R, isom = g.is_line_graph(certificate=True) # optional - sage.modules - sage: R.sparse6_string() # optional - sage.modules + sage: # needs sage.modules + sage: is_line, R, isom = g.is_line_graph(certificate=True) + sage: R.sparse6_string() ':DaHI~' - sage: R.show() # optional - sage.modules sage.plot - sage: isom # optional - sage.modules + sage: R.show() # needs sage.plot + sage: isom {0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)} TESTS: @@ -201,8 +202,8 @@ def is_line_graph(g, certificate=False): sage: g = 2 * graphs.CycleGraph(3) sage: gl = g.line_graph().relabel(inplace=False) - sage: new_g = gl.is_line_graph(certificate=True)[1] # optional - sage.modules - sage: g.line_graph().is_isomorphic(gl) # optional - sage.modules + sage: new_g = gl.is_line_graph(certificate=True)[1] # needs sage.modules + sage: g.line_graph().is_isomorphic(gl) # needs sage.modules True Verify that :trac:`29740` is fixed:: @@ -314,7 +315,7 @@ def line_graph(g, labels=True): (1, 2, None), (1, 3, None), (2, 3, None)] - sage: h.am() # optional - sage.modules + sage: h.am() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -324,7 +325,7 @@ def line_graph(g, labels=True): sage: h2 = g.line_graph(labels=False) sage: h2.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: h2.am() == h.am() + sage: h2.am() == h.am() # needs sage.modules True sage: g = DiGraph([[1..4], lambda i,j: i < j]) sage: h = g.line_graph() diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 7845b225f9c..e98cc8d6b63 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -328,9 +328,9 @@ def complete_poly(n): Checking the numerical results up to 20:: - sage: from sage.functions.orthogonal_polys import hermite # optional - sage.symbolic - sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # optional - sage.symbolic - sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import hermite # needs sage.symbolic + sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # needs sage.symbolic + sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # needs sage.symbolic True """ # global complete_matching_polys # if we do eventually make it a C array... diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 4aeb71248b9..7b7fa8681fc 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -25,17 +25,31 @@ Methods ------- """ +# **************************************************************************** +# Copyright (C) 2017 Kolja Knauer +# 2017 Petru Valicov +# 2017-2023 David Coudert +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from copy import copy from sage.graphs.digraph import DiGraph def strong_orientations_iterator(G): r""" - Returns an iterator over all strong orientations of a graph `G`. + Return an iterator over all strong orientations of a graph `G`. - A strong orientation of a graph is an orientation of its edges such that - the obtained digraph is strongly connected (i.e. there exist a directed path - between each pair of vertices). + A strong orientation of a graph is an orientation of its edges such that the + obtained digraph is strongly connected (i.e. there exist a directed path + between each pair of vertices). According to Robbins' theorem (see the + :wikipedia:`Robbins_theorem`), the graphs that have strong orientations are + exactly the 2-edge-connected graphs (i.e., the bridgeless graphs). ALGORITHM: @@ -84,7 +98,7 @@ def strong_orientations_iterator(G): A tree cannot be strongly oriented:: - sage: g = graphs.RandomTree(100) + sage: g = graphs.RandomTree(10) sage: len(list(g.strong_orientations_iterator())) 0 @@ -115,44 +129,37 @@ def strong_orientations_iterator(G): sage: g = graphs.PetersenGraph() sage: nr1 = len(list(g.strong_orientations_iterator())) sage: nr2 = g.tutte_polynomial()(0,2) - sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations + sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations True - """ # if the graph has a bridge or is disconnected, # then it cannot be strongly oriented - if G.order() < 3 or not G.is_biconnected(): + if G.order() < 3 or not G.is_connected() or any(G.bridges(labels=False)): return - V = G.vertices(sort=False) - Dg = DiGraph([V, G.edges(sort=False)], pos=G.get_pos()) + V = list(G) # compute an arbitrary spanning tree of the undirected graph - te = G.min_spanning_tree() - treeEdges = [(u, v) for u, v, _ in te] - tree_edges_set = set(treeEdges) - A = [edge for edge in G.edge_iterator(labels=False) if edge not in tree_edges_set] + T = G.subgraph(vertices=G, edges=G.min_spanning_tree(), inplace=False) + treeEdges = list(T.edges(labels=False, sort=False)) + A = [edge for edge in G.edge_iterator(labels=False) if not T.has_edge(edge)] + + # Initialize a digraph with the edges of the spanning tree doubly oriented + Dg = T.to_directed(sparse=True) + Dg.add_edges(A) # initialization of the first binary word 00...0 # corresponding to the current orientation of the non-tree edges existingAedges = [0] * len(A) - # Make the edges of the spanning tree doubly oriented - for e in treeEdges: - if Dg.has_edge(e): - Dg.add_edge(e[1], e[0]) - else: - Dg.add_edge(e) - # Generate all orientations for non-tree edges (using Gray code) # Each of these orientations can be extended to a strong orientation # of G by orienting properly the tree-edges previousWord = 0 - i = 0 # the orientation of one edge is fixed so we consider one edge less nr = 2**(len(A) - 1) - while i < nr: + for i in range(nr): word = (i >> 1) ^ i bitChanged = word ^ previousWord @@ -169,9 +176,7 @@ def strong_orientations_iterator(G): Dg.reverse_edge(A[bit][1], A[bit][0]) existingAedges[bit] = 0 # launch the algorithm for enumeration of the solutions - for sol in _strong_orientations_of_a_mixed_graph(Dg, V, treeEdges): - yield sol - i = i + 1 + yield from _strong_orientations_of_a_mixed_graph(Dg, V, treeEdges) def _strong_orientations_of_a_mixed_graph(Dg, V, E): @@ -201,9 +206,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph sage: g = graphs.CycleGraph(5) - sage: Dg = DiGraph(g) # all edges of g will be doubly oriented + sage: Dg = DiGraph(g) # all edges of g will be doubly oriented sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edges(labels=False, sort=False))) - sage: len(list(it)) # there are two orientations of this multigraph + sage: len(list(it)) # there are two orientations of this multigraph 2 """ length = len(E) @@ -213,7 +218,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): u, v = E[i] Dg.delete_edge(u, v) if not (v in Dg.depth_first_search(u)): - del E[i] + # del E[i] in constant time + E[i] = E[-1] + E.pop() length -= 1 Dg.add_edge(u, v) Dg.delete_edge(v, u) @@ -222,7 +229,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): Dg.add_edge(u, v) Dg.delete_edge(v, u) if not (u in Dg.depth_first_search(v)): - del E[i] + # del E[i] in constant time + E[i] = E[-1] + E.pop() length -= 1 boundEdges.append((u, v)) Dg.delete_edge(u, v) diff --git a/src/sage/graphs/partial_cube.py b/src/sage/graphs/partial_cube.py index 0ec81f6b200..70456e548c9 100644 --- a/src/sage/graphs/partial_cube.py +++ b/src/sage/graphs/partial_cube.py @@ -110,8 +110,8 @@ def breadth_first_level_search(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) # optional - sage.combinat - sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # optional - sage.combinat + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # needs sage.combinat [{'00': {'01', '02'}}, {'01': {'10', '11', '12'}, '02': {'20', '21', '22'}}, {'10': set(), @@ -162,9 +162,9 @@ def depth_first_traversal(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) # optional - sage.combinat - sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # optional - sage.combinat - sage: len(t) # optional - sage.combinat + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # needs sage.combinat + sage: len(t) # needs sage.combinat 16 """ neighbors = G.neighbor_out_iterator diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 032ebd95ec2..0e5304bcae4 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -346,41 +346,49 @@ def shortest_simple_paths(self, source, target, weight_function=None, EXAMPLES:: - sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)]) + sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), + ....: (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Yen")) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 5, algorithm="Yen")) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 1)) [[1]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, report_weight=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True)) [(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] - sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) + sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), + ....: (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(g.shortest_simple_paths(1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(g.shortest_simple_paths(1, 6, algorithm="Yen")) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 6, + ....: report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], @@ -432,6 +440,8 @@ def shortest_simple_paths(self, source, target, weight_function=None, [1, 2, 3, 4, 5], [1, 6, 9, 3, 4, 5], [1, 6, 9, 11, 10, 5]] + + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 3) sage: for u,v in G.edges(sort=True, labels=False): ....: G.set_edge_label(u, v, 1) @@ -470,6 +480,7 @@ def shortest_simple_paths(self, source, target, weight_function=None, Check for consistency of results of Yen's and Feng's:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 4) sage: s = set() sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): diff --git a/src/sage/graphs/planarity.pyx b/src/sage/graphs/planarity.pyx index 839039a2bde..206095f00b2 100644 --- a/src/sage/graphs/planarity.pyx +++ b/src/sage/graphs/planarity.pyx @@ -30,7 +30,7 @@ cdef extern from "planarity/graph.h": cdef int gp_SortVertices(graphP theGraph) -def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular=None): +def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False): r""" Check whether ``g`` is planar using Boyer's planarity algorithm. @@ -55,8 +55,6 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= combinatorial embedding returned (see :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding`) - - ``circular`` -- deprecated argument - EXAMPLES:: sage: G = graphs.DodecahedralGraph() @@ -72,17 +70,18 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= vertices. In fact, to try to track down a segfault, we do it twice. :: - sage: import networkx.generators.atlas # long time # optional - networkx - sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] # long time # optional - networkx - sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time # optional - networkx - sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time # optional - networkx - sage: a == b # long time # optional - networkx + sage: # long time, needs networkx + sage: import networkx.generators.atlas + sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] + sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: a == b True There were some problems with ``set_pos`` stability in the past, so let's check if this runs without exception:: - sage: for i, g in enumerate(atlas_graphs): # long time # optional - networkx + sage: for i, g in enumerate(atlas_graphs): # long time # needs networkx ....: if (not g.is_connected() or i == 0): ....: continue ....: _ = g.is_planar(set_embedding=True, set_pos=True) @@ -97,10 +96,6 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= ....: assert (hasattr(G, '_pos') and G._pos is not None) == set_pos, (set_embedding, set_pos) """ - if circular is not None: - from sage.misc.superseded import deprecation - deprecation(33759, 'the circular argument of is_planar is deprecated and has no effect') - if set_pos and not g.is_connected(): raise ValueError("is_planar() cannot set vertex positions for a disconnected graph") diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index 5427a93691e..40f6d923656 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -743,7 +743,7 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): sage: newg = minimal_schnyder_wood(g) sage: newg.edges(sort=True) [(0, -3, 'red'), (0, -2, 'blue'), (0, -1, 'green')] - sage: newg.plot(color_by_label={'red':'red','blue':'blue', # optional - sage.plot + sage: newg.plot(color_by_label={'red':'red','blue':'blue', # needs sage.plot ....: 'green':'green',None:'black'}) Graphics object consisting of 8 graphics primitives diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 08f441d90a8..08f151a65ad 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -36,10 +36,8 @@ Methods from memory_allocator cimport MemoryAllocator from sage.sets.disjoint_set cimport DisjointSet_of_hashables -from sage.misc.decorators import rename_keyword -@rename_keyword(deprecation=32805, wfunction='weight_function') def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=False): r""" Minimum spanning tree using Kruskal's algorithm. @@ -196,6 +194,7 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F The input graph must be connected. :: + sage: # long time sage: def my_disconnected_graph(n, ntries, directed=False, multiedges=False, loops=False): ....: G = Graph() ....: k = randint(2, n) @@ -216,14 +215,14 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F ....: v = randint(0, k-1) ....: G.delete_edge(u, v) ....: return G - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) + sage: kruskal(G, check=True) [] If the input graph is a tree, then return its edges:: @@ -242,19 +241,11 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F Traceback (most recent call last): ... ValueError: the input graph must be undirected - - Rename warning for parameter ``wfunction`` (:trac:`32805`):: - - sage: kruskal(Graph(1), wfunction=lambda e: 2) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] """ return list(kruskal_iterator(G, by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, check=check)) -@rename_keyword(deprecation=32805, wfunction='weight_function') def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False, bint check=False): """ Return an iterator implementation of Kruskal algorithm. @@ -322,13 +313,6 @@ def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False Traceback (most recent call last): ... ValueError: the input graph must be undirected - - Rename warning for parameter ``wfunction`` (:trac:`32805`):: - - sage: list(kruskal_iterator(Graph(1), wfunction=lambda e: 2)) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] """ from sage.graphs.graph import Graph if not isinstance(G, Graph): @@ -356,7 +340,6 @@ def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False check_weight=False) -@rename_keyword(deprecation=32805, weighted='by_weight') def kruskal_iterator_from_edges(edges, union_find, by_weight=True, weight_function=None, check_weight=False): """ @@ -399,18 +382,6 @@ def kruskal_iterator_from_edges(edges, union_find, by_weight=True, sage: union_set = DisjointSet(G) sage: next(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_weight=G.weighted())) (1, 6, 10) - - TESTS: - - Rename warning for parameter ``weighted`` (:trac:`32805`):: - - sage: from sage.graphs.spanning_tree import kruskal_iterator_from_edges - sage: G = Graph([(0, 1)]) - sage: union_set = DisjointSet(G) - sage: next(kruskal_iterator_from_edges(G.edges(sort=True), union_set, weighted=False)) - doctest:...: DeprecationWarning: use the option 'by_weight' instead of 'weighted' - See https://github.com/sagemath/sage/issues/32805 for details. - (0, 1, None) """ # We sort edges, as specified. if weight_function is not None: @@ -568,12 +539,13 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= The weights of the spanning trees returned by :func:`kruskal_iterator` and :func:`filter_kruskal_iterator` are the same:: + sage: # needs networkx sage: from sage.graphs.spanning_tree import kruskal_iterator - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: for u, v in G.edge_iterator(labels=False): # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) + sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) - sage: G.weighted(True) # optional - networkx - sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] # optional - networkx + sage: G.weighted(True) + sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] ....: for e in filter_kruskal_iterator(G, threshold=20)) True @@ -696,7 +668,6 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= stack.append((begin, i - 1)) -@rename_keyword(deprecation=32805, wfunction='weight_function') def boruvka(G, by_weight=True, weight_function=None, check_weight=True, check=False): r""" Minimum spanning tree using Boruvka's algorithm. @@ -805,13 +776,6 @@ def boruvka(G, by_weight=True, weight_function=None, check_weight=True, check=Fa Traceback (most recent call last): ... ValueError: the input graph must be undirected - - Rename warning for parameter ``wfunction`` (:trac:`32805`):: - - sage: boruvka(Graph(1), wfunction=lambda e: 2) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] """ from sage.graphs.graph import Graph if not isinstance(G, Graph): @@ -976,7 +940,7 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct sage: pos = G.get_pos() sage: T = G.random_spanning_tree(True) sage: T.set_pos(pos) - sage: T.show(vertex_labels=False) # optional - sage.plot + sage: T.show(vertex_labels=False) # needs sage.plot We can also use edge weights to change the probability of returning a spanning tree:: @@ -1000,11 +964,12 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct Check that the spanning tree returned when using weights is a tree:: - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: for u, v in G.edge_iterator(labels=False): # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) + sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) - sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True) # optional - networkx - sage: T.is_tree() # optional - networkx + sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True) + sage: T.is_tree() True TESTS:: @@ -1088,12 +1053,12 @@ def spanning_trees(g, labels=False): sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)], multiedges=True) sage: len(list(G.spanning_trees())) 8 - sage: G.spanning_trees_count() # optional - sage.modules + sage: G.spanning_trees_count() # needs sage.modules 8 sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)], multiedges=True) sage: len(list(G.spanning_trees())) 6 - sage: G.spanning_trees_count() # optional - sage.modules + sage: G.spanning_trees_count() # needs sage.modules 6 .. SEEALSO:: diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3d48b45e58d..ae7eee6f4ea 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -70,9 +70,9 @@ def is_paley(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_paley sage: t = is_paley(13,6,2,3); t (..., 13) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Paley graph with parameter 13: Graph on 13 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (13, 6, 2, 3) sage: t = is_paley(5,5,5,5); t """ @@ -110,18 +110,18 @@ def is_mathon_PC_srg(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_mathon_PC_srg - sage: t = is_mathon_PC_srg(45,22,10,11); t + sage: t = is_mathon_PC_srg(45,22,10,11); t # needs sage.libs.pari (..., 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 22, 10, 11) TESTS:: - sage: t = is_mathon_PC_srg(5,5,5,5); t - sage: mu = 1895 # t=5 case -- the construction cannot work - sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t + sage: t = is_mathon_PC_srg(5,5,5,5); t # needs sage.libs.pari + sage: mu = 1895 # t=5 case -- the construction cannot work # needs sage.libs.pari + sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t # needs sage.libs.pari """ cdef int t if (v % 4 == 1 and @@ -162,6 +162,7 @@ def is_muzychuk_S6(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_muzychuk_S6 sage: t = is_muzychuk_S6(378, 116, 34, 36) sage: G = t[0](*t[1:]); G @@ -211,6 +212,7 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph sage: t = is_orthogonal_array_block_graph(64, 35, 18, 20); t (..., 5, 8) @@ -218,20 +220,20 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): OA(5,8): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) - sage: t=is_orthogonal_array_block_graph(225,98,43,42); t + sage: t = is_orthogonal_array_block_graph(225,98,43,42); t (..., 4) sage: g = t[0](*t[1:]); g Pasechnik Graph_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 98, 43, 42) - sage: t=is_orthogonal_array_block_graph(225,112,55,56); t + sage: t = is_orthogonal_array_block_graph(225,112,55,56); t (..., 4) sage: g = t[0](*t[1:]); g skewhad^2_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: t = is_orthogonal_array_block_graph(5,5,5,5); t + sage: t = is_orthogonal_array_block_graph(5,5,5,5); t # needs sage.combinat sage.modules """ # notations from # https://www.win.tue.nl/~aeb/graphs/OA.html @@ -356,11 +358,11 @@ def is_affine_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_affine_polar - sage: t = is_affine_polar(81,32,13,12); t + sage: t = is_affine_polar(81,32,13,12); t # needs sage.rings.finite_rings (..., 4, 3) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Affine Polar Graph VO^+(4,3): Graph on 81 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (81, 32, 13, 12) sage: t = is_affine_polar(5,5,5,5); t @@ -413,12 +415,12 @@ def is_orthogonal_polar(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_orthogonal_polar sage: t = is_orthogonal_polar(85, 20, 3, 5); t (, 5, 4, '') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Orthogonal Polar Graph O(5, 4): Graph on 85 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (85, 20, 3, 5) - sage: t = is_orthogonal_polar(5,5,5,5); t + sage: t = is_orthogonal_polar(5,5,5,5); t # needs sage.rings.finite_rings TESTS: @@ -428,7 +430,7 @@ def is_orthogonal_polar(int v, int k, int l, int mu): (, 5, 4, '') sage: is_orthogonal_polar(119,54,21,27) (, 8, 2, '-') - sage: is_orthogonal_polar(130,48,20,16) + sage: is_orthogonal_polar(130,48,20,16) # needs sage.rings.finite_rings (, 6, 3, '+') """ @@ -487,25 +489,26 @@ def is_goethals_seidel(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_goethals_seidel - sage: t = is_goethals_seidel(28, 15, 6, 10); t + sage: t = is_goethals_seidel(28, 15, 6, 10); t # needs sage.combinat sage.modules [, 3, 3] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 28 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (28, 15, 6, 10) - sage: t = is_goethals_seidel(256, 135, 70, 72); t + sage: t = is_goethals_seidel(256, 135, 70, 72); t # needs sage.combinat sage.modules [, 2, 15] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 256 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (256, 135, 70, 72) - sage: t = is_goethals_seidel(5,5,5,5); t + sage: t = is_goethals_seidel(5,5,5,5); t # needs sage.combinat sage.modules TESTS:: - sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), (64, 35, 18, 20), (120, 63, 30, 36), + sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), # needs sage.combinat sage.modules + ....: (64, 35, 18, 20), (120, 63, 30, 36), ....: (144, 77, 40, 42), (256, 135, 70, 72), (400, 209, 108, 110), ....: (496, 255, 126, 136), (540, 275, 130, 150), (576, 299, 154, 156), ....: (780, 399, 198, 210), (784, 405, 208, 210), (976, 495, 238, 264)]: @@ -567,26 +570,27 @@ def is_NOodd(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOodd - sage: t = is_NOodd(120, 51, 18, 24); t + sage: t = is_NOodd(120, 51, 18, 24); t # needs sage.libs.pari (, 5, 4, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(5, 4): Graph on 120 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (120, 51, 18, 24) TESTS: All of ``NO^+(2m+1,q)`` and ``NO^-(2m+1,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_NOodd(120, 51, 18, 24); t (, 5, 4, '-') sage: t = is_NOodd(136, 75, 42, 40); t (, 5, 4, '+') - sage: t=is_NOodd(378, 260, 178, 180); t + sage: t = is_NOodd(378, 260, 178, 180); t (, 7, 3, '+') - sage: t=is_NOodd(45, 32, 22, 24); t + sage: t = is_NOodd(45, 32, 22, 24); t (, 5, 3, '+') - sage: t=is_NOodd(351, 224, 142, 144); t + sage: t = is_NOodd(351, 224, 142, 144); t (, 7, 3, '-') sage: t = is_NOodd(325, 144, 68, 60); t (, 5, 5, '+') @@ -637,22 +641,22 @@ def is_NOperp_F5(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOperp_F5 - sage: t = is_NOperp_F5(10, 3, 0, 1); t + sage: t = is_NOperp_F5(10, 3, 0, 1); t # needs sage.libs.pari (, 3, 5, '-', 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+,perp(2m+1,5)`` and ``NO^-,perp(2m+1,5)`` appear:: - sage: t = is_NOperp_F5(325, 60, 15, 10); t + sage: t = is_NOperp_F5(325, 60, 15, 10); t # needs sage.libs.pari (, 5, 5, '+', 1) - sage: t = is_NOperp_F5(300, 65, 10, 15); t + sage: t = is_NOperp_F5(300, 65, 10, 15); t # needs sage.libs.pari (, 5, 5, '-', 1) - sage: t = is_NOperp_F5(5,5,5,5); t + sage: t = is_NOperp_F5(5,5,5,5); t # needs sage.libs.pari """ cdef int n r, s = eigenvalues(v, k, l, mu) # 2*e*5**(n-1), -e*5**(n-1); note exceptional case n=1 @@ -692,22 +696,22 @@ def is_NO_F2(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F2 - sage: t = is_NO_F2(10, 3, 0, 1); t + sage: t = is_NO_F2(10, 3, 0, 1); t # needs sage.libs.pari (, 4, 2, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+(2m,2)`` and ``NO^-(2m,2)`` appear:: - sage: t = is_NO_F2(36, 15, 6, 6); t + sage: t = is_NO_F2(36, 15, 6, 6); t # needs sage.libs.pari (, 6, 2, '-') - sage: t = is_NO_F2(28, 15, 6, 10); t + sage: t = is_NO_F2(28, 15, 6, 10); t # needs sage.libs.pari (, 6, 2, '+') - sage: t = is_NO_F2(5,5,5,5); t + sage: t = is_NO_F2(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p p, n = is_prime_power(k+1, get_data=True) # k+1==2**(2*n-2) @@ -743,22 +747,22 @@ def is_NO_F3(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F3 - sage: t = is_NO_F3(15, 6, 1, 3); t + sage: t = is_NO_F3(15, 6, 1, 3); t # needs sage.libs.pari (, 4, 3, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 3): Graph on 15 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (15, 6, 1, 3) TESTS: All of ``NO^+(2m,3)`` and ``NO^-(2m,3)`` appear:: - sage: t = is_NO_F3(126, 45, 12, 18); t + sage: t = is_NO_F3(126, 45, 12, 18); t # needs sage.libs.pari (, 6, 3, '-') - sage: t = is_NO_F3(117, 36, 15, 9); t + sage: t = is_NO_F3(117, 36, 15, 9); t # needs sage.libs.pari (, 6, 3, '+') - sage: t = is_NO_F3(5,5,5,5); t + sage: t = is_NO_F3(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p r, s = eigenvalues(v, k, l, mu) # e*3**(n-1), -e*3**(n-2) @@ -799,15 +803,16 @@ def is_NU(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NU - sage: t = is_NU(40, 27, 18, 18); t + sage: t = is_NU(40, 27, 18, 18); t # needs sage.libs.pari (, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NU(4, 2): Graph on 40 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (40, 27, 18, 18) TESTS:: + sage: # needs sage.libs.pari sage: t = is_NU(176, 135, 102, 108); t (, 5, 2) sage: t = is_NU(540, 224, 88, 96); t @@ -866,16 +871,16 @@ def is_haemers(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_haemers - sage: t = is_haemers(96, 19, 2, 4); t + sage: t = is_haemers(96, 19, 2, 4); t # needs sage.libs.pari (, 4) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (96, 19, 2, 4) TESTS:: - sage: t = is_haemers(5,5,5,5); t + sage: t = is_haemers(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p p, n = is_prime_power(mu, get_data=True) @@ -908,20 +913,20 @@ def is_cossidente_penttila(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_cossidente_penttila - sage: t = is_cossidente_penttila(378, 52, 1, 8); t + sage: t = is_cossidente_penttila(378, 52, 1, 8); t # needs sage.libs.pari (, 5) - sage: g = t[0](*t[1:]); g # optional - gap_packages + sage: g = t[0](*t[1:]); g # optional - gap_package_design, needs sage.libs.pari CossidentePenttila(5): Graph on 378 vertices - sage: g.is_strongly_regular(parameters=True) # optional - gap_packages + sage: g.is_strongly_regular(parameters=True) # optional - gap_package_design, needs sage.libs.pari (378, 52, 1, 8) TESTS:: - sage: t = is_cossidente_penttila(56,10,0,2); t + sage: t = is_cossidente_penttila(56,10,0,2); t # needs sage.libs.pari (, 3) - sage: t = is_cossidente_penttila(1376,150,2,18); t + sage: t = is_cossidente_penttila(1376,150,2,18); t # needs sage.libs.pari (, 7) - sage: t = is_cossidente_penttila(5,5,5,5); t + sage: t = is_cossidente_penttila(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p q = 2*l + 3 @@ -1008,12 +1013,13 @@ def is_polhill(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.graphs.strongly_regular_db import is_polhill sage: t = is_polhill(1024, 231, 38, 56); t [. at ...>] - sage: g = t[0](*t[1:]); g # not tested (too long) + sage: g = t[0](*t[1:]); g # not tested (too long) Graph on 1024 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (too long) + sage: g.is_strongly_regular(parameters=True) # not tested (too long) (1024, 231, 38, 56) sage: t = is_polhill(1024, 264, 56, 72); t [. at ...>] @@ -1156,11 +1162,11 @@ def is_RSHCD(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_RSHCD - sage: t = is_RSHCD(64,27,10,12); t + sage: t = is_RSHCD(64,27,10,12); t # needs sage.combinat sage.modules [, 64, 27, 10, 12] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (64, 27, 10, 12) """ if SRG_from_RSHCD(v, k, l, mu, existence=True) is True: @@ -1191,26 +1197,27 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): some graphs :: sage: from sage.graphs.strongly_regular_db import SRG_from_RSHCD - sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) + sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) # needs sage.combinat sage.modules False - sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) + sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) # needs sage.combinat sage.modules True - sage: SRG_from_RSHCD(144, 65, 28, 30) + sage: SRG_from_RSHCD(144, 65, 28, 30) # needs sage.combinat sage.modules Graph on 144 vertices an example with vertex-transitive automorphism group, found during the implementation of the case `v=324` :: - sage: G=SRG_from_RSHCD(324,152,70,72) # long time - sage: a=G.automorphism_group() # long time - sage: a.order() # long time + sage: # long time, needs sage.combinat sage.modules + sage: G = SRG_from_RSHCD(324,152,70,72) + sage: a = G.automorphism_group() + sage: a.order() 2592 - sage: len(a.orbits()) # long time + sage: len(a.orbits()) 1 TESTS:: - sage: SRG_from_RSHCD(784, 0, 14, 38) + sage: SRG_from_RSHCD(784, 0, 14, 38) # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD @@ -1267,19 +1274,20 @@ def is_unitary_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_unitary_polar - sage: t = is_unitary_polar(45, 12, 3, 3); t + sage: t = is_unitary_polar(45, 12, 3, 3); t # needs sage.libs.pari (, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 12, 3, 3) - sage: t = is_unitary_polar(5,5,5,5); t + sage: t = is_unitary_polar(5,5,5,5); t # needs sage.libs.pari TESTS: All the ``U(n,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_unitary_polar(45, 12, 3, 3); t (, 4, 2) sage: t = is_unitary_polar(165, 36, 3, 9); t @@ -1342,6 +1350,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_unitary_dual_polar sage: t = is_unitary_dual_polar(297, 40, 7, 5); t (, 5, 2) @@ -1353,7 +1362,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): TESTS:: - sage: is_unitary_dual_polar(6832, 270, 26, 10) + sage: is_unitary_dual_polar(6832, 270, 26, 10) # needs sage.libs.pari (, 5, 3) """ r, s = eigenvalues(v, k, l, mu) @@ -1392,6 +1401,7 @@ def is_GQqmqp(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_GQqmqp sage: t = is_GQqmqp(27,10,1,5); t (, 3, False) @@ -1418,16 +1428,17 @@ def is_GQqmqp(int v, int k, int l, int mu): TESTS:: - sage: (S,T)=(127,129) + sage: # needs sage.libs.pari + sage: (S,T) = (127,129) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 128, False) - sage: (S,T)=(129,127) + sage: (S,T) = (129,127) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 128, True) - sage: (S,T)=(124,126) + sage: (S,T) = (124,126) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 125, False) - sage: (S,T)=(126,124) + sage: (S,T) = (126,124) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 125, True) sage: t = is_GQqmqp(5,5,5,5); t @@ -1484,19 +1495,19 @@ def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg - sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t + sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t # needs sage.rings.finite_rings (.la at... - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (27, 10, 1, 5) sage: t = is_twograph_descendant_of_srg(5,5,5,5); t TESTS:: - sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) + sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) # needs sage.combinat True - sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_packages internet + sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_package_design internet (279, 150, 85, 75) """ cdef int b, k, s @@ -1545,6 +1556,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_taylor_twograph_srg sage: t = is_taylor_twograph_srg(28, 15, 6, 10); t (, 3) @@ -1556,7 +1568,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): TESTS:: - sage: is_taylor_twograph_srg(730, 369, 168, 205) + sage: is_taylor_twograph_srg(730, 369, 168, 205) # needs sage.libs.pari (, 9) """ @@ -1595,13 +1607,13 @@ def is_switch_skewhad(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(226, 105, 48, 49) + sage: graphs.strongly_regular_graph(226, 105, 48, 49) # needs sage.combinat sage.modules switch skewhad^2+*_4: Graph on 226 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_skewhad - sage: t = is_switch_skewhad(5,5,5,5); t + sage: t = is_switch_skewhad(5,5,5,5); t # needs sage.combinat sage.modules """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix @@ -1642,22 +1654,22 @@ def is_switch_OA_srg(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest + sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest # needs sage.combinat sage.modules Graph on 170 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg sage: t = is_switch_OA_srg(5,5,5,5); t - sage: t = is_switch_OA_srg(170, 78, 35, 36) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(170, 78, 35, 36) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (170, 78, 35, 36) - sage: t = is_switch_OA_srg(290, 136, 63, 64) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(290, 136, 63, 64) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (290, 136, 63, 64) - sage: is_switch_OA_srg(626, 300, 143, 144) + sage: is_switch_OA_srg(626, 300, 143, 144) # needs sage.schemes (.switch_OA_srg at ..., 12, 25) - sage: is_switch_OA_srg(842, 406, 195, 196) + sage: is_switch_OA_srg(842, 406, 195, 196) # needs sage.schemes (.switch_OA_srg at ..., 14, 29) """ cdef int n_2_p_1 = v @@ -1700,15 +1712,15 @@ def is_nowhere0_twoweight(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(196, 60, 14, 20) + sage: graphs.strongly_regular_graph(196, 60, 14, 20) # needs sage.combinat sage.modules Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_nowhere0_twoweight - sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t + sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t # needs sage.libs.pari (, 16) - sage: t = is_nowhere0_twoweight(5,5,5,5); t + sage: t = is_nowhere0_twoweight(5,5,5,5); t # needs sage.libs.pari """ from sage.graphs.generators.classical_geometries import Nowhere0WordsTwoWeightCodeGraph @@ -1787,22 +1799,22 @@ def eigenmatrix(int v, int k, int l, int mu): Petersen's graph's C-algebra does not have a dual coming from an s.r.g.:: sage: from sage.graphs.strongly_regular_db import eigenmatrix - sage: P=eigenmatrix(10,3,0,1); P + sage: P = eigenmatrix(10,3,0,1); P # needs sage.modules [ 1 3 6] [ 1 1 -2] [ 1 -2 1] - sage: 10*P^-1 + sage: 10*P^-1 # needs sage.modules [ 1 5 4] [ 1 5/3 -8/3] [ 1 -5/3 2/3] The line graph of `K_{3,3}` is self-dual:: - sage: P=eigenmatrix(9,4,1,2); P + sage: P = eigenmatrix(9,4,1,2); P # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] - sage: 9*P^-1 + sage: 9*P^-1 # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] @@ -1810,11 +1822,12 @@ def eigenmatrix(int v, int k, int l, int mu): A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:: - sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) + sage: # needs sage.modules + sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) # needs sage.combinat True - sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) + sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) # needs sage.combinat True - sage: P=eigenmatrix(243,220,199,200); P + sage: P = eigenmatrix(243,220,199,200); P [ 1 220 22] [ 1 4 -5] [ 1 -5 4] @@ -1882,7 +1895,7 @@ def _H_3_cayley_graph(L): TESTS:: sage: from sage.graphs.strongly_regular_db import _H_3_cayley_graph - sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) + sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) # needs sage.groups Graph on 100 vertices """ from sage.groups.free_group import FreeGroup @@ -1909,8 +1922,8 @@ def SRG_100_44_18_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_100_44_18_20 - sage: G = SRG_100_44_18_20() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_100_44_18_20() # long time + sage: G.is_strongly_regular(parameters=True) # long time (100, 44, 18, 20) """ L = ['100', '110', '130', '140', '200', '230', '240', '300', '310', '320', @@ -1931,8 +1944,8 @@ def SRG_100_45_20_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_100_45_20_20 - sage: G = SRG_100_45_20_20() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_100_45_20_20() # long time + sage: G.is_strongly_regular(parameters=True) # long time (100, 45, 20, 20) """ L = ['120', '140', '200', '210', '201', '401', '411', '321', '002', '012', @@ -1955,9 +1968,9 @@ def SRG_105_32_4_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12 - sage: G = SRG_105_32_4_12(); G + sage: G = SRG_105_32_4_12(); G # needs sage.rings.finite_rings Aut L(3,4) on flags: Graph on 105 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (105, 32, 4, 12) """ from sage.combinat.designs.block_design import ProjectiveGeometryDesign @@ -1985,8 +1998,8 @@ def SRG_120_77_52_44(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_120_77_52_44 - sage: G = SRG_120_77_52_44() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_120_77_52_44() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (120, 77, 52, 44) """ from sage.combinat.designs.block_design import WittDesign @@ -2009,8 +2022,8 @@ def SRG_144_39_6_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_144_39_6_12 - sage: G = SRG_144_39_6_12() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_144_39_6_12() # needs sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # needs sage.libs.gap (144, 39, 6, 12) """ from sage.libs.gap.libgap import libgap @@ -2043,8 +2056,8 @@ def SRG_176_49_12_14(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_176_49_12_14 - sage: G = SRG_176_49_12_14() # optional - gap_packages # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages # long time + sage: G = SRG_176_49_12_14() # long time, optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (176, 49, 12, 14) """ from sage.combinat.designs.database import HigmanSimsDesign @@ -2080,8 +2093,8 @@ def SRG_176_105_68_54(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_176_105_68_54 - sage: G = SRG_176_105_68_54() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_176_105_68_54() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (176, 105, 68, 54) """ from sage.combinat.designs.block_design import WittDesign @@ -2107,8 +2120,8 @@ def SRG_210_99_48_45(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45 - sage: g=SRG_210_99_48_45() - sage: g.is_strongly_regular(parameters=True) + sage: g = SRG_210_99_48_45() # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (210, 99, 48, 45) """ from sage.libs.gap.libgap import libgap @@ -2154,8 +2167,8 @@ def SRG_243_110_37_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_243_110_37_60 - sage: G = SRG_243_110_37_60() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_243_110_37_60() # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (243, 110, 37, 60) """ from sage.coding.golay_code import GolayCode @@ -2178,8 +2191,8 @@ def SRG_253_140_87_65(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_253_140_87_65 - sage: G = SRG_253_140_87_65() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_253_140_87_65() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (253, 140, 87, 65) """ from sage.combinat.designs.block_design import WittDesign @@ -2261,8 +2274,8 @@ def SRG_276_140_58_84(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_276_140_58_84 - sage: g=SRG_276_140_58_84() # long time # optional - gap_packages - sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages + sage: g = SRG_276_140_58_84() # long time, optional - gap_package_design + sage: g.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (276, 140, 58, 84) """ from sage.graphs.generators.smallgraphs import McLaughlinGraph @@ -2290,8 +2303,8 @@ def SRG_280_135_70_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_280_135_70_60 - sage: g=SRG_280_135_70_60() # long time # optional - internet - sage: g.is_strongly_regular(parameters=True) # long time # optional - internet + sage: g=SRG_280_135_70_60() # long time, optional - internet + sage: g.is_strongly_regular(parameters=True) # long time, optional - internet (280, 135, 70, 60) """ from sage.libs.gap.libgap import libgap @@ -2365,13 +2378,13 @@ def strongly_regular_from_two_weight_code(L): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_code - sage: x=("100022021001111", - ....: "010011211122000", - ....: "001021112100011", - ....: "000110120222220") - sage: M = Matrix(GF(3),[list(l) for l in x]) - sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) - sage: G.is_strongly_regular(parameters=True) + sage: x = ("100022021001111", + ....: "010011211122000", + ....: "001021112100011", + ....: "000110120222220") + sage: M = Matrix(GF(3),[list(l) for l in x]) # needs sage.modules sage.rings.finite_rings + sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (81, 50, 31, 30) """ from sage.structure.element import is_Matrix @@ -2398,8 +2411,8 @@ def SRG_416_100_36_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20 - sage: g = SRG_416_100_36_20() # long time # optional - internet - sage: g.is_strongly_regular(parameters=True) # long time # optional - internet + sage: g = SRG_416_100_36_20() # long time, optional - internet + sage: g.is_strongly_regular(parameters=True) # long time, optional - internet (416, 100, 36, 20) """ from sage.libs.gap.libgap import libgap @@ -2422,8 +2435,8 @@ def SRG_560_208_72_80(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_560_208_72_80 - sage: g = SRG_560_208_72_80() # not tested (~2s) - sage: g.is_strongly_regular(parameters=True) # not tested (~2s) + sage: g = SRG_560_208_72_80() # not tested (~2s) + sage: g.is_strongly_regular(parameters=True) # not tested (~2s) (560, 208, 72, 80) """ from sage.libs.gap.libgap import libgap @@ -2472,10 +2485,10 @@ def strongly_regular_from_two_intersection_set(M): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_intersection_set - sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) - sage: g = strongly_regular_from_two_intersection_set(S); g + sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) # needs sage.modules sage.rings.finite_rings + sage: g = strongly_regular_from_two_intersection_set(S); g # needs sage.modules sage.rings.finite_rings two-intersection set in PG(3,4): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (64, 18, 2, 6) """ from itertools import product @@ -2662,8 +2675,8 @@ def SRG_1288_792_476_504(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504 - sage: G = SRG_1288_792_476_504() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_1288_792_476_504() # long time # needs sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.rings.finite_rings (1288, 792, 476, 504) """ from sage.coding.golay_code import GolayCode @@ -2691,7 +2704,7 @@ cdef bint seems_feasible(int v, int k, int l, int mu): :trac:`32306` is fixed:: sage: from sage.graphs.strongly_regular_db import strongly_regular_graph - sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) + sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) # needs sage.combinat sage.modules True """ cdef uint_fast32_t tmp[2] @@ -2821,9 +2834,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, An set of parameters proved in a paper to be infeasible:: - sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) + sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) # needs sage.combinat sage.modules False - sage: graphs.strongly_regular_graph(324,57,0,12) + sage: graphs.strongly_regular_graph(324,57,0,12) # needs sage.combinat sage.modules Traceback (most recent call last): ... EmptySetError: Andries Brouwer's database reports that no (324, 57, 0, @@ -2832,9 +2845,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A set of parameters unknown to be realizable in Andries Brouwer's database:: - sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) + sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(324,95,22,30) + sage: graphs.strongly_regular_graph(324,95,22,30) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Andries Brouwer's database reports that no @@ -2843,9 +2856,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A large unknown set of parameters (not in Andries Brouwer's database):: - sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) + sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(1394,175,0,25) + sage: graphs.strongly_regular_graph(1394,175,0,25) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly @@ -2860,18 +2873,18 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, Check that :trac:`26513` is fixed:: - sage: graphs.strongly_regular_graph(539, 288, 162, 144) + sage: graphs.strongly_regular_graph(539, 288, 162, 144) # needs sage.combinat descendant of (540, 264, 138, 120)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(539, 250, 105, 125) + sage: graphs.strongly_regular_graph(539, 250, 105, 125) # needs sage.combinat descendant of (540, 275, 130, 150)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(209, 100, 45, 50) + sage: graphs.strongly_regular_graph(209, 100, 45, 50) # needs sage.libs.pari descendant of complement(merging of S_7 on Circulant(6,[1,4])s) at ... 209 vertices Check that all of our constructions are correct - you will need gap_packages spkg installed:: sage: from sage.graphs.strongly_regular_db import apparently_feasible_parameters - sage: for p in sorted(apparently_feasible_parameters(1300)): # not tested + sage: for p in sorted(apparently_feasible_parameters(1300)): # not tested, optional gap_package_design ....: if graphs.strongly_regular_graph(*p,existence=True) is True: ....: try: ....: _ = graphs.strongly_regular_graph(*p) @@ -2930,11 +2943,11 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F (3, 4)) sage: g(p) complement(Multipartite Graph with set sizes [4, 4, 4]): Graph on 12 vertices - sage: g=strongly_regular_graph_lazy(539,250,105); g + sage: g = strongly_regular_graph_lazy(539,250,105); g # needs sage.combinat sage.modules (.la at...>, 5, 11) - sage: g[0](*g[1:]) + sage: g[0](*g[1:]) # needs sage.combinat sage.modules descendant of (540, 275, 130, 150)-strongly regular graph at 0: Graph on 539 vertices """ load_brouwer_database() @@ -3065,14 +3078,16 @@ def apparently_feasible_parameters(int n): (16, 9, 4, 6), (16, 10, 6, 6), (17, 8, 3, 4)} - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) True But that becomes wrong for `v<60` (because of the non-existence of a `(49,16,3,6)`-strongly regular graph):: sage: small_feasible = apparently_feasible_parameters(60) - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) False """ cdef int v, k, l, mu @@ -3100,57 +3115,57 @@ def _build_small_srg_database(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import _build_small_srg_database - sage: _build_small_srg_database() + sage: _build_small_srg_database() # needs sage.modules sage.rings.finite_rings TESTS: Make sure that all two-weight codes yield the strongly regular graphs we expect:: - sage: graphs.strongly_regular_graph(81, 50, 31, 30) + sage: graphs.strongly_regular_graph(81, 50, 31, 30) # needs sage.libs.pari complement(two-intersection set in PG(4,3)): Graph on 81 vertices - sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time + sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time, needs sage.rings.finite_rings two-weight code: [55, 5] linear code over GF(3): Graph on 243 vertices - sage: graphs.strongly_regular_graph(256, 153, 92, 90) + sage: graphs.strongly_regular_graph(256, 153, 92, 90) # needs sage.combinat complement(two-intersection set in PG(4,4)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 170, 114, 110) + sage: graphs.strongly_regular_graph(256, 170, 114, 110) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 187, 138, 132) + sage: graphs.strongly_regular_graph(256, 187, 138, 132) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long), needs sage.rings.finite_rings two-weight code: [219, 9] linear code over GF(2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time + sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time two-intersection set in PG(9,2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long), needs sage.rings.finite_rings two-weight code: [70, 9] linear code over GF(2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time + sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(625, 416, 279, 272) # long time + sage: graphs.strongly_regular_graph(625, 416, 279, 272) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(625, 468, 353, 342) # long time + sage: graphs.strongly_regular_graph(625, 468, 353, 342) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(729, 336, 153,156) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 336, 153,156) # not tested (too long) two-intersection set in PG(6,3): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 420, 243, 240) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 420, 243, 240) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 448, 277, 272) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 448, 277, 272) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 476, 313, 306) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 476, 313, 306) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 532, 391, 380) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 532, 391, 380) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 560, 433, 420) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 560, 433, 420) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 616, 523, 506) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 616, 523, 506) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(1024, 363, 122, 132)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 363, 122, 132) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 396, 148, 156)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 396, 148, 156) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 429, 176, 182)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 429, 176, 182) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 825, 668, 650)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 825, 668, 650) # not tested (too long) complement(two-intersection set in PG(10,2)): Graph on 1024 vertices """ from sage.graphs.generators.smallgraphs import McLaughlinGraph diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index a565d46fdcb..6180cb8db08 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -338,16 +338,17 @@ def lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm="fast") Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000', algorithm="fast") # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000', algorithm="fast") ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_BFS(initial_vertex='000', algorithm="slow") # optional - sage.combinat + sage: G.lex_BFS(initial_vertex='000', algorithm="slow") ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -541,14 +542,15 @@ def lex_UP(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -714,14 +716,15 @@ def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -889,14 +892,15 @@ def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 6794c960805..5a7b048ddfe 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -532,7 +532,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): The Tutte polynomial of any tree of order `n` is `x^{n-1}`:: - sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) # optional - sage.symbolic + sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) # needs sage.symbolic True The Tutte polynomial of the Petersen graph is:: @@ -550,7 +550,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.RandomGNP(10,0.6) sage: while not G.is_connected(): ....: G = graphs.RandomGNP(10,0.6) - sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() + sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() # needs sage.modules True Given that `T(x,y)` is the Tutte polynomial of a graph `G` with @@ -560,7 +560,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.OctahedralGraph() sage: T = G.tutte_polynomial() sage: R = PolynomialRing(ZZ, 'x') - sage: R((-1)^5*x*T(1-x,0)).factor() # optional - sage.symbolic + sage: R((-1)^5*x*T(1-x,0)).factor() # needs sage.symbolic (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) sage: G.chromatic_polynomial().factor() (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index c49511207e5..fcb1315febc 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -64,18 +64,10 @@ cdef class EdgesView: - ``ignore_direction`` -- boolean (default: ``False``); only applies to directed graphs. If ``True``, searches across edges in either direction. - - ``sort`` -- boolean (default: ``None``); whether to sort edges - - - if ``None``, sort edges according to the default ordering and give a - deprecation warning as sorting will be set to ``False`` by default in - the future - - - if ``True``, edges are sorted according the ordering specified with - parameter ``key`` - - - if ``False``, edges are not sorted. This is the fastest and less memory - consuming method for iterating over edges. This will become the default - behavior in the future. + - ``sort`` -- boolean (default: ``False``); whether to sort edges according + the ordering specified with parameter ``key``. If ``False`` (default), + edges are not sorted. This is the fastest and less memory consuming method + for iterating over edges. - ``key`` -- a function (default: ``None``); a function that takes an edge (a pair or a triple, according to the ``labels`` keyword) as its one @@ -175,11 +167,11 @@ cdef class EdgesView: With a directed graph:: - sage: G = digraphs.DeBruijn(2, 2) # optional - sage.combinat - sage: E = EdgesView(G, labels=False, sort=True); E # optional - sage.combinat + sage: G = digraphs.DeBruijn(2, 2) # needs sage.combinat + sage: E = EdgesView(G, labels=False, sort=True); E # needs sage.combinat [('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'), ('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')] - sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E # optional - sage.combinat + sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E # needs sage.combinat [('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'), ('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')] @@ -350,7 +342,7 @@ cdef class EdgesView: def __init__(self, G, vertices=None, vertices2=None, labels=True, ignore_direction=False, - sort=None, key=None, sort_vertices=True): + sort=False, key=None, sort_vertices=True): """ Construction of this :class:`EdgesView`. diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index bf54b8a0ad9..86051c72b28 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -55,8 +55,8 @@ Only automorphism groups of finite abelian groups are supported:: - sage: G = AbelianGroupGap([0,2]) # optional gap_packages - sage: autG = G.aut() # optional gap_packages + sage: G = AbelianGroupGap([0,2]) # optional - gap_package_polycyclic + sage: autG = G.aut() # optional - gap_package_polycyclic Traceback (most recent call last): ... ValueError: only finite abelian groups are supported diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 41b0e2c9eca..efa54bac7d1 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -856,7 +856,7 @@ def _libgap_(self): Requires the optional ``gap_packages`` for infinite groups:: sage: G = AbelianGroup(3, [0,3,4], names="abc") - sage: libgap(G) # optional - gap_packages + sage: libgap(G) # optional - gap_package_polycyclic Pcp-group with orders [ 0, 3, 4 ] """ from sage.libs.gap.libgap import libgap @@ -885,7 +885,7 @@ def _gap_init_(self): sage: G = AbelianGroup(3,[0,3,4], names="abc"); G Multiplicative Abelian group isomorphic to Z x C3 x C4 - sage: G._gap_init_() # optional - gap_packages + sage: G._gap_init_() # optional - gap_package_polycyclic 'AbelianPcpGroup([0, 3, 4])' """ if self.is_finite(): diff --git a/src/sage/groups/abelian_gps/abelian_group_gap.py b/src/sage/groups/abelian_gps/abelian_group_gap.py index fc59eba7941..04ebb9d3ed1 100644 --- a/src/sage/groups/abelian_gps/abelian_group_gap.py +++ b/src/sage/groups/abelian_gps/abelian_group_gap.py @@ -11,7 +11,7 @@ For infinite abelian groups we use the GAP package ``Polycyclic``:: - sage: AbelianGroupGap([3,0]) # optional - gap_packages + sage: AbelianGroupGap([3,0]) # optional - gap_package_polycyclic Abelian group with gap, generator orders (3, 0) AUTHORS: @@ -183,9 +183,9 @@ def order(self): sage: g = G.gens()[0] sage: g.order() 4 - sage: G = AbelianGroupGap([0]) # optional - gap_packages - sage: g = G.gens()[0] # optional - gap_packages - sage: g.order() # optional - gap_packages + sage: G = AbelianGroupGap([0]) # optional - gap_package_polycyclic + sage: g = G.gens()[0] # optional - gap_package_polycyclic + sage: g.order() # optional - gap_package_polycyclic +Infinity """ return self.gap().Order().sage() @@ -197,8 +197,8 @@ class AbelianGroupElement_polycyclic(AbelianGroupElement_gap): TESTS:: sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap - sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages - sage: TestSuite(G.an_element()).run() # optional - gap_packages + sage: G = AbelianGroupGap([4,7,0]) # optional - gap_package_polycyclic + sage: TestSuite(G.an_element()).run() # optional - gap_package_polycyclic """ def exponents(self): r""" @@ -210,18 +210,20 @@ def exponents(self): EXAMPLES:: + sage: # optional - gap_package_polycyclic sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap - sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages - sage: gens = G.gens() # optional - gap_packages - sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 # optional - gap_packages - sage: g.exponents() # optional - gap_packages + sage: G = AbelianGroupGap([4,7,0]) + sage: gens = G.gens() + sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 + sage: g.exponents() (2, 4, 8) Efficiently handles very large groups:: - sage: G = AbelianGroupGap([2^30,5^30,0]) # optional - gap_packages - sage: f1, f2, f3 = G.gens() # optional - gap_packages - sage: (f1^12345*f2^123456789).exponents() # optional - gap_packages + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([2^30,5^30,0]) + sage: f1, f2, f3 = G.gens() + sage: (f1^12345*f2^123456789).exponents() (12345, 123456789, 0) """ return tuple(self.gap().Exponents().sage()) @@ -613,12 +615,14 @@ def subgroup(self, gens): sage: s = S.an_element() sage: g * s f2^2*f3*f5 - sage: G = AbelianGroupGap([3,4,0,2]) # optional - gap_packages - sage: gen = G.gens()[:2] # optional - gap_packages - sage: S = G.subgroup(gen) # optional - gap_packages - sage: g = G.an_element() # optional - gap_packages - sage: s = S.an_element() # optional - gap_packages - sage: g * s # optional - gap_packages + + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([3,4,0,2]) + sage: gen = G.gens()[:2] + sage: S = G.subgroup(gen) + sage: g = G.an_element() + sage: s = S.an_element() + sage: g * s g1^2*g2^2*g3*g4 TESTS:: @@ -650,7 +654,7 @@ class AbelianGroupGap(AbelianGroup_gap): Abelian group with gap, generator orders (3, 6) sage: AbelianGroupGap([3,6,5]) Abelian group with gap, generator orders (3, 6, 5) - sage: AbelianGroupGap([3,6,0]) # optional - gap_packages + sage: AbelianGroupGap([3,6,0]) # optional - gap_package_polycyclic Abelian group with gap, generator orders (3, 6, 0) .. WARNING:: @@ -777,13 +781,14 @@ def __init__(self, ambient, gens): Check that we are in the correct category:: - sage: G = AbelianGroupGap([2,3,0]) # optional - gap_packages - sage: g = G.gens() # optional - gap_packages - sage: H1 = G.subgroup([g[0],g[1]]) # optional - gap_packages - sage: H1 in Groups().Finite() # optional - gap_packages + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([2,3,0]) + sage: g = G.gens() + sage: H1 = G.subgroup([g[0],g[1]]) + sage: H1 in Groups().Finite() True - sage: H2 = G.subgroup([g[0],g[2]]) # optional - gap_packages - sage: H2 in Groups().Infinite() # optional - gap_packages + sage: H2 = G.subgroup([g[0],g[2]]) + sage: H2 in Groups().Infinite() True """ gens_gap = tuple([g.gap() for g in gens]) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 965076c0a5f..6e59f4f4b84 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -164,7 +164,7 @@ def load_hap(): EXAMPLES:: - sage: sage.groups.perm_gps.permgroup.load_hap() # optional - gap_packages + sage: sage.groups.perm_gps.permgroup.load_hap() # optional - gap_package_hap """ from sage.features.gap import GapPackage GapPackage("hap", spkg="gap_packages").require() @@ -179,16 +179,17 @@ def hap_decorator(f): EXAMPLES:: + sage: # optional - gap_package_hap sage: from sage.groups.perm_gps.permgroup import hap_decorator sage: def foo(self, n, p=0): print("Done") sage: foo = hap_decorator(foo) - sage: foo(None, 3) #optional - gap_packages + sage: foo(None, 3) Done - sage: foo(None, 3, 0) # optional - gap_packages + sage: foo(None, 3, 0) Done - sage: foo(None, 3, 5) # optional - gap_packages + sage: foo(None, 3, 5) Done - sage: foo(None, 3, 4) #optional - gap_packages + sage: foo(None, 3, 4) Traceback (most recent call last): ... ValueError: p must be 0 or prime @@ -3186,16 +3187,16 @@ def cohomology(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(4) - sage: G.cohomology(1,2) # optional - gap_packages + sage: G.cohomology(1,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 sage: G = SymmetricGroup(3) - sage: G.cohomology(5) # optional - gap_packages + sage: G.cohomology(5) # optional - gap_package_hap Trivial Abelian group - sage: G.cohomology(5,2) # optional - gap_packages + sage: G.cohomology(5,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 - sage: G.homology(5,3) # optional - gap_packages + sage: G.homology(5,3) # optional - gap_package_hap Trivial Abelian group - sage: G.homology(5,4) # optional - gap_packages + sage: G.homology(5,4) # optional - gap_package_hap Traceback (most recent call last): ... ValueError: p must be 0 or prime @@ -3238,10 +3239,10 @@ def cohomology_part(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.cohomology_part(7,2) # optional - gap_packages + sage: G.cohomology_part(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 sage: G = SymmetricGroup(3) - sage: G.cohomology_part(2,3) # optional - gap_packages + sage: G.cohomology_part(2,3) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C3 AUTHORS: @@ -3282,13 +3283,13 @@ def homology(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.homology(7) # optional - gap_packages + sage: G.homology(7) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C4 x C3 x C5 - sage: G.homology(7,2) # optional - gap_packages + sage: G.homology(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C2 - sage: G.homology(7,3) # optional - gap_packages + sage: G.homology(7,3) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C3 - sage: G.homology(7,5) # optional - gap_packages + sage: G.homology(7,5) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C5 REFERENCES: @@ -3320,7 +3321,7 @@ def homology_part(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.homology_part(7,2) # optional - gap_packages + sage: G.homology_part(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C4 AUTHORS: @@ -4739,10 +4740,10 @@ def poincare_series(self, p=2, n=10): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.poincare_series(2,10) # optional - gap_packages + sage: G.poincare_series(2,10) # optional - gap_package_hap (x^2 + 1)/(x^4 - x^3 - x + 1) sage: G = SymmetricGroup(3) - sage: G.poincare_series(2,10) # optional - gap_packages + sage: G.poincare_series(2,10) # optional - gap_package_hap -1/(x - 1) AUTHORS: diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 746cd5ddbab..7b3d4947f75 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -134,7 +134,7 @@ def __classcall__(cls, *args, **kwds): EXAMPLES:: - sage: SymmetricGroup(['a','b']).domain() #indirect doctest + sage: SymmetricGroup(['a','b']).domain() # indirect doctest {'a', 'b'} """ domain = kwds.pop('domain', None) @@ -679,7 +679,7 @@ def __init__(self, domain=None): Alternating group of order 6!/2 as a permutation group sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time sage: G = AlternatingGroup([1,2,4,5]) sage: G @@ -1063,14 +1063,15 @@ def __init__(self, n): EXAMPLES:: - sage: G = groups.permutation.Janko(1); G # optional - gap_packages internet + sage: G = groups.permutation.Janko(1); G # optional - gap_package_atlasrep internet Janko group J1 of order 175560 as a permutation group TESTS:: - sage: G.category() # optional - gap_packages internet + sage: G.category() # optional - gap_package_atlasrep internet Category of finite enumerated permutation groups - sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet + sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", # optional - gap_package_atlasrep internet + ....: "_test_enumerated_set_iter_list"]) """ if n not in [1, 2, 3]: raise ValueError("n must belong to {1,2,3}") @@ -1083,7 +1084,7 @@ def _repr_(self): """ EXAMPLES:: - sage: G = groups.permutation.Janko(1); G # optional - gap_packages internet + sage: G = groups.permutation.Janko(1); G # optional - gap_package_atlasrep internet Janko group J1 of order 175560 as a permutation group """ return "Janko group J%s of order %s as a permutation group" % (self._n, self.order()) @@ -1096,14 +1097,15 @@ def __init__(self): EXAMPLES:: - sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_packages internet + sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_package_atlasrep internet Sporadic Suzuki group acting on 1782 points TESTS:: - sage: G.category() # optional - gap_packages internet + sage: G.category() # optional - gap_package_atlasrep internet Category of finite enumerated permutation groups - sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet + sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", # optional - gap_package_atlasrep internet + ....: "_test_enumerated_set_iter_list"]) """ libgap.load_package("atlasrep") PermutationGroup_generic.__init__(self, gap_group='AtlasGroup("Suz")') @@ -1112,7 +1114,7 @@ def _repr_(self): """ EXAMPLES:: - sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_packages internet + sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_package_atlasrep internet Sporadic Suzuki group acting on 1782 points """ return "Sporadic Suzuki group acting on 1782 points" @@ -1987,7 +1989,7 @@ def _repr_(self): """ TESTS:: - sage: TransitiveGroups() # indirect doctest + sage: TransitiveGroups() # indirect doctest Transitive Groups """ return "Transitive Groups" @@ -2101,7 +2103,7 @@ def __iter__(self): """ EXAMPLES:: - sage: list(TransitiveGroups(5)) # indirect doctest + sage: list(TransitiveGroups(5)) # indirect doctest [Transitive group number 1 of degree 5, Transitive group number 2 of degree 5, Transitive group number 3 of degree 5, @@ -2375,7 +2377,7 @@ class PrimitiveGroupsAll(DisjointUnionEnumeratedSets): The following test is broken, see :trac:`22576`:: - sage: TestSuite(PrimitiveGroups()).run() # known bug # long time + sage: TestSuite(PrimitiveGroups()).run() # known bug, long time """ def __init__(self): """ @@ -2399,7 +2401,7 @@ def _repr_(self): TESTS:: - sage: PrimitiveGroups() # indirect doctest + sage: PrimitiveGroups() # indirect doctest Primitive Groups """ return "Primitive Groups" @@ -2533,7 +2535,7 @@ def __iter__(self): """ EXAMPLES:: - sage: list(PrimitiveGroups(5)) # indirect doctest + sage: list(PrimitiveGroups(5)) # indirect doctest [C(5), D(2*5), AGL(1, 5), A(5), S(5)] """ for n in range(1, self.cardinality() + 1): @@ -2650,7 +2652,7 @@ def __init__(self, n, q, name='a'): sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time TESTS:: @@ -2718,7 +2720,7 @@ def __init__(self, n, q, name='a'): sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time TESTS:: @@ -2784,7 +2786,7 @@ def ramification_module_decomposition_hurwitz_curve(self): EXAMPLES:: sage: G = PSL(2,13) - sage: G.ramification_module_decomposition_hurwitz_curve() # random, optional - gap_packages + sage: G.ramification_module_decomposition_hurwitz_curve() # random, optional - gap_packages [0, 7, 7, 12, 12, 12, 13, 15, 14] This means, for example, that the trivial representation does not @@ -2834,7 +2836,7 @@ def ramification_module_decomposition_modular_curve(self): EXAMPLES:: sage: G = PSL(2,7) - sage: G.ramification_module_decomposition_modular_curve() # random, optional - gap_packages + sage: G.ramification_module_decomposition_modular_curve() # random, optional - gap_packages [0, 4, 3, 6, 7, 8] This means, for example, that the trivial representation does not diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index e198a14d7fe..c7856836f28 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs +# sage.doctest: needs sage.graphs r""" Algebraic topological model for a cell complex @@ -101,8 +101,8 @@ def algebraic_topological_model(K, base_ring=None): sage: from sage.homology.algebraic_topological_model import algebraic_topological_model sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: phi, M = algebraic_topological_model(RP2, GF(2)) # optional - sage.rings.finite_rings - sage: M.homology() # optional - sage.rings.finite_rings + sage: phi, M = algebraic_topological_model(RP2, GF(2)) + sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} @@ -372,8 +372,8 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): sage: from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex as AT_model sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: phi, M = AT_model(RP2, GF(2)) # optional - sage.rings.finite_rings - sage: M.homology() # optional - sage.rings.finite_rings + sage: phi, M = AT_model(RP2, GF(2)) + sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index f6409c5ae4b..7a56cf3fc4b 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -85,7 +85,7 @@ def _latex_module(R, m): '\\Bold{Z}^{3}' sage: _latex_module(ZZ, 0) '0' - sage: _latex_module(GF(3), 1) # optional - sage.rings.finite_rings + sage: _latex_module(GF(3), 1) '\\Bold{F}_{3}^{1}' """ if m == 0: @@ -188,11 +188,11 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, Chain complex with at most 2 nonzero terms over Integer Ring sage: m = matrix(ZZ, 2, 2, [0, 1, 0, 0]) - sage: D = ChainComplex([m, m], base_ring=GF(2)); D # optional - sage.rings.finite_rings + sage: D = ChainComplex([m, m], base_ring=GF(2)); D Chain complex with at most 3 nonzero terms over Finite Field of size 2 - sage: D == loads(dumps(D)) # optional - sage.rings.finite_rings + sage: D == loads(dumps(D)) True - sage: D.differential(0)==m, m.is_immutable(), D.differential(0).is_immutable() # optional - sage.rings.finite_rings + sage: D.differential(0)==m, m.is_immutable(), D.differential(0).is_immutable() (True, False, True) Note that when a chain complex is defined in Sage, new @@ -214,12 +214,12 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, sage: ChainComplex([matrix(QQ, 3, 1), matrix(ZZ, 4, 3)]) Chain complex with at most 3 nonzero terms over Rational Field - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(ZZ, 4, 3)]) # optional - sage.rings.finite_rings + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(ZZ, 4, 3)]) # needs sage.rings.finite_rings Chain complex with at most 3 nonzero terms over Finite Field in a of size 5^3 If the matrices are defined over incompatible rings, an error results:: - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(QQ, 4, 3)]) # optional - sage.rings.finite_rings + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(QQ, 4, 3)]) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -228,7 +228,7 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, If the base ring is given explicitly but is not compatible with the matrices, an error results:: - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1)], base_ring=QQ) # optional - sage.rings.finite_rings + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1)], base_ring=QQ) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert 0 to a rational @@ -336,9 +336,9 @@ def __init__(self, parent, vectors, check=True): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, # optional - sage.rings.finite_rings + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, ....: base_ring=GF(7)) - sage: C.category() # optional - sage.rings.finite_rings + sage: C.category() Category of chain complexes over Finite Field of size 7 TESTS:: @@ -609,7 +609,7 @@ def __eq__(self, other): sage: c == C(0) False """ - if type(self) != type(other) or self.parent() != other.parent(): + if type(self) is not type(other) or self.parent() != other.parent(): return False return self._vec == other._vec @@ -771,7 +771,7 @@ def rank(self, degree, ring=None): [2] sage: C.rank(0) 1 - sage: C.rank(0, ring=GF(2)) # optional - sage.rings.finite_rings + sage: C.rank(0, ring=GF(2)) 0 """ degree = self.grading_group()(degree) @@ -1079,12 +1079,12 @@ def __eq__(self, other): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, # optional - sage.rings.finite_rings + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, ....: base_ring=GF(2)) - sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), # optional - sage.rings.finite_rings + sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), ....: 1: matrix(ZZ, 0, 2), ....: 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices - sage: C == D # optional - sage.rings.finite_rings + sage: C == D True """ if not isinstance(other, ChainComplex_class) or self.base_ring() != other.base_ring(): @@ -1108,16 +1108,16 @@ def __ne__(self, other): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, # optional - sage.rings.finite_rings + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, ....: base_ring=GF(2)) - sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), # optional - sage.rings.finite_rings + sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), ....: 1: matrix(ZZ, 0, 2), ....: 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices - sage: C != D # optional - sage.rings.finite_rings + sage: C != D False sage: E = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, ....: base_ring=ZZ) - sage: C != E # optional - sage.rings.finite_rings + sage: C != E True """ return not self == other @@ -1143,15 +1143,15 @@ def _homology_chomp(self, deg, base_ring, verbose, generators): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(2)) # optional - sage.rings.finite_rings - sage: C._homology_chomp(None, GF(2), False, False) # optional - CHomP # optional - sage.rings.finite_rings + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(2)) + sage: C._homology_chomp(None, GF(2), False, False) # optional - chomp, needs sage.rings.finite_rings doctest:...: DeprecationWarning: the CHomP interface is deprecated; hence so is this function See https://github.com/sagemath/sage/issues/33777 for details. {0: Vector space of dimension 2 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2} sage: D = ChainComplex({0: matrix(ZZ,1,0,[]), 1: matrix(ZZ,1,1,[0]), ....: 2: matrix(ZZ,0,1,[])}) - sage: D._homology_chomp(None, GF(2), False, False) # optional - CHomP # optional - sage.rings.finite_rings + sage: D._homology_chomp(None, GF(2), False, False) # optional - chomp, needs sage.rings.finite_rings {1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} """ @@ -1253,7 +1253,7 @@ def homology(self, deg=None, base_ring=None, generators=False, sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C.homology() {0: Z x Z, 1: Z x C3} - sage: C.homology(deg=1, base_ring=GF(3)) # optional - sage.rings.finite_rings + sage: C.homology(deg=1, base_ring=GF(3)) Vector space of dimension 2 over Finite Field of size 3 sage: D = ChainComplex({0: identity_matrix(ZZ, 4), 4: identity_matrix(ZZ, 30)}) sage: D.homology() @@ -1280,9 +1280,9 @@ def homology(self, deg=None, base_ring=None, generators=False, From a torus using a field:: - sage: T = simplicial_complexes.Torus() # optional - sage.graphs - sage: C_t = T.chain_complex() # optional - sage.graphs - sage: C_t.homology(base_ring=QQ, generators=True) # optional - sage.graphs + sage: T = simplicial_complexes.Torus() # needs sage.graphs + sage: C_t = T.chain_complex() # needs sage.graphs + sage: C_t.homology(base_ring=QQ, generators=True) # needs sage.graphs {0: [(Vector space of dimension 1 over Rational Field, Chain(0:(0, 0, 0, 0, 0, 0, 1)))], 1: [(Vector space of dimension 1 over Rational Field, @@ -1461,8 +1461,8 @@ def betti(self, deg=None, base_ring=None): sage: C.betti() {0: 2, 1: 1} - sage: D = ChainComplex({0: matrix(GF(5), [[3, 1],[1, 2]])}) # optional - sage.rings.finite_rings - sage: D.betti() # optional - sage.rings.finite_rings + sage: D = ChainComplex({0: matrix(GF(5), [[3, 1],[1, 2]])}) + sage: D.betti() {0: 1, 1: 1} """ if base_ring is None: @@ -1513,14 +1513,14 @@ def torsion_list(self, max_prime, min_prime=2): sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C.homology() {0: Z x Z, 1: Z x C3} - sage: C.torsion_list(11) # optional - sage.rings.finite_rings + sage: C.torsion_list(11) # needs sage.rings.finite_rings [(3, [1])] sage: C = ChainComplex([matrix(ZZ, 1, 1, [2]), matrix(ZZ, 1, 1), matrix(1, 1, [3])]) sage: C.homology(1) C2 sage: C.homology(3) C3 - sage: C.torsion_list(5) # optional - sage.rings.finite_rings + sage: C.torsion_list(5) # needs sage.rings.finite_rings [(2, [1]), (3, [3])] """ if self.base_ring() != ZZ: @@ -1563,11 +1563,12 @@ def _Hom_(self, other, category=None): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: T = simplicial_complexes.Torus() # optional - sage.graphs - sage: C = S.chain_complex(augmented=True, cochain=True) # optional - sage.graphs - sage: D = T.chain_complex(augmented=True, cochain=True) # optional - sage.graphs - sage: Hom(C, D) # indirect doctest # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: T = simplicial_complexes.Torus() + sage: C = S.chain_complex(augmented=True, cochain=True) + sage: D = T.chain_complex(augmented=True, cochain=True) + sage: Hom(C, D) # indirect doctest Set of Morphisms from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring @@ -1629,25 +1630,27 @@ def shift(self, n=1): EXAMPLES:: - sage: S1 = simplicial_complexes.Sphere(1).chain_complex() # optional - sage.graphs - sage: S1.shift(1).differential(2) == -S1.differential(1) # optional - sage.graphs + sage: # needs sage.graphs + sage: S1 = simplicial_complexes.Sphere(1).chain_complex() + sage: S1.shift(1).differential(2) == -S1.differential(1) True - sage: S1.shift(2).differential(3) == S1.differential(1) # optional - sage.graphs + sage: S1.shift(2).differential(3) == S1.differential(1) True - sage: S1.shift(3).homology(4) # optional - sage.graphs + sage: S1.shift(3).homology(4) Z For cochain complexes, shifting goes in the other direction. Topologically, this makes sense if we grade the cochain complex for a space negatively:: - sage: T = simplicial_complexes.Torus() # optional - sage.graphs - sage: co_T = T.chain_complex()._flip_() # optional - sage.graphs - sage: co_T.homology() # optional - sage.graphs + sage: # needs sage.graphs + sage: T = simplicial_complexes.Torus() + sage: co_T = T.chain_complex()._flip_() + sage: co_T.homology() {-2: Z, -1: Z x Z, 0: Z} - sage: co_T.degree_of_differential() # optional - sage.graphs + sage: co_T.degree_of_differential() 1 - sage: co_T.shift(2).homology() # optional - sage.graphs + sage: co_T.shift(2).homology() {-4: Z, -3: Z x Z, -2: Z} You can achieve the same result by tensoring (on the left, to @@ -1655,7 +1658,7 @@ def shift(self, n=1): ``-n * deg``, if ``deg`` is the degree of the differential:: sage: C = ChainComplex({-2: matrix(ZZ, 0, 1)}) - sage: C.tensor(co_T).homology() # optional - sage.graphs + sage: C.tensor(co_T).homology() # needs sage.graphs {-4: Z, -3: Z x Z, -2: Z} """ deg = self.degree_of_differential() diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index 7bda59b8416..ad7a6bf9b84 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs (because all doctests use SimplicialComplex) +# sage.doctest: needs sage.graphs (because all doctests use SimplicialComplex) r""" Homspaces between chain complexes diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index c37f4854fe0..b3f284342bd 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -14,19 +14,20 @@ EXAMPLES:: - sage: S = simplicial_complexes.Sphere(1); S # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(1); S Minimal triangulation of the 1-sphere - sage: C = S.chain_complex() # optional - sage.graphs - sage: C.differential() # optional - sage.graphs + sage: C = S.chain_complex() + sage: C.differential() {0: [], 1: [-1 -1 0] [ 1 0 -1] [ 0 1 1], 2: []} sage: f = {0: zero_matrix(ZZ,3,3), 1: zero_matrix(ZZ,3,3)} - sage: G = Hom(C, C) # optional - sage.graphs - sage: x = G(f); x # optional - sage.graphs + sage: G = Hom(C, C) + sage: x = G(f); x Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring - sage: x._matrix_dictionary # optional - sage.graphs + sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] [0 0 0], @@ -63,19 +64,20 @@ def is_ChainComplexMorphism(x): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.homology.chain_complex_morphism import is_ChainComplexMorphism - sage: S = simplicial_complexes.Sphere(14) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # long time (8s on sage.math, 2011) # optional - sage.graphs - sage: S = simplicial_complexes.Sphere(6) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: x # indirect doctest # optional - sage.graphs + sage: S = simplicial_complexes.Sphere(14) + sage: H = Hom(S,S) + sage: i = H.identity() # long time (8s on sage.math, 2011) + sage: S = simplicial_complexes.Sphere(6) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: x # indirect doctest Chain complex morphism: From: Chain complex with at most 7 nonzero terms over Integer Ring To: Chain complex with at most 7 nonzero terms over Integer Ring - sage: is_ChainComplexMorphism(x) # optional - sage.graphs + sage: is_ChainComplexMorphism(x) True """ return isinstance(x, ChainComplexMorphism) @@ -91,21 +93,22 @@ def __init__(self, matrices, C, D, check=True): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(1); S # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(1); S Minimal triangulation of the 1-sphere - sage: C = S.chain_complex() # optional - sage.graphs - sage: C.differential() # optional - sage.graphs + sage: C = S.chain_complex() + sage: C.differential() {0: [], 1: [-1 -1 0] [ 1 0 -1] [ 0 1 1], 2: []} sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} - sage: G = Hom(C,C) # optional - sage.graphs - sage: x = G(f); x # optional - sage.graphs + sage: G = Hom(C,C) + sage: x = G(f); x Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring - sage: x._matrix_dictionary # optional - sage.graphs + sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] [0 0 0], @@ -115,10 +118,11 @@ def __init__(self, matrices, C, D, check=True): Check that the bug in :trac:`13220` has been fixed:: - sage: X = simplicial_complexes.Simplex(1) # optional - sage.graphs - sage: Y = simplicial_complexes.Simplex(0) # optional - sage.graphs - sage: g = Hom(X,Y)({0: 0, 1: 0}) # optional - sage.graphs - sage: g.associated_chain_complex_morphism() # optional - sage.graphs + sage: # needs sage.graphs + sage: X = simplicial_complexes.Simplex(1) + sage: Y = simplicial_complexes.Simplex(0) + sage: g = Hom(X,Y)({0: 0, 1: 0}) + sage: g.associated_chain_complex_morphism() Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring @@ -266,24 +270,25 @@ def dual(self): EXAMPLES:: - sage: X = simplicial_complexes.Simplex(1) # optional - sage.graphs - sage: Y = simplicial_complexes.Simplex(0) # optional - sage.graphs - sage: g = Hom(X,Y)({0:0, 1:0}) # optional - sage.graphs - sage: f = g.associated_chain_complex_morphism() # optional - sage.graphs - sage: f.in_degree(0) # optional - sage.graphs + sage: # needs sage.graphs + sage: X = simplicial_complexes.Simplex(1) + sage: Y = simplicial_complexes.Simplex(0) + sage: g = Hom(X,Y)({0:0, 1:0}) + sage: f = g.associated_chain_complex_morphism() + sage: f.in_degree(0) [1 1] - sage: f.dual() # optional - sage.graphs + sage: f.dual() Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring - sage: f.dual().in_degree(0) # optional - sage.graphs + sage: f.dual().in_degree(0) [1] [1] - sage: ascii_art(f.domain()) # optional - sage.graphs + sage: ascii_art(f.domain()) [-1] [ 1] 0 <-- C_0 <----- C_1 <-- 0 - sage: ascii_art(f.dual().codomain()) # optional - sage.graphs + sage: ascii_art(f.dual().codomain()) [-1 1] 0 <-- C_1 <-------- C_0 <-- 0 """ @@ -297,12 +302,13 @@ def __neg__(self): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: w = -x # optional - sage.graphs - sage: w._matrix_dictionary # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: w = -x + sage: w._matrix_dictionary {0: [-1 0 0 0] [ 0 -1 0 0] [ 0 0 -1 0] @@ -330,12 +336,13 @@ def __add__(self, x): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: z = x+x # optional - sage.graphs - sage: z._matrix_dictionary # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: z = x+x + sage: z._matrix_dictionary {0: [2 0 0 0] [0 2 0 0] [0 0 2 0] @@ -365,12 +372,13 @@ def __mul__(self, x): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: y = x*2 # optional - sage.graphs - sage: y._matrix_dictionary # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: y = x*2 + sage: y._matrix_dictionary {0: [2 0 0 0] [0 2 0 0] [0 0 2 0] @@ -385,8 +393,8 @@ def __mul__(self, x): [0 2 0 0] [0 0 2 0] [0 0 0 2]} - sage: z = y*y # optional - sage.graphs - sage: z._matrix_dictionary # optional - sage.graphs + sage: z = y*y + sage: z._matrix_dictionary {0: [4 0 0 0] [0 4 0 0] [0 0 4 0] @@ -451,13 +459,14 @@ def __rmul__(self, x): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: 2*x == x*2 # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: 2*x == x*2 True - sage: 3*x == x*2 # optional - sage.graphs + sage: 3*x == x*2 False """ try: @@ -475,12 +484,13 @@ def __sub__(self, x): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: y = x - x # optional - sage.graphs - sage: y._matrix_dictionary # optional - sage.graphs + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(2) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: y = x - x + sage: y._matrix_dictionary {0: [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -504,18 +514,19 @@ def __eq__(self, x): EXAMPLES:: - sage: S = SimplicialComplex(is_mutable=False) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism(); x # optional - sage.graphs + sage: # needs sage.graphs + sage: S = SimplicialComplex(is_mutable=False) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism(); x Chain complex morphism: From: Trivial chain complex over Integer Ring To: Trivial chain complex over Integer Ring - sage: f = x._matrix_dictionary # optional - sage.graphs - sage: C = S.chain_complex() # optional - sage.graphs - sage: G = Hom(C,C) # optional - sage.graphs - sage: y = G(f) # optional - sage.graphs - sage: x == y # optional - sage.graphs + sage: f = x._matrix_dictionary + sage: C = S.chain_complex() + sage: G = Hom(C,C) + sage: y = G(f) + sage: x == y True """ return isinstance(x, ChainComplexMorphism) \ @@ -529,11 +540,12 @@ def is_identity(self) -> bool: EXAMPLES:: - sage: S = SimplicialComplex(is_mutable=False) # optional - sage.graphs - sage: H = Hom(S,S) # optional - sage.graphs - sage: i = H.identity() # optional - sage.graphs - sage: x = i.associated_chain_complex_morphism() # optional - sage.graphs - sage: x.is_identity() # optional - sage.graphs + sage: # needs sage.graphs + sage: S = SimplicialComplex(is_mutable=False) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: x.is_identity() True """ return self.to_matrix().is_one() @@ -544,17 +556,19 @@ def is_surjective(self) -> bool: EXAMPLES:: - sage: S1 = simplicial_complexes.Sphere(1) # optional - sage.graphs - sage: H = Hom(S1, S1) # optional - sage.graphs - sage: flip = H({0:0, 1:2, 2:1}) # optional - sage.graphs - sage: flip.associated_chain_complex_morphism().is_surjective() # optional - sage.graphs + sage: # needs sage.graphs + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: flip = H({0:0, 1:2, 2:1}) + sage: flip.associated_chain_complex_morphism().is_surjective() True - sage: pt = simplicial_complexes.Simplex(0) # optional - sage.graphs - sage: inclusion = Hom(pt, S1)({0:2}) # optional - sage.graphs - sage: inclusion.associated_chain_complex_morphism().is_surjective() # optional - sage.graphs + sage: # needs sage.graphs + sage: pt = simplicial_complexes.Simplex(0) + sage: inclusion = Hom(pt, S1)({0:2}) + sage: inclusion.associated_chain_complex_morphism().is_surjective() False - sage: inclusion.associated_chain_complex_morphism(cochain=True).is_surjective() # optional - sage.graphs + sage: inclusion.associated_chain_complex_morphism(cochain=True).is_surjective() True """ m = self.to_matrix() @@ -566,17 +580,19 @@ def is_injective(self): EXAMPLES:: - sage: S1 = simplicial_complexes.Sphere(1) # optional - sage.graphs - sage: H = Hom(S1, S1) # optional - sage.graphs - sage: flip = H({0:0, 1:2, 2:1}) # optional - sage.graphs - sage: flip.associated_chain_complex_morphism().is_injective() # optional - sage.graphs + sage: # needs sage.graphs + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: flip = H({0:0, 1:2, 2:1}) + sage: flip.associated_chain_complex_morphism().is_injective() True - sage: pt = simplicial_complexes.Simplex(0) # optional - sage.graphs - sage: inclusion = Hom(pt, S1)({0:2}) # optional - sage.graphs - sage: inclusion.associated_chain_complex_morphism().is_injective() # optional - sage.graphs + sage: # needs sage.graphs + sage: pt = simplicial_complexes.Simplex(0) + sage: inclusion = Hom(pt, S1)({0:2}) + sage: inclusion.associated_chain_complex_morphism().is_injective() True - sage: inclusion.associated_chain_complex_morphism(cochain=True).is_injective() # optional - sage.graphs + sage: inclusion.associated_chain_complex_morphism(cochain=True).is_injective() False """ return self.to_matrix().right_nullity() == 0 diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index a20b9bc854b..91ae14eda11 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -506,20 +506,21 @@ def pi(self): EXAMPLES:: - sage: S2 = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: phi, M = S2.algebraic_topological_model(QQ) # optional - sage.graphs - sage: phi.pi() # optional - sage.graphs + sage: # needs sage.graphs + sage: S2 = simplicial_complexes.Sphere(2) + sage: phi, M = S2.algebraic_topological_model(QQ) + sage: phi.pi() Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field - sage: phi.pi().in_degree(0) # Every vertex represents a homology class. # optional - sage.graphs + sage: phi.pi().in_degree(0) # Every vertex represents a homology class. [1 1 1 1] - sage: phi.pi().in_degree(1) # No homology in degree 1. # optional - sage.graphs + sage: phi.pi().in_degree(1) # No homology in degree 1. [] The degree 2 homology generator is detected on a single simplex:: - sage: phi.pi().in_degree(2) # optional - sage.graphs + sage: phi.pi().in_degree(2) # needs sage.graphs [0 0 0 1] """ return self._pi @@ -530,16 +531,16 @@ def iota(self): EXAMPLES:: - sage: S2 = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: phi, M = S2.algebraic_topological_model(QQ) # optional - sage.graphs - sage: phi.iota() # optional - sage.graphs + sage: S2 = simplicial_complexes.Sphere(2) # needs sage.graphs + sage: phi, M = S2.algebraic_topological_model(QQ) # needs sage.graphs + sage: phi.iota() # needs sage.graphs Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex:: - sage: phi.iota().in_degree(0) # optional - sage.graphs + sage: phi.iota().in_degree(0) # needs sage.graphs [0] [0] [0] @@ -548,7 +549,7 @@ def iota(self): Lifting the degree two homology class gives the signed sum of all of the 2-simplices:: - sage: phi.iota().in_degree(2) # optional - sage.graphs + sage: phi.iota().in_degree(2) # needs sage.graphs [-1] [ 1] [-1] @@ -564,9 +565,9 @@ def dual(self): EXAMPLES:: - sage: S2 = simplicial_complexes.Sphere(2) # optional - sage.graphs - sage: phi, M = S2.algebraic_topological_model(QQ) # optional - sage.graphs - sage: phi.iota() # optional - sage.graphs + sage: S2 = simplicial_complexes.Sphere(2) # needs sage.graphs + sage: phi, M = S2.algebraic_topological_model(QQ) # needs sage.graphs + sage: phi.iota() # needs sage.graphs Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field @@ -575,22 +576,23 @@ def dual(self): but the degree zero cohomology class needs to be detected on every vertex, and vice versa for degree 2:: - sage: phi.iota().in_degree(0) # optional - sage.graphs + sage: # needs sage.graphs + sage: phi.iota().in_degree(0) [0] [0] [0] [1] - sage: phi.dual().iota().in_degree(0) # optional - sage.graphs + sage: phi.dual().iota().in_degree(0) [1] [1] [1] [1] - sage: phi.iota().in_degree(2) # optional - sage.graphs + sage: phi.iota().in_degree(2) [-1] [ 1] [-1] [ 1] - sage: phi.dual().iota().in_degree(2) # optional - sage.graphs + sage: phi.dual().iota().in_degree(2) [0] [0] [0] diff --git a/src/sage/homology/chains.py b/src/sage/homology/chains.py index ee514bd604c..87c0947c0b0 100644 --- a/src/sage/homology/chains.py +++ b/src/sage/homology/chains.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) +# sage.doctest: needs sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) r""" Chains and cochains diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index c7ea0da39cc..e3d38de4240 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.singular +# sage.doctest: needs sage.libs.singular r""" Free resolutions @@ -131,8 +131,8 @@ def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts sage: Q = R.quo(I) sage: Q.is_integral_domain() False - sage: xb, yb = Q.gens() - sage: FreeResolution(Q.ideal([xb])) # has torsion + sage: xb, yb = Q.gens() # needs sage.rings.function_field + sage: FreeResolution(Q.ideal([xb])) # has torsion # needs sage.rings.function_field Traceback (most recent call last): ... NotImplementedError: the ring must be a polynomial ring using Singular diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index b661d5fb2e5..0c01ad6f423 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.singular +# sage.doctest: needs sage.libs.singular r""" Graded free resolutions @@ -47,7 +47,7 @@ sage: R. = QQ[] sage: S. = QQ[] sage: phi = S.hom([s, s*t, s*t^2, s*t^3]) - sage: I = phi.kernel(); I + sage: I = phi.kernel(); I # needs sage.rings.function_field Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field sage: P3 = ProjectiveSpace(S) diff --git a/src/sage/homology/hochschild_complex.py b/src/sage/homology/hochschild_complex.py index 8f6041a597e..ea42164ef9d 100644 --- a/src/sage/homology/hochschild_complex.py +++ b/src/sage/homology/hochschild_complex.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat (because all doctests use FreeAlgebra, SymmetricGroupAlgebra, etc.) +# sage.doctest: needs sage.combinat (because all doctests use FreeAlgebra, SymmetricGroupAlgebra, etc.) """ Hochschild Complexes """ diff --git a/src/sage/homology/homology_group.py b/src/sage/homology/homology_group.py index 53db12c1828..8db8a47e568 100644 --- a/src/sage/homology/homology_group.py +++ b/src/sage/homology/homology_group.py @@ -32,13 +32,13 @@ class HomologyGroup_class(AdditiveAbelianGroup_fixed_gens): EXAMPLES:: sage: from sage.homology.homology_group import HomologyGroup - sage: G = AbelianGroup(5, [5,5,7,8,9]); G # optional - sage.groups + sage: G = AbelianGroup(5, [5,5,7,8,9]); G # needs sage.groups Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 sage: H = HomologyGroup(5, ZZ, [5,5,7,8,9]); H C5 x C5 x C7 x C8 x C9 - sage: G == loads(dumps(G)) # optional - sage.groups + sage: G == loads(dumps(G)) # needs sage.groups True - sage: AbelianGroup(4) # optional - sage.groups + sage: AbelianGroup(4) # needs sage.groups Multiplicative Abelian group isomorphic to Z x Z x Z x Z sage: HomologyGroup(4, ZZ) Z x Z x Z x Z @@ -157,11 +157,11 @@ def HomologyGroup(n, base_ring, invfac=None): EXAMPLES:: sage: from sage.homology.homology_group import HomologyGroup - sage: G = AbelianGroup(5, [5,5,7,8,9]); G # optional - sage.groups + sage: G = AbelianGroup(5, [5,5,7,8,9]); G # needs sage.groups Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 sage: H = HomologyGroup(5, ZZ, [5,5,7,8,9]); H C5 x C5 x C7 x C8 x C9 - sage: AbelianGroup(4) # optional - sage.groups + sage: AbelianGroup(4) # needs sage.groups Multiplicative Abelian group isomorphic to Z x Z x Z x Z sage: HomologyGroup(4, ZZ) Z x Z x Z x Z diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py index 5403fe7722b..1b4a69c2e7e 100644 --- a/src/sage/homology/homology_morphism.py +++ b/src/sage/homology/homology_morphism.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs (because all doctests use the catalog simplicial_complexes) +# sage.doctest: needs sage.graphs (because all doctests use the catalog simplicial_complexes) r""" Induced morphisms on homology @@ -198,7 +198,7 @@ def base_ring(self): sage: id = H.identity() sage: id.induced_homology_morphism(QQ).base_ring() Rational Field - sage: id.induced_homology_morphism(GF(13)).base_ring() # optional - sage.rings.finite_rings + sage: id.induced_homology_morphism(GF(13)).base_ring() Finite Field of size 13 """ return self._base_ring @@ -312,7 +312,7 @@ def __eq__(self, other) -> bool: sage: g = Hom(S1, K)({0: 0, 1:0, 2:0}) sage: f.induced_homology_morphism(QQ) == g.induced_homology_morphism(QQ) True - sage: f.induced_homology_morphism(QQ) == g.induced_homology_morphism(GF(2)) # optional - sage.rings.finite_rings + sage: f.induced_homology_morphism(QQ) == g.induced_homology_morphism(GF(2)) False sage: id = Hom(K, K).identity() # different domain sage: f.induced_homology_morphism(QQ) == id.induced_homology_morphism(QQ) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index f9a388b0f87..bf53c7b6113 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) +# sage.doctest: needs sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) """ Homology and cohomology with a basis @@ -135,6 +135,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): `\Delta`-complex model can be obtained by sending `x` to `u+v`, `y` to `v`. :: + sage: # needs sage.groups sage: X = simplicial_sets.RealProjectiveSpace(6) sage: H_X = X.cohomology_ring(GF(2)) sage: a = H_X.basis()[1,0] @@ -146,6 +147,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): All products of positive-dimensional elements in a suspension should be zero:: + sage: # needs sage.groups sage: Y = X.suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] @@ -453,6 +455,7 @@ class CohomologyRing(HomologyVectorSpaceWithBasis): sage: y.Sq(2) h^{4,0} + sage: # needs sage.groups sage: Y = simplicial_sets.RealProjectiveSpace(6).suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] @@ -577,9 +580,9 @@ def product_on_basis(self, li, ri): and simplicial sets:: sage: from sage.topology.simplicial_set_examples import RealProjectiveSpace - sage: RP5 = RealProjectiveSpace(5) - sage: x = RP5.cohomology_ring(GF(2)).basis()[1,0] - sage: x**4 + sage: RP5 = RealProjectiveSpace(5) # needs sage.groups + sage: x = RP5.cohomology_ring(GF(2)).basis()[1,0] # needs sage.groups + sage: x**4 # needs sage.groups h^{4,0} A non-connected example:: @@ -718,9 +721,9 @@ def Sq(self, i): one machine, 20 seconds with a simplicial complex, 4 ms with a simplicial set). :: - sage: RP4_ss = simplicial_sets.RealProjectiveSpace(4) - sage: z_ss = RP4_ss.cohomology_ring(GF(2)).basis()[3,0] - sage: z_ss.Sq(1) + sage: RP4_ss = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups + sage: z_ss = RP4_ss.cohomology_ring(GF(2)).basis()[3,0] # needs sage.groups + sage: z_ss.Sq(1) # needs sage.groups h^{4,0} TESTS:: diff --git a/src/sage/homology/tests.py b/src/sage/homology/tests.py index 0915ebbfb03..ab55168ac16 100644 --- a/src/sage/homology/tests.py +++ b/src/sage/homology/tests.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules """ Tests for chain complexes, simplicial complexes, etc. diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index 9ca4203b648..a334c241127 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -1016,7 +1016,7 @@ def _sympysage_true(self): #------------------------------------------------------------------ -from sage.repl.ipython_extension import run_once +from sage.misc.misc import run_once @run_once def sympy_init(): diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 411e7cb6bca..6adbe4df4b2 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -2551,7 +2551,7 @@ def __call__(self, item): True """ if self._name_unoriented: - if type(item) == str: + if isinstance(item, str): # allow input as dual number according to naming item = int(item, 2) return self[item] diff --git a/src/sage/lfunctions/lcalc.py b/src/sage/lfunctions/lcalc.py index d791460039b..73246cdd81e 100644 --- a/src/sage/lfunctions/lcalc.py +++ b/src/sage/lfunctions/lcalc.py @@ -30,9 +30,14 @@ import os from sage.structure.sage_object import SageObject +from sage.misc.lazy_import import lazy_import from sage.misc.pager import pager -import sage.rings.all -import sage.schemes.elliptic_curves.ell_generic +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ + +lazy_import('sage.rings.complex_mpfr', 'ComplexField') +lazy_import('sage.rings.real_mpfr', 'RealField') +lazy_import('sage.schemes.elliptic_curves.ell_generic', 'EllipticCurve_generic', as_='EllipticCurve') prec = 32 @@ -75,9 +80,8 @@ def _compute_L(self, L): if L == 'tau': return '--tau' return L - import sage.schemes.all - if sage.schemes.elliptic_curves.ell_generic.is_EllipticCurve(L): - if L.base_ring() == sage.rings.all.RationalField(): + if isinstance(L, EllipticCurve): + if L.base_ring() == QQ: L = L.minimal_model() return '-e --a1 %s --a2 %s --a3 %s --a4 %s --a6 %s' % tuple(L.a_invariants()) raise TypeError("$L$-function of %s not known" % L) @@ -127,7 +131,7 @@ def zeros(self, n, L=''): [0.000000000, 5.00317001, 6.87039122] """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) + RR = RealField(prec) X = self('-z %s %s' % (int(n), L)) return [RR(z) for z in X.split()] @@ -162,7 +166,7 @@ def zeros_in_interval(self, x, y, stepsize, L=''): [(14.1347251, 0.184672916), (21.0220396, -0.0677893290), (25.0108576, -0.0555872781)] """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) + RR = RealField(prec) X = self('--zeros-interval -x %s -y %s --stepsize=%s %s' % ( float(x), float(y), float(stepsize), L)) return [tuple([RR(z) for z in t.split()]) for t in X.split('\n')] @@ -193,7 +197,7 @@ def value(self, s, L=''): 2.69261988568132 - 0.0203860296025982*I """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) + CC = ComplexField(prec) s = CC(s) x, y = self('-v -x %s -y %s %s' % (s.real(), s.imag(), L)).split() return CC((float(x), float(y))) @@ -275,7 +279,7 @@ def values_along_line(self, s0, s1, number_samples, L=''): """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) + CC = ComplexField(prec) s0 = CC(s0) s1 = CC(s1) v = self('--value-line-segment -x %s -y %s -X %s -Y %s --number-samples %s %s' % ( @@ -343,8 +347,7 @@ def twist_values(self, s, dmin, dmax, L=''): 0.373691713 + 0.0*I """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) - Z = sage.rings.all.Integer + CC = ComplexField(prec) s = CC(s) typ = '--twist-quadratic' dmin = int(dmin) @@ -358,7 +361,7 @@ def twist_values(self, s, dmin, dmax, L=''): return w for a in v.split('\n'): d, x, y = a.split() - w.append((Z(d), CC(x, y))) + w.append((ZZ(d), CC(x, y))) return w def twist_zeros(self, n, dmin, dmax, L=''): @@ -393,8 +396,7 @@ def twist_zeros(self, n, dmin, dmax, L=''): {-3: [8.03973716, 11.2492062, 15.7046192], 5: [6.64845335, 9.83144443, 11.9588456]} """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) - Z = sage.rings.all.Integer + RR = RealField(prec) typ = '--twist-quadratic' n = int(n) v = self('-z %s %s --start %s --finish %s %s' % ( @@ -405,7 +407,7 @@ def twist_zeros(self, n, dmin, dmax, L=''): for a in v.split('\n'): d, x = a.split() x = RR(x) - d = Z(d) + d = ZZ(d) if d in w: w[d].append(x) else: @@ -439,10 +441,9 @@ def analytic_rank(self, L=''): 1 """ L = self._compute_L(L) - Z = sage.rings.all.Integer s = self('--rank-compute %s' % L) i = s.find('equals') - return Z(s[i + 6:]) + return ZZ(s[i + 6:]) # An instance diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index 4cf14233aa2..796e2672d82 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -51,7 +51,7 @@ from sage.structure.sage_object import SageObject from sage.misc.pager import pager from sage.misc.verbose import verbose -import sage.rings.all +from sage.rings.integer import Integer class Sympow(SageObject): @@ -237,7 +237,7 @@ def modular_degree(self, E): if i == -1: print(self._fix_err(v)) raise RuntimeError("failed to compute modular degree") - return sage.rings.all.Integer(v[i + len(s):]) + return Integer(v[i + len(s):]) def analytic_rank(self, E): r""" @@ -296,7 +296,7 @@ def analytic_rank(self, E): print(self._fix_err(v)) raise RuntimeError("failed to compute analytic rank") j = v.rfind(':') - r = sage.rings.all.Integer(v[i + len(s):j]) + r = Integer(v[i + len(s):j]) i = v.rfind(' ') L = v[i + 1:] return r, L diff --git a/src/sage/libs/coxeter3/coxeter.pyx b/src/sage/libs/coxeter3/coxeter.pyx index b6444ea177d..492afca2768 100644 --- a/src/sage/libs/coxeter3/coxeter.pyx +++ b/src/sage/libs/coxeter3/coxeter.pyx @@ -86,8 +86,10 @@ cdef class String: sage: all([tb > ta1, tb >= ta1, tb >= tb]) # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s = repr(self) o = repr(other) @@ -199,8 +201,10 @@ cdef class Type: sage: all([tb > ta1, tb >= ta1, tb >= tb]) # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s = repr(self) o = repr(other) @@ -363,8 +367,10 @@ cdef class CoxGroup(SageObject): sage: B4 >= A5 # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s_t = self.type() o_t = other.type() @@ -839,8 +845,10 @@ cdef class CoxGroupElement: sage: w1 != v1 # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s_p = self.parent_group() o_p = other.parent_group() diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 35067c59c0f..1dc53c81f67 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -47,16 +47,23 @@ cdef Obj make_gap_list(sage_list) except NULL: The list of the elements in ``a`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem - for x in sage_list: - if not isinstance(x, GapElement): - elem = libgap(x) - else: - elem = x + cdef int i + try: + GAP_Enter() + l = GAP_NewPlist(0) - AddList(l.value, elem.value) - return l.value + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = libgap(x) + else: + elem = x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: @@ -77,22 +84,30 @@ cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: The list of the elements in ``sage_list`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem cdef GapElement one + cdef int i if gap_ring is not None: one = gap_ring.One() else: one = libgap(1) - for x in sage_list: - if not isinstance(x, GapElement): - elem = libgap(x) - elem = elem * one - else: - elem = x - AddList(l.value, elem.value) - return l.value + try: + GAP_Enter() + l = GAP_NewPlist(0) + + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = libgap(x) + elem = elem * one + else: + elem = x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef char *capture_stdout(Obj func, Obj obj): diff --git a/src/sage/libs/gap/gap_includes.pxd b/src/sage/libs/gap/gap_includes.pxd index 32ee925001f..840b8a0042e 100644 --- a/src/sage/libs/gap/gap_includes.pxd +++ b/src/sage/libs/gap/gap_includes.pxd @@ -96,10 +96,6 @@ cdef extern from "gap/lists.h" nogil: Obj ELM_LIST(Obj lst, int pos) -cdef extern from "gap/listfunc.h" nogil: - void AddList(Obj list, Obj obj) - - cdef extern from "gap/objects.h" nogil: bint IS_MUTABLE_OBJ(Obj obj) Obj SHALLOW_COPY_OBJ(Obj obj) diff --git a/src/sage/manifolds/differentiable/symplectic_form_test.py b/src/sage/manifolds/differentiable/symplectic_form_test.py index 78c4fcaffd0..5bc519af6d3 100644 --- a/src/sage/manifolds/differentiable/symplectic_form_test.py +++ b/src/sage/manifolds/differentiable/symplectic_form_test.py @@ -35,7 +35,7 @@ def test_new_instance_repr(self, omega: SymplecticForm): def test_new_instance_same_type(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage - assert type(omega1) == type(omega) + assert type(omega1) is type(omega) def test_new_instance_same_parent(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py index 3e9f03a579a..b92d8a25d82 100644 --- a/src/sage/manifolds/subset.py +++ b/src/sage/manifolds/subset.py @@ -901,7 +901,7 @@ def subset_digraph(self, loops=False, quotient=False, open_covers=False, points= sage: U = M.open_subset('U'); V = M.open_subset('V'); W = M.open_subset('W') sage: D = M.subset_digraph(); D Digraph on 4 vertices - sage: D.edges(key=lambda e: (e[0]._name, e[1]._name)) + sage: D.edges(sort=True, key=lambda e: (e[0]._name, e[1]._name)) [(Set {U} of open subsets of the 3-dimensional differentiable manifold M, Set {M} of open subsets of the 3-dimensional differentiable manifold M, None), diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index dc057d1dce5..48bbd1159d6 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -268,7 +268,7 @@ cdef class MatrixMatrixAction(MatrixMulAction): B = B.dense_matrix() else: A = A.dense_matrix() - assert type(A) == type(B), (type(A), type(B)) + assert type(A) is type(B), (type(A), type(B)) prod = A._matrix_times_matrix_(B) if A._subdivisions is not None or B._subdivisions is not None: Asubs = A.subdivisions() diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index f66d16bc7d3..f52780e8b95 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -21,6 +21,7 @@ from cysignals.signals cimport sig_check MatrixSpace = None from sage.rings.integer_ring import ZZ +from sage.rings.integer cimport Integer from sage.structure.coerce cimport (coercion_model, is_numpy_type, py_scalar_parent) from sage.structure.element cimport Element, RingElement, Vector @@ -847,6 +848,24 @@ cdef class MatrixArgs: Traceback (most recent call last): ... ValueError: sequence too short (expected length 6, got 1) + + Check github issue #36065: + + sage: class MyAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): + ....: def __bool__(self): + ....: raise ValueError + sage: matrix(1, 1, MyAlgebraicNumber(0)) + [0] + sage: matrix(1, 1, MyAlgebraicNumber(3)) + [3] + sage: matrix(1, 2, MyAlgebraicNumber(0)) + Traceback (most recent call last): + ... + TypeError: scalar matrix must be square if the value cannot be determined to be zero + sage: matrix(1, 2, MyAlgebraicNumber(3)) + Traceback (most recent call last): + ... + TypeError: scalar matrix must be square if the value cannot be determined to be zero """ self.finalize() return self @@ -924,11 +943,18 @@ cdef class MatrixArgs: raise AssertionError(f"nrows={self.nrows} ncols={self.ncols} base={self.base} type={self.typ}") # Non-zero scalar matrices must be square + # also ensure type is MA_ENTRIES_ZERO for scalar zero matrices if self.typ == MA_ENTRIES_SCALAR: - if self.nrows != self.ncols: - if self.entries: - raise TypeError("nonzero scalar matrix must be square") - self.typ = MA_ENTRIES_ZERO + try: + if not self.entries: + self.typ = MA_ENTRIES_ZERO + except Exception: + # "not self.entries" has failed, self.entries cannot be determined to be zero + if self.nrows != self.ncols: + raise TypeError("scalar matrix must be square if the value cannot be determined to be zero") + if self.typ == MA_ENTRIES_SCALAR and self.nrows != self.ncols: + # self.typ is still SCALAR -> "not self.entries" has successfully evaluated, to False + raise TypeError("nonzero scalar matrix must be square") if self.sparse == -1: self.sparse = (self.typ & MA_FLAG_SPARSE) != 0 @@ -1219,12 +1245,14 @@ cdef class MatrixArgs: # hurt to do these first. if self.entries is None: return MA_ENTRIES_ZERO + if isinstance(self.entries, (int, float, complex, Integer)): + if self.entries: + return MA_ENTRIES_SCALAR + return MA_ENTRIES_ZERO if isinstance(self.entries, (list, tuple)): return self.sequence_type() if isinstance(self.entries, dict): return MA_ENTRIES_MAPPING - if isinstance(self.entries, (int, float, complex)): - return MA_ENTRIES_SCALAR # Note: some objects are callable, iterable and act like a # scalar, e.g. polynomials. So the order of these checks diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index 6043b69077c..1f2cb38a65c 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -484,7 +484,7 @@ cdef class MatroidExtensions(LinearSubclasses): """ if M.full_rank() == 0: pass - if type(M) == BasisMatroid: + if isinstance(M, BasisMatroid): BM = M else: BM = BasisMatroid(M) diff --git a/src/sage/matroids/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index dd312daf138..54c68e637c0 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -396,7 +396,7 @@ cdef class LeanMatrix: cdef long i cdef LeanMatrix A if isinstance(left, LeanMatrix): - if type(left) == type(right): + if type(left) is type(right): return (left)._matrix_times_matrix_(right) else: return NotImplemented @@ -457,7 +457,7 @@ cdef class LeanMatrix: return NotImplemented if not isinstance(left, LeanMatrix) or not isinstance(right, LeanMatrix): return NotImplemented - if type(left) != type(right): + if type(left) is not type(right): return NotImplemented if op == Py_EQ: res = True diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 11f6b4a2656..61452e80c48 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -4451,7 +4451,7 @@ cdef class TernaryMatroid(LinearMatroid): """ if certificate: return self._is_isomorphic(other), self._isomorphism(other) - if type(other) == TernaryMatroid: + if isinstance(other, TernaryMatroid): return self.is_field_isomorphic(other) else: return LinearMatroid._is_isomorphic(self, other) @@ -6152,7 +6152,7 @@ cdef class RegularMatroid(LinearMatroid): """ if certificate: return self._is_isomorphic(other), self._isomorphism(other) - if type(other) == RegularMatroid: + if isinstance(other, RegularMatroid): return self.is_field_isomorphic(other) else: return LinearMatroid._is_isomorphic(self, other) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index d7eec3a8cda..090dea33293 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -38,8 +38,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import contextlib +import functools import os import pdb +import sys import warnings from .lazy_string import lazy_string @@ -1132,3 +1135,68 @@ def inject_variable_test(name, value, depth): inject_variable(name, value) else: inject_variable_test(name, value, depth - 1) + + +# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop +def run_once(func): + """ + Runs a function (successfully) only once. + + The running can be reset by setting the ``has_run`` attribute to False + + TESTS:: + + sage: from sage.repl.ipython_extension import run_once + sage: @run_once + ....: def foo(work): + ....: if work: + ....: return 'foo worked' + ....: raise RuntimeError("foo didn't work") + sage: foo(False) + Traceback (most recent call last): + ... + RuntimeError: foo didn't work + sage: foo(True) + 'foo worked' + sage: foo(False) + sage: foo(True) + """ + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not wrapper.has_run: + result = func(*args, **kwargs) + wrapper.has_run = True + return result + wrapper.has_run = False + return wrapper + + +@contextlib.contextmanager +def increase_recursion_limit(increment): + r""" + Context manager to temporarily change the Python maximum recursion depth. + + INPUT: + + - `increment`: increment to add to the current limit + + EXAMPLES:: + + sage: from sage.misc.misc import increase_recursion_limit + sage: def rec(n): None if n == 0 else rec(n-1) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + sage: with increase_recursion_limit(10000): rec(10000) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + """ + old_limit = sys.getrecursionlimit() + sys.setrecursionlimit(old_limit + increment) + try: + yield + finally: + sys.setrecursionlimit(old_limit) diff --git a/src/sage/misc/replace_dot_all.py b/src/sage/misc/replace_dot_all.py index ebb9a83dfff..3415ea83058 100644 --- a/src/sage/misc/replace_dot_all.py +++ b/src/sage/misc/replace_dot_all.py @@ -298,7 +298,7 @@ def process_line(location, line, replacements, row_index, verbose=False): sage: from sage.misc.replace_dot_all import * sage: location = os.path.join(sage.env.SAGE_SRC, 'sage/plot/arc.py') sage: replacements = find_replacements(location, package_regex='sage[.]plot[.]all', verbose=True); replacements - [[471, 24, 'from sage.plot.graphics import Graphics']] + [[476, 24, 'from sage.plot.graphics import Graphics']] sage: with open(location, "r") as file: ....: lines = file.readlines() sage: row_index, col_number, *_ = replacements[0] @@ -385,7 +385,8 @@ def make_replacements_in_file(location, package_regex=None, verbose=False, outpu write_file.write(replaced_content) # overwriting the old file contents with the new/replaced content -def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex=None, verbose=False): +def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex=None, verbose=False, *, + excluded_file_regex=r'auto-methods|replace_dot_all'): r""" Replace ``import`` statements in the files in directory ``dir`` matching the regex pattern ``file_regex``. @@ -396,6 +397,7 @@ def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex - ``package_regex`` -- (default: :obj:`default_package_regex`) a regular expression matching the ``sage.PAC.KAGE.all`` package names from which we do not want to import. - ``verbose`` -- if True, print statements when interesting examples are found + - ``excluded_file_regex`` -- a regular expression matching the file names to exclude EXAMPLES:: @@ -404,14 +406,14 @@ def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex """ global numberFiles, numberFilesMatchingRegex file_regex = re.compile(file_regex) + excluded_file_regex = re.compile(excluded_file_regex) for root, dirs, files in os.walk(dir, topdown=False): for name in files: numberFiles += 1 - if file_regex.search(name): + if file_regex.search(name) and not excluded_file_regex.search(name): numberFilesMatchingRegex += 1 location = os.path.join(root, name) - if location.find('replace_dot_all') == -1: # to avoid changing anything in this file itself - make_replacements_in_file(location, package_regex, verbose) + make_replacements_in_file(location, package_regex, verbose) # ******************************************************** EXECUTES MAIN FUNCTION ********************************************************************** diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 05a9c16b9a1..7f59627139a 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -33,6 +33,8 @@ from copy import copy from random import randrange +import sage.rings.abc + from sage.arith.functions import lcm as LCM from sage.arith.misc import divisors, next_prime, is_prime from sage.categories.modular_abelian_varieties import ModularAbelianVarieties @@ -55,7 +57,6 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import QQbar from sage.rings.rational_field import QQ from sage.rings.ring import is_Ring from sage.schemes.elliptic_curves.constructor import EllipticCurve @@ -67,6 +68,7 @@ lazy_import('sage.databases.cremona', ['cremona_letter_code', 'CremonaDatabase']) + from . import homspace from . import lseries from .morphism import HeckeOperator, Morphism, DegeneracyMap @@ -798,8 +800,8 @@ def _Hom_(self, B, cat=None): L = B.base_field() if K == L: F = K - elif K == QQbar or L == QQbar: - F = QQbar + elif isinstance(K, sage.rings.abc.AlgebraicField) or isinstance(L, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import QQbar as F else: # TODO -- improve this raise ValueError("please specify a category") @@ -997,7 +999,7 @@ def intersection(self, other): for v in V.coordinate_module(S).basis()] if A.dimension() > 0: - finitegroup_base_field = QQbar + from sage.rings.qqbar import QQbar as finitegroup_base_field else: finitegroup_base_field = self.base_field() G = self.finite_subgroup(gens, field_of_definition=finitegroup_base_field) @@ -3126,7 +3128,7 @@ def finite_subgroup(self, X, field_of_definition=None, check=True): raise ValueError("X must be a subgroup of self.") if field_of_definition is None: - field_of_definition = QQbar + from sage.rings.qqbar import QQbar as field_of_definition return FiniteSubgroup_lattice( self, X, field_of_definition=field_of_definition, check=check) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 3f4f0ffbd8f..ec76a0f5e26 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -97,6 +97,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import sage.rings.abc + +from sage.misc.lazy_import import lazy_import from sage.modular.abvar.torsion_point import TorsionPoint from sage.modules.module import Module from sage.modules.free_module import is_FreeModule @@ -105,7 +108,6 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.qqbar import QQbar from sage.rings.rational_field import QQ from sage.arith.functions import lcm from sage.misc.misc_c import prod @@ -521,7 +523,7 @@ def _repr_(self): 'Finite subgroup with invariants [3, 3, 3, 3, 3, 3, 3, 3, 3, 3] over QQ of Abelian variety J0(42) of dimension 5' """ K = self.__field_of_definition - if K == QQbar: + if isinstance(K, sage.rings.abc.AlgebraicField): field = "QQbar" elif K == QQ: field = "QQ" @@ -750,6 +752,8 @@ def subgroup(self, gens): sage: H == G.subgroup([[1/11,0,0,0]]) True """ + from sage.rings.qqbar import QQbar + if not isinstance(gens, (tuple, list)): raise TypeError("gens must be a list or tuple") A = self.abelian_variety() @@ -815,7 +819,7 @@ def invariants(self): class FiniteSubgroup_lattice(FiniteSubgroup): - def __init__(self, abvar, lattice, field_of_definition=QQbar, check=True): + def __init__(self, abvar, lattice, field_of_definition=None, check=True): """ A finite subgroup of a modular abelian variety that is defined by a given lattice. @@ -841,6 +845,8 @@ def __init__(self, abvar, lattice, field_of_definition=QQbar, check=True): sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 """ + if field_of_definition is None: + from sage.rings.qqbar import QQbar as field_of_definition if check: from .abvar import is_ModularAbelianVariety if not is_FreeModule(lattice) or lattice.base_ring() != ZZ: diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 1b29df45c1b..6d96cc0fabe 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -186,14 +186,14 @@ from . import morphism import sage.rings.integer_ring -import sage.rings.all +from sage.rings.infinity import Infinity from sage.rings.ring import Ring from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import Matrix, identity_matrix from sage.structure.element import is_Matrix -ZZ = sage.rings.integer_ring.ZZ +from sage.rings.integer_ring import ZZ class Homspace(HomsetWithBase): @@ -882,7 +882,7 @@ def index_in(self, other, check=True): M = self.free_module() N = other.free_module() if M.rank() < N.rank(): - return sage.rings.all.Infinity + return Infinity return M.index_in(N) def index_in_saturation(self): diff --git a/src/sage/modular/arithgroup/all.py b/src/sage/modular/arithgroup/all.py index 9f312be37d0..d4fb241d1f9 100644 --- a/src/sage/modular/arithgroup/all.py +++ b/src/sage/modular/arithgroup/all.py @@ -9,7 +9,8 @@ from .congroup_gamma import Gamma_constructor as Gamma, is_Gamma from .congroup_sl2z import SL2Z, is_SL2Z -from .arithgroup_perm import ArithmeticSubgroup_Permutation +from sage.misc.lazy_import import lazy_import +lazy_import('sage.modular.arithgroup.arithgroup_perm', 'ArithmeticSubgroup_Permutation') from .congroup import (degeneracy_coset_representatives_gamma0, degeneracy_coset_representatives_gamma1) diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 892c8de62d2..844d8db7165 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -885,12 +885,12 @@ def index(self): def generalised_level(self): r""" - Return the generalised level of self, i.e. the least common multiple of + Return the generalised level of ``self``, i.e., the least common multiple of the widths of all cusps. - If self is *even*, Wohlfart's theorem tells us that this is equal to - the (conventional) level of self when self is a congruence subgroup. - This can fail if self is odd, but the actual level is at most twice the + If ``self`` is *even*, Wohlfart's theorem tells us that this is equal to + the (conventional) level of ``self`` when ``self`` is a congruence subgroup. + This can fail if ``self`` is odd, but the actual level is at most twice the generalised level. See the paper by Kiming, Schuett and Verrill for more examples. @@ -898,7 +898,8 @@ def generalised_level(self): sage: Gamma0(18).generalised_level() 18 - sage: sage.modular.arithgroup.arithgroup_perm.HsuExample18().generalised_level() + sage: from sage.modular.arithgroup.arithgroup_perm import HsuExample18 + sage: HsuExample18().generalised_level() 24 In the following example, the actual level is twice the generalised diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index cfe2da14117..20da4f05b3e 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -40,7 +40,7 @@ def GammaH_constructor(level, H): r""" Return the congruence subgroup `\Gamma_H(N)`, which is the subgroup of `SL_2(\ZZ)` consisting of matrices of the form `\begin{pmatrix} a & b \\ - c & d \end{pmatrix}` with `N | c` and `a, b \in H`, for `H` a specified + c & d \end{pmatrix}` with `N | c` and `a, d \in H`, for `H` a specified subgroup of `(\ZZ/N\ZZ)^\times`. INPUT: @@ -163,7 +163,7 @@ class GammaH_class(CongruenceSubgroup): The congruence subgroup `\Gamma_H(N)` for some subgroup `H \trianglelefteq (\ZZ / N\ZZ)^\times`, which is the subgroup of `\SL_2(\ZZ)` consisting of matrices of the form `\begin{pmatrix} a & - b \\ c & d \end{pmatrix}` with `N \mid c` and `a, b \in H`. + b \\ c & d \end{pmatrix}` with `N \mid c` and `a, d \in H`. TESTS: diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index ce37fcc86b5..1bf60ecbefb 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -41,11 +41,7 @@ from copy import copy from collections import deque -from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra from sage.arith.misc import gcd, xgcd, kronecker_symbol, fundamental_discriminant -from sage.graphs.graph import Graph -from sage.interfaces.magma import magma -from sage.libs.pari.all import pari from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method @@ -62,14 +58,19 @@ from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField -from sage.rings.padics.factory import Qp, Zp from sage.rings.padics.precision_error import PrecisionError from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation lazy_import("sage.plot.colors", "rainbow") +lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra') +lazy_import('sage.graphs.graph', 'Graph') +lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.plot.colors', 'rainbow') +lazy_import('sage.rings.number_field.number_field', 'NumberField') +lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) + class DoubleCosetReduction(SageObject): r""" diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index b068af0cd15..6428c7357da 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -46,6 +46,7 @@ from sage.matrix.constructor import Matrix, zero_matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.modular.btquotients.btquotient import DoubleCosetReduction from sage.modular.hecke.all import AmbientHeckeModule, HeckeModuleElement @@ -56,7 +57,6 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.rings.padics.factory import Qp from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR @@ -64,6 +64,9 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.structure.unique_representation import UniqueRepresentation +lazy_import('sage.rings.padics.factory', 'Qp') + + # Need this to be pickleable diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 71192ec80b2..098c7e52a24 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -28,7 +28,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.pari.all import pari, pari_gen from sage.misc.fast_methods import Singleton from sage.modular.modsym.p1list import lift_to_sl2z_llong from sage.rings.infinity import Infinity, InfinityRing @@ -41,6 +40,11 @@ from sage.structure.parent import Parent from sage.structure.richcmp import richcmp +try: + from sage.libs.pari.all import pari, pari_gen +except ImportError: + pari_gen = () + class Cusp(Element): """ diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 68b4eaaa4f1..caf47f48362 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -62,23 +62,21 @@ import sage.rings.abc from sage.arith.functions import lcm -from sage.arith.misc import bernoulli, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation +from sage.arith.misc import bernoulli, binomial, factorial, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation from sage.categories.map import Map from sage.categories.objects import Objects -from sage.functions.other import binomial, factorial -from sage.libs.pari import pari from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById from sage.misc.functional import round +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField, NumberField, NumberField_generic from sage.rings.power_series_ring import PowerSeriesRing -from sage.rings.rational_field import RationalField, QQ, is_RationalField +from sage.rings.rational_field import QQ, is_RationalField from sage.rings.ring import is_Ring from sage.structure.element import MultiplicativeGroupElement from sage.structure.factory import UniqueFactory @@ -87,8 +85,11 @@ from sage.structure.richcmp import richcmp from sage.structure.sequence import Sequence +lazy_import('sage.libs.pari', 'pari') +lazy_import('sage.rings.number_field.number_field', ['CyclotomicField', 'NumberField', 'NumberField_generic']) -def trivial_character(N, base_ring=RationalField()): + +def trivial_character(N, base_ring=QQ): r""" Return the trivial character of the given modulus, with values in the given base ring. @@ -135,14 +136,14 @@ def kronecker_character(d): raise ValueError("d must be nonzero") D = fundamental_discriminant(d) - G = DirichletGroup(abs(D), RationalField()) + G = DirichletGroup(abs(D), QQ) return G([kronecker(D, u) for u in G.unit_gens()]) def kronecker_character_upside_down(d): """ Return the quadratic Dirichlet character (./d) of conductor d, for - d0. + d > 0. EXAMPLES:: @@ -157,11 +158,11 @@ def kronecker_character_upside_down(d): if d <= 0: raise ValueError("d must be positive") - G = DirichletGroup(d, RationalField()) + G = DirichletGroup(d, QQ) return G([kronecker(u.lift(), d) for u in G.unit_gens()]) -def is_DirichletCharacter(x): +def is_DirichletCharacter(x) -> bool: r""" Return ``True`` if ``x`` is of type ``DirichletCharacter``. @@ -639,7 +640,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): .. MATH:: \sum_{a=1}^N \frac{\varepsilon(a) t e^{at}}{e^{Nt}-1} - = sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. + = \sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. ALGORITHM: @@ -707,8 +708,9 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): def S(n): return sum(v[r] * r**n for r in range(1, N)) - ber = K(sum(binomial(k, j) * bernoulli(j, **opts) * - N**(j - 1) * S(k - j) for j in range(k + 1))) + + ber = sum(binomial(k, j) * bernoulli(j, **opts) * + N**(j - 1) * S(k - j) for j in range(k + 1)) elif algorithm == "definition": # This is better since it computes the same thing, but requires # no arith in a poly ring over a number field. @@ -721,7 +723,7 @@ def S(n): h = [0] + [g * ((n * t).exp(prec)) for n in range(1, N + 1)] ber = sum([self(a) * h[a][k] for a in range(1, N + 1)]) * factorial(k) else: - raise ValueError("algorithm = '%s' unknown" % algorithm) + raise ValueError(f"algorithm = '{algorithm}' unknown") if cache: self.__bernoulli[k] = ber @@ -913,9 +915,6 @@ def fixed_field_polynomial(self, algorithm="pari"): # this algorithm was written by Francis Clarke see issue #9407 - from sage.rings.finite_rings.integer_mod_ring import IntegerModRing - from sage.rings.integer_ring import IntegerRing - ZZ = IntegerRing() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import matrix @@ -998,7 +997,7 @@ def fixed_field_polynomial(self, algorithm="pari"): G, chi = self._pari_init_() K = pari.charker(G, chi) H = pari.galoissubcyclo(G, K) - P = PolynomialRing(RationalField(), "x") + P = PolynomialRing(QQ, "x") x = P.gen() return H.sage({"x": x}) @@ -2943,7 +2942,7 @@ def _automorphisms(self): if p == 0: Auts = [e for e in range(1, n) if gcd(e, n) == 1] else: - if not ZZ(p).is_prime(): + if not Integer(p).is_prime(): raise NotImplementedError("Automorphisms for finite non-field base rings not implemented") # The automorphisms in characteristic p are # k-th powering for diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 3e4ae52f00f..6b03862d6dd 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -21,9 +21,8 @@ from . import module from . import submodule -import sage.modules.all - -import sage.rings.all +from sage.modules.free_module import FreeModule, is_FreeModule +from sage.rings.integer import Integer import sage.arith.all as arith @@ -70,7 +69,7 @@ def __init__(self, base_ring, rank, level, weight, category=None): sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4) Generic ambient Hecke module of rank 3, level 2 and weight 4 over Rational Field """ - rank = sage.rings.all.Integer(rank) + rank = Integer(rank) if rank < 0: raise ValueError("rank (=%s) must be nonnegative" % rank) self.__rank = rank @@ -491,7 +490,7 @@ def free_module(self): try: return self.__free_module except AttributeError: - M = sage.modules.all.FreeModule(self.base_ring(), self.rank()) + M = FreeModule(self.base_ring(), self.rank()) self.__free_module = M return M @@ -917,7 +916,7 @@ def old_submodule(self, p=None): def submodule(self, M, Mdual=None, check=True): """ - Return the Hecke submodule of self generated by M, which may be a + Return the Hecke submodule of ``self`` generated by `M`, which may be a submodule of the free module of self, or a list of elements of self. EXAMPLES:: @@ -927,7 +926,7 @@ def submodule(self, M, Mdual=None, check=True): Modular Forms subspace of dimension 2 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(37) of weight 2 over Rational Field """ if check: - if not sage.modules.free_module.is_FreeModule(M): + if not is_FreeModule(M): V = self.free_module() if isinstance(M, (list, tuple)): M = V.span([V(x.element()) for x in M]) diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index efcd8c9c848..e50b9d723e8 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -21,8 +21,8 @@ import sage.arith.all as arith from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method +from sage.modules.free_module import is_FreeModule from sage.structure.richcmp import richcmp_method, richcmp_not_equal -import sage.modules.all from . import module @@ -80,7 +80,7 @@ def __init__(self, ambient, submodule, dual_free_module=None, check=True): from . import ambient_module if not isinstance(ambient, ambient_module.AmbientHeckeModule): raise TypeError("ambient must be an ambient Hecke module") - if not sage.modules.free_module.is_FreeModule(submodule): + if not is_FreeModule(submodule): raise TypeError("submodule must be a free module") if not submodule.is_submodule(ambient.free_module()): raise ValueError("submodule must be a submodule of the ambient free module") @@ -94,7 +94,7 @@ def __init__(self, ambient, submodule, dual_free_module=None, check=True): module.HeckeModule_free_module.__init__(self, ambient.base_ring(), ambient.level(), ambient.weight()) if not (dual_free_module is None): - if not sage.modules.free_module.is_FreeModule(dual_free_module): + if not is_FreeModule(dual_free_module): raise TypeError("dual_free_module must be a free module") if dual_free_module.rank() != submodule.rank(): raise ArithmeticError("dual_free_module must have the same rank as submodule") @@ -908,7 +908,7 @@ def submodule(self, M, Mdual=None, check=True): sage: S.submodule(S[0].free_module()) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(18) of weight 4 with sign 0 over Rational Field """ - if not sage.modules.free_module.is_FreeModule(M): + if not is_FreeModule(M): V = self.ambient_module().free_module() if isinstance(M, (list, tuple)): M = V.span([V(x.element()) for x in M]) diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index 4a8ec0195f5..765ce805ed9 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -23,14 +23,16 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import QQbar from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.misc.flatten import flatten from sage.modular.modform.element import Newform from sage.structure.sequence import Sequence +lazy_import('sage.rings.qqbar', 'QQbar') + from .type_space import TypeSpace from .smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic, SmoothCharacterGroupRamifiedQuadratic diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 0e878b99277..b56befe27cb 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -49,15 +49,14 @@ from sage.categories.rings import Rings from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup -from sage.rings.finite_rings.conway_polynomials import conway_polynomial from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.structure.element import MultiplicativeGroupElement, parent @@ -65,6 +64,9 @@ from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.structure.sequence import Sequence +lazy_import('sage.rings.finite_rings.conway_polynomials', 'conway_polynomial') +lazy_import('sage.rings.number_field.number_field', 'NumberField') + class SmoothCharacterGeneric(MultiplicativeGroupElement): r""" diff --git a/src/sage/modular/modform/all.py b/src/sage/modular/modform/all.py index eefb8c3609f..feb1521d3ca 100644 --- a/src/sage/modular/modform/all.py +++ b/src/sage/modular/modform/all.py @@ -14,9 +14,10 @@ from .theta import theta_qexp, theta2_qexp -from .j_invariant import j_invariant_qexp +from sage.misc.lazy_import import lazy_import -from .vm_basis import victor_miller_basis, delta_qexp +lazy_import('sage.modular.modform.j_invariant', 'j_invariant_qexp') +lazy_import('sage.modular.modform.vm_basis', ['victor_miller_basis', 'delta_qexp']) from .hecke_operator_on_qexp import hecke_operator_on_qexp, hecke_operator_on_basis diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index b5c3c543d67..8f14e22ce20 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -75,7 +75,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.integer import Integer import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet @@ -200,7 +200,7 @@ def change_ring(self, base_ring): return self return ambient_R.ModularFormsAmbient_R(self, base_ring=base_ring) - @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return corresponding space of modular symbols with given sign. @@ -220,7 +220,7 @@ def modular_symbols(self, sign=0): ... ValueError: sign must be -1, 0, or 1 """ - sign = rings.Integer(sign) + sign = Integer(sign) return modsym.ModularSymbols(self.character(), weight=self.weight(), sign=sign, diff --git a/src/sage/modular/modform/ambient_g0.py b/src/sage/modular/modform/ambient_g0.py index a409a062984..114718b68b9 100644 --- a/src/sage/modular/modform/ambient_g0.py +++ b/src/sage/modular/modform/ambient_g0.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ import sage.modular.arithgroup.all as arithgroup @@ -43,7 +43,7 @@ def __init__(self, level, weight): sage: type(m) """ - ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma0(level), weight, rings.QQ) + ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma0(level), weight, QQ) def _pari_init_(self): """ diff --git a/src/sage/modular/modform/ambient_g1.py b/src/sage/modular/modform/ambient_g1.py index 75f0de39e15..8c10c861cc0 100644 --- a/src/sage/modular/modform/ambient_g1.py +++ b/src/sage/modular/modform/ambient_g1.py @@ -50,7 +50,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ import sage.modular.arithgroup.all as arithgroup @@ -77,7 +77,7 @@ def __init__(self, group, weight, eis_only): sage: type(m) """ - ambient.ModularFormsAmbient.__init__(self, group, weight, rings.QQ, eis_only=eis_only) + ambient.ModularFormsAmbient.__init__(self, group, weight, QQ, eis_only=eis_only) #################################################################### # Computation of Special Submodules @@ -170,7 +170,7 @@ def __init__(self, level, weight, eis_only): sage: type(m) """ - ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma1(level), weight, rings.QQ, eis_only=eis_only) + ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma1(level), weight, QQ, eis_only=eis_only) #################################################################### # Computation of Special Submodules diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 6e9acf74e36..c30a28354ca 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -34,7 +34,9 @@ import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet -import sage.rings.all as rings +from sage.rings.integer import Integer +from sage.rings.rational_field import Q as QQ +from sage.rings.ring import CommutativeRing from .ambient_eps import ModularFormsAmbient_eps from .ambient_g0 import ModularFormsAmbient_g0_Q @@ -92,38 +94,38 @@ def canonical_parameters(group, level, weight, base_ring): ... ValueError: group and level do not match. """ - weight = rings.Integer(weight) + weight = Integer(weight) if weight <= 0: raise NotImplementedError("weight must be at least 1") if isinstance(group, dirichlet.DirichletCharacter): - if ( group.level() != rings.Integer(level) ): + if ( group.level() != Integer(level) ): raise ValueError("group.level() and level do not match.") group = group.minimize_base_ring() - level = rings.Integer(level) + level = Integer(level) elif arithgroup.is_CongruenceSubgroup(group): - if ( rings.Integer(level) != group.level() ): + if ( Integer(level) != group.level() ): raise ValueError("group.level() and level do not match.") # normalize the case of SL2Z if arithgroup.is_SL2Z(group) or \ - arithgroup.is_Gamma1(group) and group.level() == rings.Integer(1): - group = arithgroup.Gamma0(rings.Integer(1)) + arithgroup.is_Gamma1(group) and group.level() == Integer(1): + group = arithgroup.Gamma0(Integer(1)) elif group is None: pass else: try: - m = rings.Integer(group) + m = Integer(group) except TypeError: raise TypeError("group of unknown type.") - level = rings.Integer(level) + level = Integer(level) if ( m != level ): raise ValueError("group and level do not match.") group = arithgroup.Gamma0(m) - if not isinstance(base_ring, rings.CommutativeRing): + if not isinstance(base_ring, CommutativeRing): raise TypeError("base_ring (=%s) must be a commutative ring"%base_ring) # it is *very* important to include the level as part of the data @@ -299,7 +301,7 @@ def ModularForms(group=1, if base_ring is None: base_ring = group.minimize_base_ring().base_ring() if base_ring is None: - base_ring = rings.QQ + base_ring = QQ if isinstance(group, dirichlet.DirichletCharacter) \ or arithgroup.is_CongruenceSubgroup(group): @@ -324,17 +326,17 @@ def ModularForms(group=1, M = None if arithgroup.is_Gamma0(group): M = ModularFormsAmbient_g0_Q(group.level(), weight) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_Gamma1(group): M = ModularFormsAmbient_g1_Q(group.level(), weight, eis_only) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_GammaH(group): M = ModularFormsAmbient_gH_Q(group, weight, eis_only) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif isinstance(group, dirichlet.DirichletCharacter): @@ -466,7 +468,7 @@ def Newforms(group, weight=2, base_ring=None, names=None): return CuspForms(group, weight, base_ring).newforms(names) -def Newform(identifier, group=None, weight=2, base_ring=rings.QQ, names=None): +def Newform(identifier, group=None, weight=2, base_ring=QQ, names=None): """ INPUT: @@ -497,7 +499,7 @@ def Newform(identifier, group=None, weight=2, base_ring=rings.QQ, names=None): group, identifier = parse_label(identifier) if weight != 2: raise ValueError("Canonical label not implemented for higher weight forms.") - elif base_ring != rings.QQ: + elif base_ring != QQ: raise ValueError("Canonical label not implemented except for over Q.") elif group is None: raise ValueError("Must specify a group or a label.") diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index fe9d35d55dd..19a0b5661c0 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -41,12 +41,14 @@ from sage.matrix.constructor import Matrix from sage.matrix.special import identity_matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.rings.integer import Integer from sage.rings.rational_field import QQ +lazy_import('sage.modular.modform.vm_basis', 'victor_miller_basis') + from .submodule import ModularFormsSubmodule -from . import vm_basis from . import weight1 class CuspidalSubmodule(ModularFormsSubmodule): @@ -316,8 +318,7 @@ def _compute_q_expansion_basis(self, prec=None): prec = self.prec() else: prec = Integer(prec) - return vm_basis.victor_miller_basis(self.weight(), prec, - cusp_only=True, var='q') + return victor_miller_basis(self.weight(), prec, cusp_only=True, var='q') def _pari_init_(self): """ diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index fbdee194cfa..be0f2557c73 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -14,16 +14,17 @@ from sage.arith.functions import lcm from sage.arith.misc import bernoulli, divisors, is_squarefree +from sage.misc.lazy_import import lazy_import from sage.misc.timing import cputime from sage.modular.arithgroup.congroup_gammaH import GammaH_class from sage.modular.dirichlet import DirichletGroup from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ -from .eis_series_cython import eisenstein_series_poly, Ek_ZZ +lazy_import('sage.modular.modform.eis_series_cython', ['eisenstein_series_poly', 'Ek_ZZ']) +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index aced6a69aca..fd1731574fa 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -8,10 +8,12 @@ from sage.categories.objects import Objects from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer -from sage.rings.number_field.number_field import CyclotomicField from sage.structure.sequence import Sequence +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') + from . import eis_series from . import element from . import submodule @@ -29,7 +31,8 @@ def __init__(self, ambient_space): sage: E = ModularForms(23,4).eisenstein_subspace() # indirect doctest sage: E - Eisenstein subspace of dimension 2 of Modular Forms space of dimension 7 for Congruence Subgroup Gamma0(23) of weight 4 over Rational Field + Eisenstein subspace of dimension 2 of Modular Forms space of dimension 7 + for Congruence Subgroup Gamma0(23) of weight 4 over Rational Field sage: E == loads(dumps(E)) True """ @@ -101,10 +104,13 @@ def modular_symbols(self, sign=0): sage: eps = DirichletGroup(13).0 sage: E = EisensteinForms(eps^2, 2) sage: E.modular_symbols() - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2 + Modular Symbols subspace of dimension 2 of Modular Symbols space of + dimension 4 and level 13, weight 2, character [zeta6], sign 0, + over Cyclotomic Field of order 6 and degree 2 sage: E = EisensteinForms(eps, 1); E - Eisenstein subspace of dimension 1 of Modular Forms space of character [zeta12] and weight 1 over Cyclotomic Field of order 12 and degree 4 + Eisenstein subspace of dimension 1 of Modular Forms space of character + [zeta12] and weight 1 over Cyclotomic Field of order 12 and degree 4 sage: E.modular_symbols() Traceback (most recent call last): ... @@ -127,11 +133,13 @@ def parameters(self): EXAMPLES:: sage: ModularForms(24,2).eisenstein_submodule().parameters() - [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 2), - ... - Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 24)] + [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 2), + ... + Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 24)] sage: EisensteinForms(12,6).parameters()[-1] - (Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, 12) + (Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, + Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, 12) sage: pars = ModularForms(DirichletGroup(24).0,3).eisenstein_submodule().parameters() sage: [(x[0].values_on_gens(),x[1].values_on_gens(),x[2]) for x in pars] @@ -144,7 +152,14 @@ def parameters(self): ((-1, 1, 1), (1, 1, 1), 3), ((-1, 1, 1), (1, 1, 1), 6)] sage: EisensteinForms(DirichletGroup(24).0,1).parameters() - [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 1), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 2), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 3), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 6)] + [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 1), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 2), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 3), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 6)] """ char = self._parameters_character() if char is None: @@ -159,7 +174,8 @@ def new_submodule(self, p=None): EXAMPLES:: sage: e = EisensteinForms(Gamma0(225), 2).new_submodule(); e - Modular Forms subspace of dimension 3 of Modular Forms space of dimension 42 for Congruence Subgroup Gamma0(225) of weight 2 over Rational Field + Modular Forms subspace of dimension 3 of Modular Forms space of dimension 42 + for Congruence Subgroup Gamma0(225) of weight 2 over Rational Field sage: e.basis() [ q + O(q^6), @@ -190,7 +206,8 @@ def change_ring(self, base_ring): EXAMPLES:: sage: E = EisensteinForms(12,2) ; E - Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Rational Field + Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 + for Congruence Subgroup Gamma0(12) of weight 2 over Rational Field sage: E.basis() [ 1 + O(q^6), @@ -200,7 +217,8 @@ def change_ring(self, base_ring): q^4 + O(q^6) ] sage: E.change_ring(GF(5)) - Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Finite Field of size 5 + Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 + for Congruence Subgroup Gamma0(12) of weight 2 over Finite Field of size 5 sage: E.change_ring(GF(5)).basis() [ 1 + O(q^6), @@ -233,7 +251,8 @@ def eisenstein_series(self): ] sage: EisensteinForms(1,24).eisenstein_series() [ - 236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6) + 236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 + + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6) ] sage: EisensteinForms(5,4).eisenstein_series() [ @@ -259,7 +278,8 @@ def eisenstein_series(self): sage: eps = DirichletGroup(13).0^2 sage: ModularForms(eps,2).eisenstein_series() [ - -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), + -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6) ] @@ -271,7 +291,8 @@ def eisenstein_series(self): sage: M = ModularForms(DirichletGroup(13).0, 1) sage: M.eisenstein_series() [ - -1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6) + -1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 + + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6) ] sage: M = ModularForms(GammaH(15, [4]), 4) @@ -322,9 +343,9 @@ def _compute_q_expansion_basis(self, prec=None, new=False): O(q^6)] sage: EisensteinForms(22,4)._compute_q_expansion_basis(15) [1 + O(q^15), - q + 28*q^3 - 8*q^4 + 126*q^5 + 344*q^7 - 72*q^8 + 757*q^9 - 224*q^12 + 2198*q^13 + O(q^15), - q^2 + 9*q^4 + 28*q^6 + 73*q^8 + 126*q^10 + 252*q^12 + 344*q^14 + O(q^15), - q^11 + O(q^15)] + q + 28*q^3 - 8*q^4 + 126*q^5 + 344*q^7 - 72*q^8 + 757*q^9 - 224*q^12 + 2198*q^13 + O(q^15), + q^2 + 9*q^4 + 28*q^6 + 73*q^8 + 126*q^10 + 252*q^12 + 344*q^14 + O(q^15), + q^11 + O(q^15)] """ if prec is None: prec = self.prec() @@ -543,7 +564,8 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): sage: M.eisenstein_series() [ - -1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), + -1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 + + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), -1/3*zeta6 - 1/3 + q^3 + O(q^6), q + (-2*zeta6 + 1)*q^2 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 1)*q^5 + O(q^6), q + (zeta6 + 1)*q^2 + 3*q^3 + (zeta6 + 2)*q^4 + (-zeta6 + 5)*q^5 + O(q^6), @@ -590,8 +612,8 @@ def cyclotomic_restriction(L,K): EXAMPLES:: - sage: L = CyclotomicField(12) ; N = CyclotomicField(33) ; M = CyclotomicField(132) - sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N) + sage: L = CyclotomicField(12); N = CyclotomicField(33); M = CyclotomicField(132) + sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L, N) sage: n 2 @@ -600,11 +622,11 @@ def cyclotomic_restriction(L,K): sage: z(L.0)(M.0) zeta132^11 - sage: z(L.0^3-L.0+1) + sage: z(L.0^3 - L.0 + 1) (zeta33^19 + zeta33^8)*x + 1 - sage: z(L.0^3-L.0+1)(M.0) + sage: z(L.0^3 - L.0 + 1)(M.0) zeta132^33 - zeta132^11 + 1 - sage: z(L.0^3-L.0+1)(M.0) - M(L.0^3-L.0+1) + sage: z(L.0^3 - L.0 + 1)(M.0) - M(L.0^3 - L.0 + 1) 0 """ if not L.has_coerce_map_from(K): @@ -687,7 +709,7 @@ def z(a): EXAMPLES:: - sage: L = CyclotomicField(121) ; K = CyclotomicField(11) + sage: L = CyclotomicField(121); K = CyclotomicField(11) sage: z = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction_tower(L,K) sage: z(L.0) x diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 4d2123abab1..fba61a0fdd8 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -35,10 +35,10 @@ from sage.arith.functions import lcm from sage.arith.misc import divisors, moebius, sigma, factor, crt from sage.arith.srange import xsrange -from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.matrix.constructor import Matrix from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup @@ -51,13 +51,15 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.morphism import RingHomomorphism -from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField from sage.structure.element import coercion_model, ModuleElement, Element from sage.structure.richcmp import richcmp, op_NE, op_EQ +lazy_import('sage.combinat.integer_vector_weighted', 'WeightedIntegerVectors') +lazy_import('sage.rings.number_field.number_field_morphisms', 'NumberFieldEmbedding') + import sage.modular.hecke.element as element from . import defaults diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 8601c9fd51e..36e092d8200 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -14,12 +14,14 @@ from sage.arith.misc import divisors, gcd from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring_element import is_PowerSeries +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') + from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter from .element import is_ModularFormElement diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index fcff2fdedae..110b0fe3be7 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -16,21 +16,23 @@ # **************************************************************************** from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.free_module_element import vector -from sage.rings.imaginary_unit import I from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import is_LaurentSeriesRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing -from sage.rings.qqbar import AlgebraicField from sage.rings.rational_field import QQ from sage.structure.element import parent from .abstract_ring import FormsRing_abstract +lazy_import('sage.rings.imaginary_unit', 'I') +lazy_import('sage.rings.qqbar', 'QQbar') + class FormsSpace_abstract(FormsRing_abstract): r""" @@ -756,7 +758,7 @@ def aut_factor(self, gamma, t): if (gamma.is_translation()): return ZZ(1) elif (gamma.is_reflection()): - return self._ep * (t/AlgebraicField()(I))**self._weight + return self._ep * (t/QQbar(I))**self._weight else: L = [v for v in gamma.word_S_T()[0]] aut_f = ZZ(1) diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index 92981f2f52e..a2ef2a03b04 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -19,17 +19,20 @@ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.misc.cachefunc import cached_method from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector from sage.rings.big_oh import O from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring_element import LaurentSeries -from sage.rings.number_field.number_field import QuadraticField from sage.structure.element import CommutativeAlgebraElement from sage.structure.parent_gens import localvars from sage.structure.richcmp import op_NE, op_EQ from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.constants import pi + +lazy_import("sage.functions.log", "exp") +lazy_import("sage.rings.number_field.number_field", "QuadraticField") +lazy_import("sage.symbolic.constants", "pi") from .constructor import rational_type, FormsSpace, FormsRing from .series_constructor import MFSeriesConstructor diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index af1c6c89a3a..7c3867923c9 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -17,13 +17,15 @@ # **************************************************************************** from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.cc import CC -from sage.rings.qqbar import AA, QQbar + +lazy_import('sage.rings.qqbar', 'AA') from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane @@ -772,6 +774,8 @@ def _primitive_block_decomposition_data(self): if self.parent().n() == infinity: raise NotImplementedError + from sage.rings.qqbar import QQbar + emb = self.root_extension_embedding(QQbar) p = self.fixed_points()[0] embp = emb(p) @@ -3223,26 +3227,26 @@ def slash(self, f, tau=None, k=None): INPUT: - ``f`` -- A function in ``tau`` (or an object for which - evaluation at ``self.acton(tau)`` makes sense. + evaluation at ``self.acton(tau)`` makes sense. - ``tau`` -- Where to evaluate the result. - This should be a valid argument for :meth:`acton`. + This should be a valid argument for :meth:`acton`. - If ``tau`` is a point of ``HyperbolicPlane()`` then - its coordinates in the upper half plane model are used. + If ``tau`` is a point of ``HyperbolicPlane()`` then + its coordinates in the upper half plane model are used. - Default: ``None`` in which case ``f`` has to be - a rational function / polynomial in one variable and - the generator of the polynomial ring is used for ``tau``. - That way ``slash`` acts on rational functions / polynomials. + Default: ``None`` in which case ``f`` has to be + a rational function / polynomial in one variable and + the generator of the polynomial ring is used for ``tau``. + That way ``slash`` acts on rational functions / polynomials. - ``k`` -- An even integer. - Default: ``None`` in which case ``f`` either - has to be a rational function / polynomial in one - variable (then -degree is used). - Or ``f`` needs to have a ``weight`` attribute which - is then used. + Default: ``None`` in which case ``f`` either + has to be a rational function / polynomial in one + variable (then -degree is used). + Or ``f`` needs to have a ``weight`` attribute which + is then used. EXAMPLES:: @@ -3321,4 +3325,5 @@ def as_hyperbolic_plane_isometry(self, model="UHP"): sage: el.as_hyperbolic_plane_isometry("KM").parent() Set of Morphisms from Hyperbolic plane in the Klein Disk Model to Hyperbolic plane in the Klein Disk Model in Category of hyperbolic models of Hyperbolic plane """ + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane return HyperbolicPlane().UHP().get_isometry(self._matrix).to_model(model) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index cd51bda2b9d..a5e72e0eaa0 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -17,23 +17,25 @@ # **************************************************************************** from sage.arith.misc import divisors -from sage.functions.gamma import psi1 -from sage.functions.log import exp -from sage.functions.trig import sec from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import AA, AlgebraicField -from sage.rings.universal_cyclotomic_field import E from sage.rings.rational_field import QQ from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.constants import pi + +lazy_import("sage.functions.log", "exp") +lazy_import("sage.functions.gamma", "psi1") +lazy_import("sage.functions.trig", "sec") +lazy_import("sage.rings.number_field.number_field", "NumberField") +lazy_import("sage.rings.qqbar", ["AA", "AlgebraicField"]) +lazy_import("sage.rings.universal_cyclotomic_field", "E") +lazy_import("sage.symbolic.constants", "pi") from .hecke_triangle_group_element import HeckeTriangleGroupElement, cyclic_representative, coerce_AA diff --git a/src/sage/modular/modsym/all.py b/src/sage/modular/modsym/all.py index e3bfa152ca7..798a4a7d55f 100644 --- a/src/sage/modular/modsym/all.py +++ b/src/sage/modular/modsym/all.py @@ -1,9 +1,10 @@ +from sage.misc.lazy_import import lazy_import from .element import set_modsym_print_mode from .modsym import ModularSymbols, ModularSymbols_clear_cache -from .heilbronn import HeilbronnCremona, HeilbronnMerel +lazy_import('sage.modular.modsym.heilbronn', ['HeilbronnCremona', 'HeilbronnMerel']) from .p1list import P1List, lift_to_sl2z diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 81f2dcedb3e..208371b9deb 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -101,7 +101,8 @@ import sage.modular.hecke.all as hecke from sage.modular.modsym.manin_symbol import ManinSymbol -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ +from sage.rings.ring import Ring from . import element @@ -283,7 +284,7 @@ def __init__(self, group=arithgroup.Gamma0(1), weight=2, sign=0, - base_ring=rings.QQ, + base_ring=QQ, character=None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). @@ -319,7 +320,7 @@ def __init__(self, if not arithgroup.is_CongruenceSubgroup(group): raise TypeError("group must be a congruence subgroup") sign = int(sign) - if not isinstance(base_ring, rings.Ring) and rings.is_CommutativeRing(base_ring): + if not isinstance(base_ring, Ring): raise TypeError("base_ring must be a commutative ring") if character is None and arithgroup.is_Gamma0(group): character = dirichlet.TrivialCharacter(group.level(), base_ring) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index e6e63f1bbcb..45f0921034d 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -111,7 +111,8 @@ cdef class Heilbronn: EXAMPLES:: - sage: H = sage.modular.modsym.heilbronn.Heilbronn() + sage: from sage.modular.modsym.heilbronn import Heilbronn + sage: H = Heilbronn() sage: H._initialize_list() Traceback (most recent call last): ... @@ -343,6 +344,7 @@ cdef class HeilbronnCremona(Heilbronn): EXAMPLES:: + sage: from sage.modular.modsym.heilbronn import HeilbronnCremona sage: H = HeilbronnCremona.__new__(HeilbronnCremona) sage: H.p = 5 sage: H @@ -457,6 +459,7 @@ cdef class HeilbronnMerel(Heilbronn): EXAMPLES:: + sage: from sage.modular.modsym.heilbronn import HeilbronnMerel sage: H = HeilbronnMerel.__new__(HeilbronnMerel) sage: H.n = 5 sage: H diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index d6aea48b548..d33f61cd928 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -92,8 +92,9 @@ import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet -import sage.rings.rational_field as rational_field -import sage.rings.all as rings +from sage.rings.integer import Integer +from sage.rings.ring import CommutativeRing +from sage.rings.rational_field import RationalField def canonical_parameters(group, weight, sign, base_ring): @@ -114,15 +115,15 @@ def canonical_parameters(group, weight, sign, base_ring): sage: type(p1[1]) """ - sign = rings.Integer(sign) + sign = Integer(sign) if sign not in [-1, 0, 1]: raise ValueError("sign must be -1, 0, or 1") - weight = rings.Integer(weight) + weight = Integer(weight) if weight <= 1: raise ValueError("the weight must be at least 2") - if isinstance(group, (int, rings.Integer)): + if isinstance(group, (int, Integer)): group = arithgroup.Gamma0(group) elif isinstance(group, dirichlet.DirichletCharacter): if group.is_trivial(): @@ -134,9 +135,9 @@ def canonical_parameters(group, weight, sign, base_ring): base_ring = eps.base_ring() if base_ring is None: - base_ring = rational_field.RationalField() + base_ring = RationalField() - if not isinstance(base_ring, rings.CommutativeRing): + if not isinstance(base_ring, CommutativeRing): raise TypeError(f"base_ring (={base_ring}) must be a commutative ring") if not base_ring.is_field(): diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 9297b4d4313..9cf4bf0796f 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -27,6 +27,7 @@ from sage.categories.fields import Fields from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module import EchelonMatrixKey, FreeModule, VectorSpace from sage.modules.free_module_element import FreeModuleElement @@ -46,7 +47,7 @@ from sage.modular.hecke.module import HeckeModule_free_module from sage.modular.modsym.element import ModularSymbolsElement -from . import hecke_operator +lazy_import('sage.modular.modsym', 'hecke_operator') def is_ModularSymbolsSpace(x): diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 032a592ef36..471b39325c3 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -184,10 +184,10 @@ from sage.combinat.words.word import Word from sage.combinat.words.words import Words from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 as shuffle -from sage.libs.pari.all import pari from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modular.multiple_zeta_F_algebra import F_algebra from sage.modules.free_module import VectorSpace @@ -195,6 +195,9 @@ from sage.rings.rational_field import QQ from sage.sets.positive_integers import PositiveIntegers +lazy_import('sage.libs.pari.all', 'pari') + + # multiplicative generators for weight <= 17 # using the following convention # (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0] diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index dc74311e7f4..30e52f242e6 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -177,25 +177,27 @@ from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import diagonal_matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 from sage.modular.dirichlet import trivial_character from sage.modular.etaproducts import EtaProduct from sage.modular.modform.element import ModularFormElement from sage.modular.modform.hecke_operator_on_qexp import hecke_operator_on_qexp -from sage.modular.modform.j_invariant import j_invariant_qexp from sage.modules.free_module_element import vector from sage.modules.module import Module from sage.rings.big_oh import O from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp as pAdicField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.element import Vector, ModuleElement from sage.structure.richcmp import richcmp +lazy_import('sage.modular.modform.j_invariant', 'j_invariant_qexp') +lazy_import('sage.rings.padics.factory', 'Qp', as_='pAdicField') + from .weightspace import WeightSpace_constructor as WeightSpace, WeightCharacter diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index e7716b173a6..8f0ecc8b8c0 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -68,18 +68,20 @@ from sage.arith.misc import divisors from sage.categories.sets_cat import Sets from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.modular.dirichlet import DirichletGroup, trivial_character from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp -from sage.rings.padics.padic_generic_element import pAdicGenericElement from sage.rings.padics.precision_error import PrecisionError from sage.rings.rational_field import QQ from sage.structure.element import Element from sage.structure.parent import Parent from sage.structure.richcmp import richcmp +lazy_import('sage.rings.padics.factory', 'Qp') +lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement') + _wscache = {} def WeightSpace_constructor(p, base_ring=None): diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index 1bb73ceacc9..55a5ec72663 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -40,19 +40,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.misc.lazy_import import lazy_import from sage.modules.module import Module from sage.structure.parent import Parent -from sage.rings.padics.factory import ZpCA, QpCR -from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from sage.categories.modules import Modules -from sage.modular.pollack_stevens.dist import get_dist_classes # , Dist_long from sage.structure.factory import UniqueFactory import sage.rings.ring as ring +lazy_import('sage.modular.pollack_stevens.dist', 'get_dist_classes') +lazy_import('sage.rings.padics.factory', ['ZpCA', 'QpCR']) +lazy_import('sage.rings.padics.padic_generic', 'pAdicGeneric') + from .sigma0 import _default_adjuster diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index a9ff459a590..78e601189a8 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -42,16 +42,18 @@ from sage.arith.misc import next_prime, gcd, kronecker from sage.categories.action import Action from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp -from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.padics.precision_error import PrecisionError from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.structure.element import ModuleElement from sage.structure.richcmp import op_EQ, op_NE +lazy_import('sage.rings.padics.factory', 'Qp') +lazy_import('sage.rings.padics.padic_generic', 'pAdicGeneric') + from .manin_map import ManinMap from .sigma0 import Sigma0 from .fund_domain import M2Z diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 0692e81aef3..396a96af90e 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -21,13 +21,15 @@ # **************************************************************************** from sage.arith.misc import kronecker, binomial +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp as pAdicField from sage.rings.padics.precision_error import PrecisionError from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject +lazy_import('sage.rings.padics.factory', 'Qp', as_='pAdicField') + class pAdicLseries(SageObject): r""" diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 81381adef3d..1c74d953f6d 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -202,12 +202,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra, basis_for_quaternion_lattice -from sage.algebras.quatalg.quaternion_algebra_cython import rational_matrix_from_rational_quaternions from sage.arith.misc import gcd, factor, prime_divisors, kronecker, next_prime from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.modular.dirichlet import TrivialCharacter @@ -223,6 +222,9 @@ from sage.rings.ring import CommutativeRing from sage.structure.richcmp import richcmp, richcmp_method +lazy_import('sage.algebras.quatalg.quaternion_algebra', ['QuaternionAlgebra', 'basis_for_quaternion_lattice']) +lazy_import('sage.algebras.quatalg.quaternion_algebra_cython', 'rational_matrix_from_rational_quaternions') + cache = {} diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index 78fe82dc1f1..a23320cecb0 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -68,8 +68,8 @@ # **************************************************************************** from sage.arith.misc import kronecker, next_prime -from sage.libs.pari.all import pari from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.modular.arithgroup.all import Gamma0 from sage.modular.hecke.module import HeckeModule_free_module from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -78,6 +78,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.richcmp import richcmp_method, richcmp +lazy_import('sage.libs.pari.all', 'pari') + ZZy = PolynomialRing(ZZ, 'y') diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index a4a32815197..f30b3f058c6 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -929,7 +929,7 @@ def __eq__(self, other): sage: FilteredVectorSpace(2, base_ring=QQ) == FilteredVectorSpace(2, base_ring=GF(5)) False """ - if type(self) != type(other): + if type(self) is not type(other): return False if self.base_ring() != other.base_ring(): return False diff --git a/src/sage/modules/multi_filtered_vector_space.py b/src/sage/modules/multi_filtered_vector_space.py index e3f551b9e4b..beb46762361 100644 --- a/src/sage/modules/multi_filtered_vector_space.py +++ b/src/sage/modules/multi_filtered_vector_space.py @@ -490,7 +490,7 @@ def __eq__(self, other): sage: V == MultiFilteredVectorSpace({'a':F1, 'b':F2}) False """ - if type(self) != type(other): + if type(self) is not type(other): return False return self._filt == other._filt diff --git a/src/sage/modules/vector_space_homspace.py b/src/sage/modules/vector_space_homspace.py index 13004ea14ce..c15f0f59285 100644 --- a/src/sage/modules/vector_space_homspace.py +++ b/src/sage/modules/vector_space_homspace.py @@ -191,7 +191,7 @@ # http://www.gnu.org/licenses/ #################################################################################### -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix import sage.modules.free_module_homspace # This module initially overrides just the minimum functionality necessary @@ -384,7 +384,7 @@ def __call__(self, A, check=True, **kwds): msg = 'function cannot be applied properly to some basis element because\n' + e.args[0] raise ValueError(msg) try: - A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) + A = matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) except (ArithmeticError, TypeError) as e: msg = 'some image of the function is not in the codomain, because\n' + e.args[0] raise ArithmeticError(msg) @@ -396,7 +396,7 @@ def __call__(self, A, check=True, **kwds): raise ValueError(msg.format(len(D.basis()), len(A))) try: v = [C(a) for a in A] - A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(a) for a in v]) + A = matrix(D.dimension(), C.dimension(), [C.coordinates(a) for a in v]) except (ArithmeticError, TypeError) as e: msg = 'some proposed image is not in the codomain, because\n' + e.args[0] raise ArithmeticError(msg) diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index 20eb36cbd00..547dbea951a 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -423,7 +423,7 @@ cdef class GenericBackend: sage: p.add_linear_constraint([(0, 3), (1, 2)], None, 6) # optional - Nonexistent_LP_solver sage: p.remove_constraints([0, 1]) # optional - Nonexistent_LP_solver """ - if type(constraints) == int: self.remove_constraint(constraints) + if isinstance(constraints, int): self.remove_constraint(constraints) cdef int last = self.nrows() + 1 diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index ba0adb60481..ae9e43383e4 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -185,7 +185,7 @@ from sage.geometry.polyhedron.constructor import Polyhedron from sage.matrix.special import column_matrix from sage.matrix.special import identity_matrix -from sage.matrix.constructor import Matrix as matrix +from sage.matrix.constructor import matrix from sage.matrix.special import random_matrix from sage.misc.latex import LatexExpr, latex from sage.misc.cachefunc import cached_function, cached_method diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index 3d5f7565ebe..49f2ecd87d5 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Animated plots @@ -31,7 +31,8 @@ The sine function:: sage: x = SR.var("x") - sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1) for c in sxrange(0,1,.2)] + sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1) + ....: for c in sxrange(0,1,.2)] sage: a = animate(sines) sage: print(a) Animation with 5 frames @@ -48,15 +49,20 @@ An animated :class:`sage.plot.multigraphics.GraphicsArray` of rotating ellipses:: - sage: E = animate((graphics_array([[ellipse((0,0),a,b,angle=t,xmin=-3,xmax=3)+circle((0,0),3,color='blue') for a in range(1,3)] for b in range(2,4)]) for t in sxrange(0,pi/4,.15))) + sage: E = animate((graphics_array([[ellipse((0,0), a, b, angle=t, xmin=-3, xmax=3) + ....: + circle((0,0), 3, color='blue') + ....: for a in range(1,3)] + ....: for b in range(2,4)]) + ....: for t in sxrange(0, pi/4, .15))) sage: str(E) # animations produced from a generator do not have a known length 'Animation with unknown number of frames' sage: E.show() # long time # optional -- ImageMagick A simple animation of a circle shooting up to the right:: - sage: c = animate([circle((i,i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)], - ....: xmin=0,ymin=0,xmax=2,ymax=2,figsize=[2,2]) + sage: c = animate([circle((i,i), 1 - 1/(i+1), hue=i/10) + ....: for i in srange(0, 2, 0.2)], + ....: xmin=0, ymin=0, xmax=2, ymax=2, figsize=[2,2]) sage: c.show() # long time # optional -- ImageMagick @@ -64,8 +70,11 @@ sage: s,t = SR.var("s,t") sage: def sphere_and_plane(x): - ....: return sphere((0,0,0),1,color='red',opacity=.5)+parametric_plot3d([t,x,s],(s,-1,1),(t,-1,1),color='green',opacity=.7) - sage: sp = animate([sphere_and_plane(x) for x in sxrange(-1,1,.3)]) + ....: return (sphere((0,0,0), 1, color='red', opacity=.5) + ....: + parametric_plot3d([t,x,s], (s,-1,1), (t,-1,1), + ....: color='green', opacity=.7)) + sage: sp = animate([sphere_and_plane(x) + ....: for x in sxrange(-1, 1, .3)]) sage: sp[0] # first frame Graphics3d Object sage: sp[-1] # last frame @@ -74,9 +83,12 @@ sage: (x,y,z) = SR.var("x,y,z") sage: def frame(t): - ....: return implicit_plot3d((x^2 + y^2 + z^2), (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=60, contour=[1,3,5], region=lambda x,y,z: x<=t or y>=t or z<=t) - sage: a = animate([frame(t) for t in srange(.01,1.5,.2)]) - sage: a[0] # long time + ....: return implicit_plot3d((x^2 + y^2 + z^2), + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), + ....: plot_points=60, contour=[1,3,5], + ....: region=lambda x,y,z: x<=t or y>=t or z<=t) + sage: a = animate([frame(t) for t in srange(.01, 1.5, .2)]) + sage: a[0] # long time Graphics3d Object sage: a.show() # long time # optional -- ImageMagick @@ -86,7 +98,7 @@ illustrated by the following example:: sage: t = SR.var("t") - sage: a = animate((sin(c*pi*t) for c in sxrange(1,2,.2))) + sage: a = animate((sin(c*pi*t) for c in sxrange(1, 2, .2))) sage: a.show() # long time # optional -- ImageMagick @@ -135,7 +147,7 @@ def animate(frames, **kwds): EXAMPLES:: sage: t = SR.var("t") - sage: a = animate((cos(c*pi*t) for c in sxrange(1,2,.2))) + sage: a = animate((cos(c*pi*t) for c in sxrange(1, 2, .2))) sage: a.show() # long time # optional -- ImageMagick See also :mod:`sage.plot.animate` for more examples. @@ -148,23 +160,22 @@ class Animation(WithEqualityById, SageObject): INPUT: - - - ``v`` - iterable of Sage objects. These should preferably be - graphics objects, but if they aren't then :meth:`make_image` is + - ``v`` -- iterable of Sage objects. These should preferably be + graphics objects, but if they aren't, then :meth:`make_image` is called on them. - - ``xmin, xmax, ymin, ymax`` - the ranges of the x and y axes. + - ``xmin, xmax, ymin, ymax`` -- the ranges of the x and y axes. - - ``**kwds`` - all additional inputs are passed onto the rendering - command. E.g., use figsize to adjust the resolution and aspect + - ``**kwds`` -- all additional inputs are passed onto the rendering + command. E.g., use ``figsize`` to adjust the resolution and aspect ratio. EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.3)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: a = animate([sin(x + float(k)) for k in srange(0, 2*pi, 0.3)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) sage: print(a) Animation with 21 frames sage: print(a[:5]) @@ -185,9 +196,9 @@ class Animation(WithEqualityById, SageObject): sage: step = 0.1 sage: L = Graphics() sage: v = [] - sage: for i in srange(0,1,step): - ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2) - ....: v.append(L) + sage: for i in srange(0, 1, step): + ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2) + ....: v.append(L) sage: a = animate(v, xmin=0, ymin=0) sage: a.show() # long time # optional -- ImageMagick sage: show(L) @@ -427,7 +438,9 @@ def make_image(self, frame, filename, **kwds): sage: t = SR.var("t") sage: x = lambda t: cos(t) sage: y = lambda n,t: sin(t)/n - sage: B = MyAnimation([([x(t), y(i+1,t)],(t,0,1), {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1}) for i in range(4)]) + sage: B = MyAnimation([([x(t), y(i+1,t)], (t,0,1), + ....: {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1}) + ....: for i in range(4)]) sage: d = B.png(); v = os.listdir(d); v.sort(); v # long time ['00000000.png', '00000001.png', '00000002.png', '00000003.png'] @@ -436,7 +449,8 @@ def make_image(self, frame, filename, **kwds): sage: class MyAnimation(Animation): ....: def make_image(self, frame, filename, **kwds): ....: G = frame.plot() - ....: G.set_axes_range(floor(G.xmin()),ceil(G.xmax()),floor(G.ymin()),ceil(G.ymax())) + ....: G.set_axes_range(floor(G.xmin()), ceil(G.xmax()), + ....: floor(G.ymin()), ceil(G.ymax())) ....: G.save_image(filename, **kwds) sage: B = MyAnimation([graphs.CompleteGraph(n) for n in range(7,11)], figsize=5) @@ -506,26 +520,28 @@ def graphics_array(self, ncols=3): EXAMPLES:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') - sage: v = [E.change_ring(GF(p)).plot(pointsize=30) for p in [97, 101, 103]] + sage: v = [E.change_ring(GF(p)).plot(pointsize=30) + ....: for p in [97, 101, 103]] sage: a = animate(v, xmin=0, ymin=0, axes=False) sage: print(a) Animation with 3 frames - sage: a.show() # optional -- ImageMagick + sage: a.show() # optional -- ImageMagick Modify the default arrangement of array:: - sage: g = a.graphics_array(); print(g) + sage: g = a.graphics_array(); print(g) # needs sage.schemes Graphics Array of size 1 x 3 - sage: g.show(figsize=[6,3]) + sage: g.show(figsize=[6,3]) # needs sage.schemes Specify different arrangement of array and save it with a given file name:: - sage: g = a.graphics_array(ncols=2); print(g) + sage: g = a.graphics_array(ncols=2); print(g) # needs sage.schemes Graphics Array of size 2 x 2 - sage: f = tmp_filename(ext='.png'); print(f) + sage: f = tmp_filename(ext='.png'); print(f) # needs sage.schemes ...png - sage: g.save(f) + sage: g.save(f) # needs sage.schemes Frames can be specified as a generator too; it is internally converted to a list:: @@ -580,16 +596,21 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() sage: a.gif() # not tested - sage: a.gif(savefile=td + 'my_animation.gif', delay=35, iterations=3) # long time # optional -- ImageMagick - sage: with open(td + 'my_animation.gif', 'rb') as f: print(b'GIF8' in f.read()) # long time # optional -- ImageMagick + sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick + ....: delay=35, iterations=3) + sage: with open(td + 'my_animation.gif', 'rb') as f: # long time # optional -- ImageMagick + ....: print(b'GIF8' in f.read()) True - sage: a.gif(savefile=td + 'my_animation.gif', show_path=True) # long time # optional -- ImageMagick + sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick + ....: show_path=True) Animation saved to .../my_animation.gif. - sage: a.gif(savefile=td + 'my_animation_2.gif', show_path=True, use_ffmpeg=True) # long time # optional -- ffmpeg + sage: a.gif(savefile=td + 'my_animation_2.gif', # long time # optional -- FFmpeg + ....: show_path=True, use_ffmpeg=True) Animation saved to .../my_animation_2.gif. .. NOTE:: @@ -810,8 +831,9 @@ def show(self, delay=None, iterations=None, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) sage: a.show() # long time # optional -- ImageMagick The preceding will loop the animation forever. If you want to show @@ -825,18 +847,20 @@ def show(self, delay=None, iterations=None, **kwds): You can also make use of the HTML5 video element in the Sage Notebook:: - sage: a.show(format="ogg") # long time # optional -- ffmpeg - sage: a.show(format="webm") # long time # optional -- ffmpeg - sage: a.show(format="mp4") # long time # optional -- ffmpeg - sage: a.show(format="webm", iterations=1) # long time # optional -- ffmpeg + sage: # long time, optional -- FFmpeg + sage: a.show(format="ogg") + sage: a.show(format="webm") + sage: a.show(format="mp4") + sage: a.show(format="webm", iterations=1) Other backends may support other file formats as well:: - sage: a.show(format="flash") # long time # optional -- ffmpeg - sage: a.show(format="matroska") # long time # optional -- ffmpeg - sage: a.show(format="avi") # long time # optional -- ffmpeg - sage: a.show(format="wmv") # long time # optional -- ffmpeg - sage: a.show(format="quicktime") # long time # optional -- ffmpeg + sage: # long time, optional -- FFmpeg + sage: a.show(format="flash") + sage: a.show(format="matroska") + sage: a.show(format="avi") + sage: a.show(format="wmv") + sage: a.show(format="quicktime") TESTS: @@ -922,13 +946,14 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0, 2*pi, 0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() - sage: a.ffmpeg(savefile=td + 'new.mpg') # long time # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.avi') # long time # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.gif') # long time # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.mpg', show_path=True) # long time # optional -- ffmpeg + sage: a.ffmpeg(savefile=td + 'new.mpg') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.avi') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.gif') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.mpg', show_path=True) # long time # optional -- FFmpeg Animation saved to .../new.mpg. .. NOTE:: @@ -942,7 +967,7 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, TESTS:: - sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # long time # optional -- ffmpeg + sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # long time # optional -- FFmpeg """ from sage.features.ffmpeg import FFmpeg FFmpeg().require() @@ -1042,8 +1067,9 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) sage: dir = tmp_dir() sage: a.apng(show_path=True) # long time Animation saved to ....png. @@ -1053,7 +1079,8 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0): If the individual frames have different sizes, an error will be raised:: - sage: a = animate([plot(sin(x), (x, 0, k)) for k in range(1,4)], + sage: a = animate([plot(sin(x), (x, 0, k)) + ....: for k in range(1,4)], ....: ymin=-1, ymax=1, aspect_ratio=1, figsize=[2,1]) sage: a.apng() # long time Traceback (most recent call last): @@ -1111,14 +1138,15 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0, 2*pi, 0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() sage: a.save() # not tested sage: a.save(td + 'wave.gif') # long time # optional -- ImageMagick sage: a.save(td + 'wave.gif', show_path=True) # long time # optional -- ImageMagick Animation saved to file .../wave.gif. - sage: a.save(td + 'wave.avi', show_path=True) # long time # optional -- ffmpeg + sage: a.save(td + 'wave.avi', show_path=True) # long time # optional -- FFmpeg Animation saved to file .../wave.avi. sage: a.save(td + 'wave0.sobj') sage: a.save(td + 'wave1.sobj', show_path=True) @@ -1132,22 +1160,23 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds): Ensure that we can pass delay and iteration count to the saved GIF image (see :trac:`18176`):: - sage: a.save(td + 'wave.gif') # long time # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: # long time # optional -- ImageMagick + sage: # long time, optional -- ImageMagick + sage: a.save(td + 'wave.gif') + sage: with open(td + 'wave.gif', 'rb') as f: ....: print(b'GIF8' in f.read()) True - sage: with open(td + 'wave.gif', 'rb') as f: # long time # optional -- ImageMagick + sage: with open(td + 'wave.gif', 'rb') as f: ....: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) True - sage: a.save(td + 'wave.gif', delay=35) # long time # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: # long time # optional -- ImageMagick + sage: a.save(td + 'wave.gif', delay=35) + sage: with open(td + 'wave.gif', 'rb') as f: ....: print(b'GIF8' in f.read()) True - sage: a.save(td + 'wave.gif', iterations=3) # long time # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: # long time # optional -- ImageMagick + sage: a.save(td + 'wave.gif', iterations=3) + sage: with open(td + 'wave.gif', 'rb') as f: ....: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) False - sage: with open(td + 'wave.gif', 'rb') as f: # long time # optional -- ImageMagick + sage: with open(td + 'wave.gif', 'rb') as f: ....: check1 = b'!\xff\x0bNETSCAPE2.0\x03\x01\x02\x00\x00' ....: check2 = b'!\xff\x0bNETSCAPE2.0\x03\x01\x03\x00\x00' ....: data = f.read() @@ -1194,7 +1223,8 @@ def interactive(self, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: frames = [point3d((sin(x), cos(x), x)) for x in (0, pi/16, .., 2*pi)] + sage: frames = [point3d((sin(x), cos(x), x)) + ....: for x in (0, pi/16, .., 2*pi)] sage: animate(frames).interactive(online=True) Graphics3d Object @@ -1245,16 +1275,16 @@ class APngAssembler(): INPUT: - - ``out`` -- a file opened for binary writing to which the data - will be written + - ``out`` -- a file opened for binary writing to which the data + will be written - - ``num_frames`` -- the number of frames in the animation + - ``num_frames`` -- the number of frames in the animation - - ``num_plays`` -- how often to iterate, 0 means infinitely + - ``num_plays`` -- how often to iterate, 0 means infinitely - - ``delay`` -- numerator of the delay fraction in seconds + - ``delay`` -- numerator of the delay fraction in seconds - - ``delay_denominator`` -- denominator of the delay in seconds + - ``delay_denominator`` -- denominator of the delay in seconds EXAMPLES:: diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index f65973bcbd5..84a62554118 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -45,6 +45,7 @@ class Arc(GraphicPrimitive): Note that the construction should be done using ``arc``:: + sage: from math import pi sage: from sage.plot.arc import Arc sage: print(Arc(0,0,1,1,pi/4,pi/4,pi/2,{})) Arc with center (0.0,0.0) radii (1.0,1.0) angle 0.78539816339... inside the sector (0.78539816339...,1.5707963267...) @@ -115,6 +116,7 @@ def get_minmax_data(self): The same example with a rotation of angle `\pi/2`:: + sage: from math import pi sage: p = arc((-2, 3), 1, 2, pi/2) sage: d = p.get_minmax_data() sage: d['xmin'] @@ -293,6 +295,7 @@ def bezier_path(self): sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path() Graphics object consisting of 1 graphics primitive + sage: from math import pi sage: a = arc((0,0),2,1,0,(pi/5,pi/2+pi/12), linestyle="--", color="red") sage: b = a[0].bezier_path() sage: b[0] @@ -348,6 +351,7 @@ def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: A = arc((1,1),3,4,pi/4,(pi,4*pi/3)); A Graphics object consisting of 1 graphics primitive """ @@ -421,6 +425,7 @@ def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options): Plot an arc of circle centered at (0,0) with radius 1 in the sector `(\pi/4,3*\pi/4)`:: + sage: from math import pi sage: arc((0,0), 1, sector=(pi/4,3*pi/4)) Graphics object consisting of 1 graphics primitive diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index 0d09c2881d9..179e026d2e4 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -586,7 +586,8 @@ def arrow2d(tailpoint=None, headpoint=None, path=None, **options): A pretty circle of arrows:: - sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]]) + sage: sum(arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) # needs sage.symbolic + ....: for x in [0..2*pi, step=0.1]) Graphics object consisting of 63 graphics primitives .. PLOT:: diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 27c95f10c0c..a8bffed51ba 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -168,9 +168,9 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: sage: b = bezier_path([[(0,0),(0,1),(1,0)]]) - sage: A = b.plot3d() - sage: B = b.plot3d(z=2) - sage: A + B + sage: A = b.plot3d() # needs sage.symbolic + sage: B = b.plot3d(z=2) # needs sage.symbolic + sage: A + B # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -182,7 +182,7 @@ def plot3d(self, z=0, **kwds): :: - sage: bezier3d([[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]) + sage: bezier3d([[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]) # needs sage.symbolic Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/circle.py b/src/sage/plot/circle.py index 1dc58e02e39..512080a6ed8 100644 --- a/src/sage/plot/circle.py +++ b/src/sage/plot/circle.py @@ -25,18 +25,18 @@ class Circle(GraphicPrimitive): """ - Primitive class for the Circle graphics type. See circle? for information + Primitive class for the :class:`Circle` graphics type. See ``circle?`` for information about actually plotting circles. INPUT: - - x -- `x`-coordinate of center of Circle + - ``x`` -- `x`-coordinate of center of Circle - - y -- `y`-coordinate of center of Circle + - ``y`` -- `y`-coordinate of center of Circle - - r -- radius of Circle object + - ``r`` -- radius of Circle object - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: @@ -80,7 +80,7 @@ def __init__(self, x, y, r, options): def get_minmax_data(self): """ - Returns a dictionary with the bounding box data. + Return a dictionary with the bounding box data. EXAMPLES:: @@ -139,6 +139,7 @@ def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: C = circle((2,pi), 2, edgecolor='black', facecolor='green', fill=True) """ import matplotlib.patches as patches @@ -182,7 +183,8 @@ def plot3d(self, z=0, **kwds): This example uses this method implicitly, but does not pass the optional parameter z to this method:: - sage: sum([circle((random(),random()), random()).plot3d(z=random()) for _ in range(20)]) + sage: sum(circle((random(),random()), random()).plot3d(z=random()) + ....: for _ in range(20)) Graphics3d Object .. PLOT:: @@ -192,6 +194,7 @@ def plot3d(self, z=0, **kwds): These examples are explicit, and pass z to this method:: + sage: from math import pi sage: C = circle((2,pi), 2, hue=.8, alpha=.3, fill=True) sage: c = C[0] sage: d = c.plot3d(z=2) @@ -304,14 +307,16 @@ def circle(center, radius, **options): Here we make a more complicated plot, with many circles of different colors:: sage: g = Graphics() - sage: step=6; ocur=1/5; paths=16 + sage: step = 6; ocur = 1/5; paths = 16 sage: PI = math.pi # numerical for speed -- fine for graphics sage: for r in range(1,paths+1): - ....: for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: + ....: for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) + ....: for n in srange(0, 2*PI+PI/step, PI/step)]: ....: g += circle((x,y), ocur, rgbcolor=hue(r/paths)) ....: rnext = (r+1)^2 ....: ocur = (rnext-r)-ocur - sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) + sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, + ....: ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) .. PLOT:: @@ -358,7 +363,8 @@ def circle(center, radius, **options): And circles with legends:: - sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0) + sage: circle((4,5), 1, rgbcolor='yellow', fill=True, + ....: legend_label='the sun').show(xmin=0, ymin=0) .. PLOT:: @@ -368,7 +374,8 @@ def circle(center, radius, **options): :: - sage: circle((4,5), 1, legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) + sage: circle((4,5), 1, + ....: legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) .. PLOT:: @@ -378,12 +385,12 @@ def circle(center, radius, **options): Extra options will get passed on to show(), as long as they are valid:: - sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! + sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! Graphics object consisting of 1 graphics primitive :: - sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent + sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent TESTS: diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index bc89be406ea..8c0db2b3c34 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.plot r""" Colors diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index efb923a2df7..cb6a9cf8ca0 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -669,11 +669,14 @@ def add_lightness_smoothing_to_rgb(rgb, delta): We can call this on grids of values:: + sage: # needs numpy sage: import numpy as np sage: from sage.plot.complex_plot import add_lightness_smoothing_to_rgb - sage: add_lightness_smoothing_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_lightness_smoothing_to_rgb( # abs tol 1e-4 + ....: np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) array([[[0.75 , 0.8125, 0.875 ]]]) - sage: add_lightness_smoothing_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_lightness_smoothing_to_rgb( # abs tol 1e-4 + ....: np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) array([[[0.75 , 0.8125, 0.875 ]]]) """ import numpy as np @@ -731,21 +734,25 @@ def add_contours_to_rgb(rgb, delta, dark_rate=0.5): EXAMPLES:: + sage: # needs numpy sage: import numpy as np sage: from sage.plot.complex_plot import add_contours_to_rgb - sage: add_contours_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0, 0.25, 0.5]]]), # abs tol 1e-4 + ....: np.array([[0.75]])) array([[[0.25 , 0.625, 1. ]]]) - sage: add_contours_to_rgb(np.array([[[0, 0, 0]]]), np.array([[1]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0, 0, 0]]]), # abs tol 1e-4 + ....: np.array([[1]])) array([[[0.5, 0.5, 0.5]]]) - sage: add_contours_to_rgb(np.array([[[1, 1, 1]]]), np.array([[-0.5]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[1, 1, 1]]]), # abs tol 1e-4 + ....: np.array([[-0.5]])) array([[[0.75, 0.75, 0.75]]]) Raising ``dark_rate`` leads to bigger adjustments:: - sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 # needs numpy ....: np.array([[0.5]]), dark_rate=0.1) array([[[0.55, 0.55, 0.55]]]) - sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 # needs numpy ....: np.array([[0.5]]), dark_rate=0.5) array([[[0.75, 0.75, 0.75]]]) """ @@ -927,7 +934,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Here we plot a couple of simple functions:: - sage: complex_plot(sqrt(x), (-5, 5), (-5, 5)) + sage: complex_plot(sqrt(x), (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -936,7 +943,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(sin(x), (-5, 5), (-5, 5)) + sage: complex_plot(sin(x), (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -945,7 +952,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(log(x), (-10, 10), (-10, 10)) + sage: complex_plot(log(x), (-10, 10), (-10, 10)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -954,7 +961,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(exp(x), (-10, 10), (-10, 10)) + sage: complex_plot(exp(x), (-10, 10), (-10, 10)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -963,7 +970,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, A plot with a different choice of colormap:: - sage: complex_plot(exp(x), (-10, 10), (-10, 10), cmap='viridis') + sage: complex_plot(exp(x), (-10, 10), (-10, 10), cmap='viridis') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -972,8 +979,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, A function with some nice zeros and a pole:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3)) + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -984,8 +991,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The same function as above, but with contours. Contours render poorly with few plot points, so we use 300 here:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, contoured=True) + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, contoured=True) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -995,8 +1002,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The same function as above, but tiled and with the *plasma* colormap:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), # needs sage.symbolic ....: plot_points=300, tiled=True, cmap='plasma') Graphics object consisting of 1 graphics primitive @@ -1009,8 +1016,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, controlled by adjusting ``nphases``. We make the same plot with fewer tilings:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, # needs sage.symbolic ....: tiled=True, nphases=5, cmap='plasma') Graphics object consisting of 1 graphics primitive @@ -1022,8 +1029,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, It is also possible to use *linear* contours. We plot the same function above on an inset, setting contours to appear `1` apart:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (0, 1), (0, 1), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (0, 1), (0, 1), plot_points=300, # needs sage.symbolic ....: contoured=True, contour_type='linear', contour_base=1) Graphics object consisting of 1 graphics primitive @@ -1035,8 +1042,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Note that tightly spaced contours can lead to Moiré patterns and aliasing problems. For example:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, # needs sage.symbolic ....: contoured=True, contour_type='linear', contour_base=1) Graphics object consisting of 1 graphics primitive @@ -1049,8 +1056,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, be considered more appropriate for showing changes in phase without sharp color contrasts:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, cmap='twilight') + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, cmap='twilight') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1061,8 +1068,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Passing *matplotlib* as the colormap gives a special colormap that is similar to the default:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), # needs sage.symbolic ....: plot_points=300, contoured=True, cmap='matplotlib') Graphics object consisting of 1 graphics primitive @@ -1073,7 +1080,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Here is the identity, useful for seeing what values map to what colors:: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)) + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1082,7 +1089,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The Riemann Zeta function:: - sage: complex_plot(zeta, (-30,30), (-30,30)) + sage: complex_plot(zeta, (-30,30), (-30,30)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1093,7 +1100,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, ``dark_rate`` will make regions become darker/lighter faster when there are no contours:: - sage: complex_plot(zeta, (-30, 30), (-30, 30), dark_rate=1.0) + sage: complex_plot(zeta, (-30, 30), (-30, 30), dark_rate=1.0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1103,7 +1110,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Decreasing ``dark_rate`` has the opposite effect. When there are contours, adjust ``dark_rate`` affects how visible contours are. Compare:: - sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time + sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time, needs sage.symbolic ....: contoured=True, cmap='twilight', dark_rate=0.2) Graphics object consisting of 1 graphics primitive @@ -1113,7 +1120,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, and:: - sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time + sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time, needs sage.symbolic ....: contoured=True, cmap='twilight', dark_rate=0.75) Graphics object consisting of 1 graphics primitive @@ -1126,12 +1133,12 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Extra options will get passed on to show(), as long as they are valid:: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3), figsize=[1,1]) + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3), figsize=[1,1]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)).show(figsize=[1,1]) # These are equivalent + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)).show(figsize=[1,1]) # These are equivalent # needs sage.symbolic REFERENCES: @@ -1143,6 +1150,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Test to make sure that using fast_callable functions works:: + sage: # needs sage.symbolic sage: f(x) = x^2 sage: g = fast_callable(f, domain=CC, vars='x') sage: h = fast_callable(f, domain=CDF, vars='x') @@ -1162,7 +1170,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(sqrt, (-5, 5), (-5, 5)) + sage: complex_plot(sqrt, (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ import matplotlib as mpl diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 9a46eaefe76..7a8be38979b 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Contour plots """ diff --git a/src/sage/plot/density_plot.py b/src/sage/plot/density_plot.py index 155ac8d7a8e..b9f993239d0 100644 --- a/src/sage/plot/density_plot.py +++ b/src/sage/plot/density_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Density plots """ diff --git a/src/sage/plot/disk.py b/src/sage/plot/disk.py index d84b883d6e2..91891b84550 100644 --- a/src/sage/plot/disk.py +++ b/src/sage/plot/disk.py @@ -46,10 +46,12 @@ class Disk(GraphicPrimitive): Note this should normally be used indirectly via ``disk``:: + sage: from math import pi sage: from sage.plot.disk import Disk sage: D = Disk((1,2), 2, (pi/2,pi), {'zorder':3}) sage: D - Disk defined by (1.0,2.0) with r=2.0 spanning (1.5707963267..., 3.1415926535...) radians + Disk defined by (1.0,2.0) with r=2.0 + spanning (1.5707963267..., 3.1415926535...) radians sage: D.options()['zorder'] 3 sage: D.x @@ -68,6 +70,7 @@ def __init__(self, point, r, angle, options): EXAMPLES:: + sage: from math import pi sage: D = disk((2,3), 1, (pi/2, pi), fill=False, color='red', thickness=1, alpha=.5) sage: D[0].x 2.0 @@ -95,6 +98,7 @@ def get_minmax_data(self): EXAMPLES:: + sage: from math import pi sage: D = disk((5,4), 1, (pi/2, pi)) sage: d = D.get_minmax_data() sage: d['xmin'] @@ -118,6 +122,7 @@ def _allowed_options(self): EXAMPLES:: + sage: from math import pi sage: p = disk((3, 3), 1, (0, pi/2)) sage: p[0]._allowed_options()['alpha'] 'How transparent the figure is.' @@ -139,6 +144,7 @@ def _repr_(self): EXAMPLES:: + sage: from math import pi sage: P = disk((3, 3), 1, (0, pi/2)) sage: p = P[0]; p Disk defined by (3.0,3.0) with r=1.0 spanning (0.0, 1.5707963267...) radians @@ -149,6 +155,7 @@ def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: D = disk((2,-1), 2, (0, pi), color='black', thickness=3, fill=False); D Graphics object consisting of 1 graphics primitive @@ -192,6 +199,7 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: + sage: from math import pi sage: disk((0,0), 1, (0, pi/2)).plot3d() Graphics3d Object sage: disk((0,0), 1, (0, pi/2)).plot3d(z=2) @@ -253,12 +261,13 @@ def disk(point, radius, angle, **options): Make some dangerous disks:: + sage: from math import pi sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow') sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow') sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black') sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black') - sage: P = tl+tr+bl+br - sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2) + sage: P = tl + tr + bl + br + sage: P.show(xmin=-2, xmax=2, ymin=-2, ymax=2) .. PLOT:: @@ -318,9 +327,11 @@ def disk(point, radius, angle, **options): Extra options will get passed on to ``show()``, as long as they are valid:: - sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1)) + sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1), + ....: xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) Graphics object consisting of 1 graphics primitive - sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent + sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show( # These are equivalent + ....: xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) TESTS: diff --git a/src/sage/plot/ellipse.py b/src/sage/plot/ellipse.py index c35bed574ef..6d99cc90401 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -41,6 +41,7 @@ class Ellipse(GraphicPrimitive): Note that this construction should be done using ``ellipse``:: + sage: from math import pi sage: from sage.plot.ellipse import Ellipse sage: Ellipse(0, 0, 2, 1, pi/4, {}) Ellipse centered at (0.0, 0.0) with radii (2.0, 1.0) and angle 0.78539816339... @@ -94,6 +95,7 @@ def get_minmax_data(self): The same example with a rotation of angle `\pi/2`:: + sage: from math import pi sage: p = ellipse((-2, 3), 1, 2, pi/2) sage: d = p.get_minmax_data() sage: d['xmin'] @@ -178,6 +180,7 @@ def _render_on_subplot(self, subplot): TESTS:: + sage: from math import pi sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3) Graphics object consisting of 1 graphics primitive @@ -280,7 +283,8 @@ def ellipse(center, r1, r2, angle=0, **options): More complicated examples with tilted axes and drawing options:: - sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed") + sage: from math import pi + sage: ellipse((0,0), 3, 1, pi/6, fill=True, alpha=0.3, linestyle="dashed") Graphics object consisting of 1 graphics primitive .. PLOT:: diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index cdc99ced263..614505f89ac 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -130,23 +130,23 @@ class Graphics(WithEqualityById, SageObject): sage: G = Graphics(); print(G) Graphics object consisting of 0 graphics primitives sage: c = circle((1,1), 1) - sage: G+=c; print(G) + sage: G += c; print(G) Graphics object consisting of 1 graphics primitive Here we make a graphic of embedded isosceles triangles, coloring each one with a different color as we go:: - sage: h=10; c=0.4; p=0.5 + sage: h = 10; c = 0.4; p = 0.5 sage: G = Graphics() - sage: for x in srange(1,h+1): + sage: for x in srange(1, h+1): # needs sage.symbolic ....: l = [[0,x*sqrt(3)],[-x/2,-x*sqrt(3)/2],[x/2,-x*sqrt(3)/2],[0,x*sqrt(3)]] - ....: G+=line(l,color=hue(c + p*(x/h))) - sage: G.show(figsize=[5,5]) + ....: G += line(l, color=hue(c + p*(x/h))) + sage: G.show(figsize=[5,5]) # needs sage.symbolic We can change the scale of the axes in the graphics before displaying.:: - sage: G = plot(exp, 1, 10) # long time - sage: G.show(scale='semilogy') # long time + sage: G = plot(exp, 1, 10) # long time # needs sage.symbolic + sage: G.show(scale='semilogy') # long time # needs sage.symbolic TESTS: @@ -212,32 +212,32 @@ def set_aspect_ratio(self, ratio): EXAMPLES: We create a plot of the upper half of a circle, but it doesn't look round because the aspect ratio is off:: - sage: P = plot(sqrt(1-x^2),(x,-1,1)); P + sage: P = plot(sqrt(1-x^2),(x,-1,1)); P # needs sage.symbolic Graphics object consisting of 1 graphics primitive So we set the aspect ratio and now it is round:: - sage: P.set_aspect_ratio(1) - sage: P.aspect_ratio() + sage: P.set_aspect_ratio(1) # needs sage.symbolic + sage: P.aspect_ratio() # needs sage.symbolic 1.0 - sage: P + sage: P # needs sage.symbolic Graphics object consisting of 1 graphics primitive Note that the aspect ratio is inherited upon addition (which takes the max of aspect ratios of objects whose aspect ratio has been set):: - sage: P + plot(sqrt(4-x^2),(x,-2,2)) + sage: P + plot(sqrt(4-x^2),(x,-2,2)) # needs sage.symbolic Graphics object consisting of 2 graphics primitives In the following example, both plots produce a circle that looks twice as tall as wide:: sage: Q = circle((0,0), 0.5); Q.set_aspect_ratio(2) - sage: (P + Q).aspect_ratio(); P+Q + sage: (P + Q).aspect_ratio(); P + Q # needs sage.symbolic 2.0 Graphics object consisting of 2 graphics primitives - sage: (Q + P).aspect_ratio(); Q+P + sage: (Q + P).aspect_ratio(); Q + P # needs sage.symbolic 2.0 Graphics object consisting of 2 graphics primitives """ @@ -252,20 +252,20 @@ def set_aspect_ratio(self, ratio): def aspect_ratio(self): """ Get the current aspect ratio, which is the ratio of height to - width of a unit square, or 'automatic'. + width of a unit square, or ``'automatic'``. - OUTPUT: a positive float (height/width of a unit square), or 'automatic' + OUTPUT: a positive float (height/width of a unit square), or ``'automatic'`` (expand to fill the figure). EXAMPLES: - The default aspect ratio for a new blank Graphics object is 'automatic':: + The default aspect ratio for a new blank :class:`Graphics` object is ``'automatic'``:: sage: P = Graphics() sage: P.aspect_ratio() 'automatic' - The aspect ratio can be explicitly set different than the object's default:: + The aspect ratio can be explicitly set different from the object's default:: sage: P = circle((1,1), 1) sage: P.aspect_ratio() @@ -285,7 +285,7 @@ def legend(self, show=None): INPUT: - - ``show`` - (default: None) a boolean + - ``show`` -- (default: ``None``) a boolean If called with no input, return the current legend setting. @@ -293,23 +293,24 @@ def legend(self, show=None): By default no legend is displayed:: - sage: P = plot(sin) - sage: P.legend() + sage: P = plot(sin) # needs sage.symbolic + sage: P.legend() # needs sage.symbolic False But if we put a label then the legend is shown:: - sage: P = plot(sin, legend_label='sin') - sage: P.legend() + sage: P = plot(sin, legend_label='sin') # needs sage.symbolic + sage: P.legend() # needs sage.symbolic True We can turn it on or off:: + sage: # needs sage.symbolic sage: P.legend(False) sage: P.legend() False sage: P.legend(True) - sage: P # show with the legend + sage: P # show with the legend Graphics object consisting of 1 graphics primitive """ if show is None: @@ -405,30 +406,30 @@ def set_legend_options(self, **kwds): By default, no options are set:: - sage: p = plot(tan, legend_label='tan') - sage: p.set_legend_options() + sage: p = plot(tan, legend_label='tan') # needs sage.symbolic + sage: p.set_legend_options() # needs sage.symbolic {} We build a legend without a shadow:: - sage: p.set_legend_options(shadow=False) - sage: p.set_legend_options()['shadow'] + sage: p.set_legend_options(shadow=False) # needs sage.symbolic + sage: p.set_legend_options()['shadow'] # needs sage.symbolic False To set the legend position to the center of the plot, all these methods are roughly equivalent:: - sage: p.set_legend_options(loc='center'); p + sage: p.set_legend_options(loc='center'); p # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: p.set_legend_options(loc=10); p + sage: p.set_legend_options(loc=10); p # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: p.set_legend_options(loc=(0.5,0.5)); p # aligns the bottom of the box to the center + sage: p.set_legend_options(loc=(0.5,0.5)); p # aligns the bottom of the box to the center # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if len(kwds) == 0: @@ -623,8 +624,9 @@ def axes_labels_size(self, s=None): EXAMPLES:: + sage: # needs sage.symbolic sage: p = plot(sin(x^2), (x, -3, 3), axes_labels=['$x$','$y$']) - sage: p.axes_labels_size() # default value + sage: p.axes_labels_size() # default value 1.6 sage: p.axes_labels_size(2.5) sage: p.axes_labels_size() @@ -632,7 +634,7 @@ def axes_labels_size(self, s=None): Now the axes labels are large w.r.t. the tick marks:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ @@ -759,20 +761,20 @@ def axes_labels(self, l=None): :: - sage: p = plot(sin(x), (x, 0, 10)) - sage: p.axes_labels(['$x$','$y$']) - sage: p.axes_labels() + sage: p = plot(sin(x), (x, 0, 10)) # needs sage.symbolic + sage: p.axes_labels(['$x$','$y$']) # needs sage.symbolic + sage: p.axes_labels() # needs sage.symbolic ('$x$', '$y$') Now when you plot p, you see x and y axes labels:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive Notice that some may prefer axes labels which are not typeset:: - sage: plot(sin(x), (x, 0, 10), axes_labels=['x','y']) + sage: plot(sin(x), (x, 0, 10), axes_labels=['x','y']) # needs sage.symbolic Graphics object consisting of 1 graphics primitive TESTS: @@ -805,7 +807,7 @@ def axes_label_color(self, c=None): Set the color of the axes labels. The axes labels are placed at the edge of the x and y axes, and are - not on by default (use the ``axes_labels`` command to + not on by default (use the :meth:`axes_labels` command to set them; see the example below). This function just changes their color. @@ -823,25 +825,25 @@ def axes_label_color(self, c=None): :: - sage: p = plot(sin, (-1,1)) - sage: p.axes_label_color() + sage: p = plot(sin, (-1,1)) # needs sage.symbolic + sage: p.axes_label_color() # needs sage.symbolic (0, 0, 0) We change the labels to be red, and confirm this:: - sage: p.axes_label_color((1,0,0)) - sage: p.axes_label_color() + sage: p.axes_label_color((1,0,0)) # needs sage.symbolic + sage: p.axes_label_color() # needs sage.symbolic (1.0, 0.0, 0.0) We set labels, since otherwise we won't see anything. :: - sage: p.axes_labels(['$x$ axis', '$y$ axis']) + sage: p.axes_labels(['$x$ axis', '$y$ axis']) # needs sage.symbolic In the plot below, notice that the labels are red:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if c is None: @@ -860,7 +862,7 @@ def axes_width(self, w=None): INPUT: - - ``w`` - a float + - ``w`` -- a float If called with no input, return the current @@ -871,6 +873,7 @@ def axes_width(self, w=None): :: + sage: # needs sage.symbolic sage: p = plot(cos, (-3,3)) sage: p.axes_width() 0.8 @@ -882,7 +885,7 @@ def axes_width(self, w=None): :: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if w is None: @@ -908,6 +911,7 @@ def tick_label_color(self, c=None): EXAMPLES:: + sage: # needs sage.symbolic sage: p = plot(cos, (-3,3)) sage: p.tick_label_color() (0, 0, 0) @@ -938,27 +942,27 @@ def _repr_(self): We create a plot and call :meth:`show` on it, which causes it to be displayed as a plot:: - sage: P = plot(cos, (-1,1)) - sage: P.show() + sage: P = plot(cos, (-1,1)) # needs sage.symbolic + sage: P.show() # needs sage.symbolic Just doing this also displays the plot:: - sage: P + sage: P # needs sage.symbolic Graphics object consisting of 1 graphics primitive Using the Python `repr` or `str` commands do not display the plot:: - sage: repr(P) + sage: repr(P) # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' - sage: str(P) + sage: str(P) # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' - sage: print(P) + sage: print(P) # needs sage.symbolic Graphics object consisting of 1 graphics primitive TESTS:: - sage: P._repr_() + sage: P._repr_() # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' """ return str(self) @@ -1071,8 +1075,8 @@ def __delitem__(self, i): def __setitem__(self, i, x): """ - You can replace a GraphicPrimitive (point, line, circle, etc...) in - a Graphics object G with any other GraphicPrimitive + You can replace a :class:`GraphicPrimitive` (point, line, circle, etc...) in + a :class:`Graphics` object G with any other :class:`GraphicPrimitive` EXAMPLES:: @@ -1125,7 +1129,7 @@ def __add__(self, other): """ If you have any Graphics object G1, you can always add any other amount of Graphics objects G2,G3,... to form a new Graphics object: - G4 = G1 + G2 + G3. + ``G4 = G1 + G2 + G3``. The xmin, xmax, ymin, and ymax properties of the graphics objects are expanded to include all objects in both scenes. If the aspect @@ -1140,15 +1144,16 @@ def __add__(self, other): EXAMPLES:: - sage: g1 = plot(abs(sqrt(x^3-1)), (x,1,5), frame=True) - sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red') - sage: g1 + g2 # displays the plot + sage: g1 = plot(abs(sqrt(x^3-1)), (x,1,5), frame=True) # needs sage.symbolic + sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red') # needs sage.symbolic + sage: g1 + g2 # displays the plot # needs sage.symbolic Graphics object consisting of 2 graphics primitives TESTS: Extra keywords to show are propagated:: + sage: # needs sage.symbolic sage: (g1 + g2)._extra_kwds=={'aspect_ratio': 'automatic', 'frame': True} True sage: g1.set_aspect_ratio(2) @@ -1160,10 +1165,11 @@ def __add__(self, other): As are legend options, :trac:`12936`:: + sage: # needs sage.symbolic sage: p1 = plot(x, x, 0, 1) sage: p2 = p1 - sage: p1.set_legend_options(back_color = 'black') - sage: p2.set_legend_options(shadow = False) + sage: p1.set_legend_options(back_color='black') + sage: p2.set_legend_options(shadow=False) sage: p3 = p1 + p2 sage: p3._legend_opts {'back_color': 'black', 'shadow': False} @@ -1171,19 +1177,21 @@ def __add__(self, other): If the same legend option is specified more than once, the latter takes precedence:: + sage: # needs sage.symbolic sage: p1 = plot(x, x, 0, 1) sage: p2 = p1 - sage: p1.set_legend_options(shadow = True) - sage: p2.set_legend_options(shadow = False) + sage: p1.set_legend_options(shadow=True) + sage: p2.set_legend_options(shadow=False) sage: p3 = p1 + p2 sage: p3._legend_opts {'shadow': False} Flipped axes take precedence over non-flipped axes:: - sage: p1 = plot(x, x, 0, 1, flip_x=True, flip_y=True) - sage: p2 = plot(x^2, x, 0, 1) - sage: [p._extra_kwds[k] for p in [p1 + p2, p2 + p1] for k in ['flip_x', 'flip_y']] + sage: p1 = plot(x, x, 0, 1, flip_x=True, flip_y=True) # needs sage.symbolic + sage: p2 = plot(x^2, x, 0, 1) # needs sage.symbolic + sage: [p._extra_kwds[k] for p in [p1 + p2, p2 + p1] # needs sage.symbolic + ....: for k in ['flip_x', 'flip_y']] [True, True, True, True] """ if isinstance(other, int) and other == 0: @@ -1224,10 +1232,15 @@ def add_primitive(self, primitive): We give a very explicit example:: sage: G = Graphics() + sage: from math import e sage: from sage.plot.line import Line sage: from sage.plot.arrow import Arrow - sage: L = Line([3,4,2,7,-2],[1,2,e,4,5.],{'alpha':1,'thickness':2,'rgbcolor':(0,1,1),'legend_label':''}) - sage: A = Arrow(2,-5,.1,.2,{'width':3,'head':0,'rgbcolor':(1,0,0),'linestyle':'dashed','zorder':8,'legend_label':''}) + sage: L = Line([3,4,2,7,-2], [1,2,e,4,5.], + ....: {'alpha': 1, 'thickness': 2, 'rgbcolor': (0,1,1), + ....: 'legend_label': ''}) + sage: A = Arrow(2, -5, .1, .2, + ....: {'width': 3, 'head': 0, 'rgbcolor': (1,0,0), + ....: 'linestyle': 'dashed', 'zorder': 8, 'legend_label': ''}) sage: G.add_primitive(L) sage: G.add_primitive(A) sage: G @@ -1262,13 +1275,14 @@ def plot(self): def plot3d(self, z=0, **kwds): """ - Returns an embedding of this 2D plot into the xy-plane of 3D space, - as a 3D plot object. An optional parameter z can be given to + Return an embedding of this 2D plot into the xy-plane of 3D space, + as a 3D plot object. An optional parameter ``z`` can be given to specify the z-coordinate. EXAMPLES:: - sage: sum([plot(z*sin(x), 0, 10).plot3d(z) for z in range(6)]) # long time + sage: sum(plot(z*sin(x), 0, 10).plot3d(z) # long time # needs sage.symbolic + ....: for z in range(6)) Graphics3d Object """ from sage.plot.plot3d.base import Graphics3dGroup @@ -1286,7 +1300,7 @@ def _extract_kwds_for_show(cls, kwds, ignore=[]): sage: kwds = {'f': lambda x: x, 'xmin': 0, 'figsize': [1,1], 'plot_points': (40, 40)} sage: G_kwds = Graphics._extract_kwds_for_show(kwds, ignore='xmin') - sage: kwds # Note how this action modifies the passed dictionary + sage: kwds # Note how this action modifies the passed dictionary {'f': at 0x...>, 'plot_points': (40, 40), 'xmin': 0} @@ -1296,7 +1310,7 @@ def _extract_kwds_for_show(cls, kwds, ignore=[]): This method is intended to be used with _set_extra_kwds(). Here is an idiom to ensure the correct keywords will get passed on to show():: - sage: options = {} # Usually this will come from an argument + sage: options = {} # Usually this will come from an argument sage: g = Graphics() sage: g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) """ @@ -1321,7 +1335,7 @@ def _set_extra_kwds(self, kwds): sage: g._set_extra_kwds({'figsize': [10,10]}) sage: g._extra_kwds {'figsize': [10, 10]} - sage: g.show() # Now the (blank) plot will be extra large + sage: g.show() # Now the (blank) plot will be extra large """ self._extra_kwds = kwds @@ -1714,117 +1728,117 @@ def show(self, **kwds): height each having a maximum value of 327 inches at default dpi:: sage: p = ellipse((0,0),4,1) - sage: p.show(figsize=[327,10],dpi=100) - sage: p.show(figsize=[328,10],dpi=80) + sage: p.show(figsize=[327,10], dpi=100) + sage: p.show(figsize=[328,10], dpi=80) You can turn off the drawing of the axes:: - sage: show(plot(sin,-4,4), axes=False) + sage: show(plot(sin,-4,4), axes=False) # needs sage.symbolic You can also label the axes. Putting something in dollar signs formats it as a mathematical expression:: - sage: show(plot(sin,-4,4), axes_labels=('$x$','$y$')) + sage: show(plot(sin,-4,4), axes_labels=('$x$','$y$')) # needs sage.symbolic You can add a title to a plot:: - sage: show(plot(sin,-4,4), title=r'A plot of $\sin(x)$') + sage: show(plot(sin,-4,4), title=r'A plot of $\sin(x)$') # needs sage.symbolic You can also provide the position for the title to the plot. In the plot below the title is placed on the bottom left of the figure.:: - sage: plot(sin, -4, 4, title='Plot sin(x)', title_pos=(0.05,-0.05)) + sage: plot(sin, -4, 4, title='Plot sin(x)', title_pos=(0.05,-0.05)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive If you want all the text to be rendered by using an external LaTeX installation then set the ``typeset`` to ``"latex"``. This requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='latex') # optional - latex + sage: plot(x, typeset='latex') # optional - latex, needs sage.symbolic Graphics object consisting of 1 graphics primitive If you want all the text in your plot to use Type 1 fonts, then set the ``typeset`` option to ``"type1"``. This requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='type1') # optional - latex + sage: plot(x, typeset='type1') # optional - latex, needs sage.symbolic Graphics object consisting of 1 graphics primitive You can turn on the drawing of a frame around the plots:: - sage: show(plot(sin,-4,4), frame=True) + sage: show(plot(sin,-4,4), frame=True) # needs sage.symbolic You can make the background transparent:: - sage: plot(sin(x), (x, -4, 4), transparent=True) + sage: plot(sin(x), (x, -4, 4), transparent=True) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Prior to :trac:`19485`, legends by default had a shadowless gray background. This behavior can be recovered by passing in certain ``legend_options``:: - sage: p = plot(sin(x), legend_label=r'$\sin(x)$') - sage: p.show(legend_options={'back_color': (0.9,0.9,0.9), + sage: p = plot(sin(x), legend_label=r'$\sin(x)$') # needs sage.symbolic + sage: p.show(legend_options={'back_color': (0.9,0.9,0.9), # needs sage.symbolic ....: 'shadow': False}) We can change the scale of the axes in the graphics before displaying:: - sage: G = plot(exp, 1, 10) - sage: G.show(scale='semilogy') + sage: G = plot(exp, 1, 10) # needs sage.symbolic + sage: G.show(scale='semilogy') # needs sage.symbolic We can change the base of the logarithm too. The following changes the vertical axis to be on log scale, and with base 2. Note that the ``base`` argument will ignore any changes to the axis which is in linear scale.:: - sage: G.show(scale='semilogy', base=2) # long time # y axis as powers of 2 + sage: G.show(scale='semilogy', base=2) # y axis as powers of 2 # long time, needs sage.symbolic :: - sage: G.show(scale='semilogy', base=(3,2)) # base ignored for x-axis + sage: G.show(scale='semilogy', base=(3,2)) # base ignored for x-axis # needs sage.symbolic The scale can be also given as a 2-tuple or a 3-tuple.:: - sage: G.show(scale=('loglog', 2.1)) # long time # both x and y axes in base 2.1 + sage: G.show(scale=('loglog', 2.1)) # both x and y axes in base 2.1 # long time, needs sage.symbolic :: - sage: G.show(scale=('loglog', 2, 3)) # long time # x in base 2, y in base 3 + sage: G.show(scale=('loglog', 2, 3)) # x in base 2, y in base 3 # long time, needs sage.symbolic The base need not be an integer, though it does have to be made a float.:: - sage: G.show(scale='semilogx', base=float(e)) # base is e + sage: G.show(scale='semilogx', base=float(e)) # base is e # needs sage.symbolic Logarithmic scale can be used for various kinds of plots. Here are some examples.:: - sage: G = list_plot([10**i for i in range(10)]) # long time - sage: G.show(scale='semilogy') # long time + sage: G = list_plot([10**i for i in range(10)]) # long time, needs sage.symbolic + sage: G.show(scale='semilogy') # long time :: - sage: G = parametric_plot((x, x**2), (x, 1, 10)) - sage: G.show(scale='loglog') + sage: G = parametric_plot((x, x**2), (x, 1, 10)) # needs sage.symbolic + sage: G.show(scale='loglog') # needs sage.symbolic :: - sage: disk((5,5), 4, (0, 3*pi/2)).show(scale='loglog',base=2) + sage: disk((5,5), 4, (0, 3*pi/2)).show(scale='loglog',base=2) # needs sage.symbolic :: - sage: x, y = var('x, y') - sage: G = plot_vector_field((2^x,y^2),(x,1,10),(y,1,100)) - sage: G.show(scale='semilogx',base=2) + sage: x, y = var('x, y') # needs sage.symbolic + sage: G = plot_vector_field((2^x,y^2), (x,1,10), (y,1,100)) # needs sage.symbolic + sage: G.show(scale='semilogx',base=2) # needs sage.symbolic Flip the horizontal or vertical axis. :: - sage: G = plot(x^3, -2, 3) - sage: G.show(flip_x=True) - sage: G.show(flip_y=True) + sage: G = plot(x^3, -2, 3) # needs sage.symbolic + sage: G.show(flip_x=True) # needs sage.symbolic + sage: G.show(flip_y=True) # needs sage.symbolic Add grid lines at the major ticks of the axes. @@ -1839,6 +1853,7 @@ def show(self, **kwds): :: + sage: # needs sage.symbolic sage: u,v = var('u v') sage: f = exp(-(u^2+v^2)) sage: p = plot_vector_field(f.gradient(), (u,-2,2), (v,-2,2)) @@ -1848,18 +1863,18 @@ def show(self, **kwds): :: - sage: p = plot(sin,-10,20) - sage: p.show(gridlines=[None, "automatic"]) - sage: p.show(gridlines=["minor", False]) + sage: p = plot(sin, -10, 20) # needs sage.symbolic + sage: p.show(gridlines=[None, "automatic"]) # needs sage.symbolic + sage: p.show(gridlines=["minor", False]) # needs sage.symbolic Add grid lines at specific positions (using lists/tuples). :: - sage: x, y = var('x, y') - sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3)-4*(x^2+y^2-2*x)^2, \ - ....: (x,-2,2), (y,-2,2), plot_points=1000) - sage: p.show(gridlines=[[1,0],[-1,0,1]]) + sage: x, y = var('x, y') # needs sage.symbolic + sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3) - 4*(x^2+y^2-2*x)^2, # needs sage.symbolic + ....: (x,-2,2), (y,-2,2), plot_points=1000) + sage: p.show(gridlines=[[1,0],[-1,0,1]]) # needs sage.symbolic Add grid lines at specific positions (using iterators). @@ -1867,16 +1882,18 @@ def show(self, **kwds): sage: def maple_leaf(t): ....: return (100/(100+(t-pi/2)^8))*(2-sin(7*t)-cos(30*t)/2) - sage: p = polar_plot(maple_leaf, -pi/4, 3*pi/2, color="red",plot_points=1000) # long time - sage: p.show(gridlines=([-3,-2.75,..,3], range(-1,5,2))) # long time + sage: p = polar_plot(maple_leaf, -pi/4, 3*pi/2, # long time, needs sage.symbolic + ....: color="red",plot_points=1000) + sage: p.show(gridlines=([-3,-2.75,..,3], range(-1,5,2))) # long time, needs sage.symbolic Add grid lines at specific positions (using functions). :: + sage: # needs sage.symbolic sage: y = x^5 + 4*x^4 - 10*x^3 - 40*x^2 + 9*x + 36 sage: p = plot(y, -4.1, 1.1) - sage: xlines = lambda a,b: [z for z,m in y.roots()] + sage: xlines = lambda a, b: [z for z, m in y.roots()] sage: p.show(gridlines=[xlines, [0]], frame=True, axes=False) Change the style of all the grid lines. @@ -1884,27 +1901,27 @@ def show(self, **kwds): :: sage: b = bar_chart([-3,5,-6,11], color='red') - sage: b.show(gridlines=([-1,-0.5,..,4],True), - ....: gridlinesstyle=dict(color="blue", linestyle=":")) + sage: b.show(gridlines=([-1,-0.5,..,4], True), + ....: gridlinesstyle=dict(color="blue", linestyle=":")) Change the style of the horizontal or vertical grid lines separately. :: - sage: p = polar_plot(2 + 2*cos(x), 0, 2*pi, color=hue(0.3)) - sage: p.show(gridlines=True, - ....: hgridlinesstyle=dict(color="orange", linewidth=1.0), - ....: vgridlinesstyle=dict(color="blue", linestyle=":")) + sage: p = polar_plot(2 + 2*cos(x), 0, 2*pi, color=hue(0.3)) # needs sage.symbolic + sage: p.show(gridlines=True, # needs sage.symbolic + ....: hgridlinesstyle=dict(color="orange", linewidth=1.0), + ....: vgridlinesstyle=dict(color="blue", linestyle=":")) Change the style of each grid line individually. :: - sage: x, y = var('x, y') - sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3)-4*(x^2+y^2-2*x)^2, - ....: (x,-2,2), (y,-2,2), plot_points=1000) - sage: p.show(gridlines=( + sage: x, y = var('x, y') # needs sage.symbolic + sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3) - 4*(x^2+y^2-2*x)^2, # needs sage.symbolic + ....: (x,-2,2), (y,-2,2), plot_points=1000) + sage: p.show(gridlines=( # needs sage.symbolic ....: [ ....: (1,{"color":"red","linestyle":":"}), ....: (0,{"color":"blue","linestyle":"--"}) @@ -1921,9 +1938,10 @@ def show(self, **kwds): :: - sage: f = sin(x^2 + y^2)*cos(x)*sin(y) - sage: c = contour_plot(f, (x, -4, 4), (y, -4, 4), plot_points=100) - sage: c.show(gridlines=True, gridlinesstyle={'linestyle':':','linewidth':1, 'color':'red'}) + sage: f = sin(x^2 + y^2)*cos(x)*sin(y) # needs sage.symbolic + sage: c = contour_plot(f, (x, -4, 4), (y, -4, 4), plot_points=100) # needs sage.symbolic + sage: c.show(gridlines=True, # needs sage.symbolic + ....: gridlinesstyle={'linestyle': ':', 'linewidth': 1, 'color': 'red'}) Grid lines can be added to matrix plots. @@ -1942,9 +1960,11 @@ def show(self, **kwds): :: - sage: plot(sin(x), (x, -pi, pi),thickness=2)+point((pi, -1), pointsize=15) + sage: (plot(sin(x), (x, -pi, pi), thickness=2) # needs sage.symbolic + ....: + point((pi, -1), pointsize=15)) Graphics object consisting of 2 graphics primitives - sage: plot(sin(x), (x, -pi, pi),thickness=2,axes_pad=0)+point((pi, -1), pointsize=15) + sage: (plot(sin(x), (x, -pi, pi), thickness=2, axes_pad=0) # needs sage.symbolic + ....: + point((pi, -1), pointsize=15)) Graphics object consisting of 2 graphics primitives The behavior of the ``axes_pad`` parameter is different if the axis @@ -1956,10 +1976,10 @@ def show(self, **kwds): :: - sage: plot_loglog(x, (1.1*10**-2, 9990)) + sage: plot_loglog(x, (1.1*10**-2, 9990)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: plot_loglog(x, (1.1*10**-2, 9990), axes_pad=0) + sage: plot_loglog(x, (1.1*10**-2, 9990), axes_pad=0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Via matplotlib, Sage allows setting of custom ticks. See above @@ -1967,38 +1987,39 @@ def show(self, **kwds): Here the labels are not so useful:: - sage: plot(sin(pi*x), (x, -8, 8)) + sage: plot(sin(pi*x), (x, -8, 8)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Now put ticks at multiples of 2:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=2) + sage: plot(sin(pi*x), (x, -8, 8), ticks=2) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Or just choose where you want the ticks:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7],[-1/2,0,1/2]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7], [-1/2,0,1/2]]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Or no ticks at all:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[],[]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[], []]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive This can be very helpful in showing certain features of plots. :: - sage: plot(1.5/(1+e^(-x)), (x, -10, 10)) # doesn't quite show value of inflection point + sage: plot(1.5/(1+e^(-x)), (x, -10, 10)) # doesn't quite show value of inflection point # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: plot(1.5/(1+e^(-x)), (x, -10, 10), ticks=[None, 1.5/4]) # It's right at f(x)=0.75! + sage: plot(1.5/(1+e^(-x)), (x, -10, 10), # It's right at f(x)=0.75! # needs sage.symbolic + ....: ticks=[None, 1.5/4]) Graphics object consisting of 1 graphics primitive But be careful to leave enough room for at least two major ticks, so that the user can tell what the scale is:: - sage: plot(x^2,(x,1,8),ticks=6).show() + sage: plot(x^2, (x,1,8), ticks=6).show() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Expand the range of the independent variable to @@ -2007,7 +2028,9 @@ def show(self, **kwds): We can also do custom formatting if you need it. See above for full details:: - sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") # not tested (broken with matplotlib 3.6) + sage: plot(2*x + 1, (x,0,5), # not tested (broken with matplotlib 3.6), needs sage.symbolic + ....: ticks=[[0,1,e,pi,sqrt(20)], 2], + ....: tick_formatter="latex") Graphics object consisting of 1 graphics primitive This is particularly useful when setting custom ticks in multiples @@ -2015,41 +2038,47 @@ def show(self, **kwds): :: - sage: plot(sin(x),(x,0,2*pi),ticks=pi/3,tick_formatter=pi) + sage: plot(sin(x), (x,0,2*pi), ticks=pi/3, tick_formatter=pi) # needs sage.symbolic Graphics object consisting of 1 graphics primitive But keep in mind that you will get exactly the formatting you asked for if you specify both formatters. The first syntax is recommended for best style in that case. :: - sage: plot(arcsin(x),(x,-1,1),ticks=[None,pi/6],tick_formatter=["latex",pi]) # Nice-looking! + sage: plot(arcsin(x), (x,-1,1), ticks=[None, pi/6], # Nice-looking! # needs sage.symbolic + ....: tick_formatter=["latex", pi]) Graphics object consisting of 1 graphics primitive :: - sage: plot(arcsin(x),(x,-1,1),ticks=[None,pi/6],tick_formatter=[None,pi]) # Not so nice-looking + sage: plot(arcsin(x), (x,-1,1), ticks=[None, pi/6], # Not so nice-looking # needs sage.symbolic + ....: tick_formatter=[None, pi]) Graphics object consisting of 1 graphics primitive Custom tick labels can be provided by providing the keyword ``tick_formatter`` with the list of labels, and simultaneously providing the keyword ``ticks`` with the positions of the labels. :: - sage: plot(x, (x,0,3), ticks=[[1,2.5],[0.5,1,2]], tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) + sage: plot(x, (x,0,3), ticks=[[1,2.5], [0.5,1,2]], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], ["$y_1$","$y_2$","$y_3$"]]) Graphics object consisting of 1 graphics primitive The following sets the custom tick labels only along the horizontal axis. :: - sage: plot(x**2, (x,0,2), ticks=[[1,2], None], tick_formatter=[["$x_1$","$x_2$"], None]) + sage: plot(x**2, (x,0,2), ticks=[[1,2], None], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], None]) Graphics object consisting of 1 graphics primitive If the number of tick labels do not match the number of positions of tick labels, then it results in an error.:: - sage: plot(x**2, (x,0,2), ticks=[[2], None], tick_formatter=[["$x_1$","$x_2$"], None]).show() + sage: plot(x**2, (x,0,2), ticks=[[2], None], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], None]).show() Traceback (most recent call last): ... - ValueError: If the first component of the list `tick_formatter` is a list then the first component of `ticks` must also be a list of equal length. + ValueError: If the first component of the list `tick_formatter` is a list + then the first component of `ticks` must also be a list of equal length. When using logarithmic scale along the axis, make sure to have enough room for two ticks so that the user can tell what the scale @@ -2083,8 +2112,9 @@ def show(self, **kwds): When using ``title_pos``, it must be ensured that a list or a tuple of length two is used. Otherwise, a warning is raised:: - sage: plot(x, -4, 4, title='Plot x', title_pos=0.05) - doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying object: 'title_pos' must be a list or tuple of two real numbers. + sage: plot(x, -4, 4, title='Plot x', title_pos=0.05) # needs sage.symbolic + doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying + object: 'title_pos' must be a list or tuple of two real numbers. Graphics object consisting of 1 graphics primitive TESTS: @@ -2111,6 +2141,7 @@ def show(self, **kwds): The following tests ensure we give a good error message for negative figsizes:: + sage: # needs sage.symbolic sage: P = plot(x^2,(x,0,1)) sage: P.show(figsize=[-1,1]) Traceback (most recent call last): @@ -2127,7 +2158,8 @@ def show(self, **kwds): sage: P.show(figsize=[2,3,4]) Traceback (most recent call last): ... - ValueError: figsize should be a positive number or a list of two positive numbers, not [2, 3, 4] + ValueError: figsize should be a positive number or + a list of two positive numbers, not [2, 3, 4] sage: P.show(figsize=[sqrt(2),sqrt(3)]) """ from sage.repl.rich_output import get_display_manager @@ -2240,7 +2272,8 @@ def get_minmax_data(self): 'ymin': -1.0} sage: l = line([(0,0), (1,1)], aspect_ratio=1e19) sage: l.get_minmax_data() - {'xmax': 5000.50000000000, 'xmin': -4999.50000000000, 'ymax': 1.0, 'ymin': 0.0} + {'xmax': 5000.50000000000, 'xmin': -4999.50000000000, + 'ymax': 1.0, 'ymin': 0.0} """ objects = self._objects if objects: @@ -2332,10 +2365,12 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), the ticks formatting. This function is only for internal use. INPUT: + - ``subplot`` -- the subplot instance. EXAMPLES:: + sage: # needs sage.symbolic sage: from matplotlib.figure import Figure sage: p = plot(x); d = p.get_minmax_data() sage: subplot = Figure().add_subplot(111) @@ -2649,14 +2684,15 @@ def matplotlib(self, filename=None, :: - sage: p = plot(sin(x), (x, -2*pi, 2*pi)) - sage: figure = p.matplotlib() - sage: axes = figure.axes[0] + sage: p = plot(sin(x), (x, -2*pi, 2*pi)) # needs sage.symbolic + sage: figure = p.matplotlib() # needs sage.symbolic + sage: axes = figure.axes[0] # needs sage.symbolic TESTS: We verify that :trac:`10291` is fixed:: + sage: # needs sage.symbolic sage: p = plot(sin(x), (x, -2*pi, 2*pi)) sage: figure = p.matplotlib() sage: axes_range = p.get_axes_range() @@ -2669,20 +2705,22 @@ def matplotlib(self, filename=None, First, we test with no options, and next with an incomplete set of options.:: + sage: # needs sage.symbolic sage: p = plot(x, legend_label='aha') sage: p.legend(True) sage: pm = p.matplotlib() - sage: pm = p.matplotlib(legend_options={'font_size':'small'}) + sage: pm = p.matplotlib(legend_options={'font_size': 'small'}) The title should not overlap with the axes labels nor the frame in the following plot (see :trac:`10512`):: - sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y'],frame=True) + sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', # needs sage.symbolic + ....: axes_labels=['x','y'], frame=True) Graphics object consisting of 1 graphics primitive ``typeset`` must not be set to an arbitrary string:: - sage: plot(x, typeset='garbage') + sage: plot(x, typeset='garbage') # needs sage.symbolic doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying object: typeset must be set to one of 'default', 'latex', or 'type1'; got 'garbage'. @@ -2692,12 +2730,14 @@ def matplotlib(self, filename=None, By default, Sage 5.10 changes float objects to the `RealLiteral` type. The patch changes them to float before creating `matplotlib` objects.:: - sage: f = lambda x, y : (abs(cos((x + I * y) ** 4)) - 1) # long time - sage: g = implicit_plot(f,(-4, 4),(-3, 3),linewidth=0.6) # long time - sage: gm = g.matplotlib() # long time # without the patch, this goes BOOM -- er, TypeError + sage: # long time, needs sage.symbolic + sage: f = lambda x, y: abs(cos((x + I * y) ** 4)) - 1 + sage: g = implicit_plot(f, (-4, 4), (-3, 3), linewidth=0.6) + sage: gm = g.matplotlib() If the axes are flipped, the limits of the axes get swapped:: + sage: # needs sage.symbolic sage: p = plot(2*x, 1, 2) sage: sub, = p.matplotlib(flip_y=True, flip_x=True).axes sage: xmin, xmax = sub.get_xlim() @@ -3251,16 +3291,16 @@ def save(self, filename, **kwds): ``fig_tight=False``:: sage: c.save(f.name, figsize=[8,4], fig_tight=False, - ....: xmin=-1, xmax=3, ymin=-1, ymax=3) + ....: xmin=-1, xmax=3, ymin=-1, ymax=3) You can also pass extra options to the plot command instead of this method, e.g. :: - sage: plot(x^2 - 5, (x, 0, 5), ymin=0).save(tmp_filename(ext='.png')) + sage: plot(x^2 - 5, (x, 0, 5), ymin=0).save(tmp_filename(ext='.png')) # needs sage.symbolic will save the same plot as the one shown by this command:: - sage: plot(x^2 - 5, (x, 0, 5), ymin=0) + sage: plot(x^2 - 5, (x, 0, 5), ymin=0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive (This test verifies that :trac:`8632` is fixed.) @@ -3269,6 +3309,7 @@ def save(self, filename, **kwds): Legend labels should save correctly:: + sage: # needs sage.symbolic sage: P = plot(x,(x,0,1),legend_label='$xyz$') sage: P.set_legend_options(back_color=(1,0,0)) sage: P.set_legend_options(loc=7) @@ -3279,16 +3320,16 @@ def save(self, filename, **kwds): This plot should save with the frame shown, showing :trac:`7524` is fixed (same issue as :trac:`7981` and :trac:`8632`):: - sage: var('x,y') + sage: var('x,y') # needs sage.symbolic (x, y) - sage: a = plot_vector_field((x,-y),(x,-1,1),(y,-1,1)) + sage: a = plot_vector_field((x,-y),(x,-1,1),(y,-1,1)) # needs sage.symbolic sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.symbolic ....: a.save(f.name) The following plot should show the axes; fixes :trac:`14782` :: - sage: plot(x^2, (x, 1, 2), ticks=[[], []]) + sage: plot(x^2, (x, 1, 2), ticks=[[], []]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ @@ -3403,7 +3444,7 @@ def description(self): EXAMPLES:: - sage: print(polytopes.hypercube(2).plot().description()) + sage: print(polytopes.hypercube(2).plot().description()) # needs sage.geometry.polyhedron Polygon defined by 4 points: [(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)] Line defined by 2 points: [(-1.0, 1.0), (-1.0, -1.0)] Line defined by 2 points: [(1.0, -1.0), (-1.0, -1.0)] @@ -3448,6 +3489,7 @@ def inset(self, graphics, pos=None, fontsize=None): EXAMPLES:: + sage: # needs sage.symbolic sage: f(x) = x^2*sin(1/x) sage: g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$']) sage: g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'], @@ -3465,7 +3507,7 @@ def inset(self, graphics, pos=None, fontsize=None): Using non-default values for the position/size and the font size:: - sage: g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8) + sage: g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8) # needs sage.symbolic Multigraphics with 2 elements .. PLOT:: @@ -3478,10 +3520,10 @@ def inset(self, graphics, pos=None, fontsize=None): We can add another inset by invoking ``inset`` on the last output:: - sage: g1g2 = _ - sage: g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'], + sage: g1g2 = _ # needs sage.symbolic + sage: g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'], # needs sage.symbolic ....: frame=True) - sage: g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25)) + sage: g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25)) # needs sage.symbolic Multigraphics with 3 elements .. PLOT:: @@ -3518,7 +3560,8 @@ def GraphicsArray(*args, **kwargs): sage: from sage.plot.graphics import GraphicsArray sage: c = circle((0,0), 1) sage: G = GraphicsArray([c, c]) - doctest:...: DeprecationWarning: GraphicsArray must be imported from sage.plot.multigraphics and no longer from sage.plot.graphics. + doctest:...: DeprecationWarning: GraphicsArray must be imported from + sage.plot.multigraphics and no longer from sage.plot.graphics. See https://github.com/sagemath/sage/issues/28675 for details. sage: G Graphics Array of size 1 x 2 diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 0ab3f2744c8..4e7fda8350d 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Arcs in hyperbolic geometry diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index 1726525ff43..efe39697829 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Polygons and triangles in hyperbolic geometry diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index 5874073b549..a20d7d5a002 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Regular polygons in the upper half model for hyperbolic plane diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index 691e3c31307..c945946484a 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -131,9 +131,9 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: - sage: E = EllipticCurve('37a').plot(thickness=5).plot3d() - sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) - sage: E + F # long time (5s on sage.math, 2012) + sage: E = EllipticCurve('37a').plot(thickness=5).plot3d() # needs sage.schemes + sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) # needs sage.schemes + sage: E + F # long time (5s on sage.math, 2012), needs sage.schemes Graphics3d Object .. PLOT:: @@ -389,16 +389,16 @@ def line2d(points, **options): A line with no points or one point:: - sage: line([]) #returns an empty plot + sage: line([]) # returns an empty plot Graphics object consisting of 0 graphics primitives - sage: import numpy; line(numpy.array([])) + sage: import numpy; line(numpy.array([])) # needs numpy Graphics object consisting of 0 graphics primitives sage: line([(1,1)]) Graphics object consisting of 1 graphics primitive A line with numpy arrays:: - sage: line(numpy.array([[1,2], [3,4]])) + sage: line(numpy.array([[1,2], [3,4]])) # needs numpy Graphics object consisting of 1 graphics primitive A line with a legend:: @@ -442,7 +442,9 @@ def line2d(points, **options): A blue conchoid of Nicomedes:: - sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] + sage: from math import pi + sage: L = [[1 + 5*cos(pi/2+pi*i/100), + ....: tan(pi/2+pi*i/100) * (1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1/8,3/4)) Graphics object consisting of 1 graphics primitive @@ -454,7 +456,7 @@ def line2d(points, **options): A line with 2 complex points:: sage: i = CC(0,1) - sage: line([1+i, 2+3*i]) + sage: line([1 + i, 2 + 3*i]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -466,7 +468,8 @@ def line2d(points, **options): A blue hypotrochoid (3 leaves):: sage: n = 4; h = 3; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: L = [[n*cos(pi*i/100) + h*cos((n/b)*pi*i/100), + ....: n*sin(pi*i/100) - h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive @@ -482,7 +485,8 @@ def line2d(points, **options): A blue hypotrochoid (4 leaves):: sage: n = 6; h = 5; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: L = [[n*cos(pi*i/100) + h*cos((n/b)*pi*i/100), + ....: n*sin(pi*i/100) - h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive @@ -493,7 +497,8 @@ def line2d(points, **options): A red limacon of Pascal:: - sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] + sage: L = [[sin(pi*i/100) + sin(pi*i/50), + ....: -(1 + cos(pi*i/100) + cos(pi*i/50))] for i in range(-100,101)] sage: line(L, rgbcolor=(1,1/4,1/2)) Graphics object consisting of 1 graphics primitive @@ -504,7 +509,8 @@ def line2d(points, **options): A light green trisectrix of Maclaurin:: - sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] + sage: L = [[2 * (1-4*cos(-pi/2+pi*i/100)^2), + ....: 10 * tan(-pi/2+pi*i/100) * (1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1,1/8)) Graphics object consisting of 1 graphics primitive @@ -530,8 +536,8 @@ def line2d(points, **options): A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`:: - sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in - ....: range(-300, 300, 30)] + sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) + ....: for i in range(-300, 300, 30)] sage: line(L, rgbcolor=(3/4, 1/4, 1/8)) Graphics object consisting of 1 graphics primitive @@ -543,7 +549,7 @@ def line2d(points, **options): A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`:: sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)] - sage: line(L, rgbcolor=(3/4,1/4,5/8)) + sage: line(L, rgbcolor=(3/4, 1/4, 5/8)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -556,7 +562,7 @@ def line2d(points, **options): sage: i = CDF.gen() sage: v = [zeta(0.5 + n/10 * i) for n in range(300)] sage: L = [(z.real(), z.imag()) for z in v] - sage: line(L, rgbcolor=(3/4,1/2,5/8)) + sage: line(L, rgbcolor=(3/4, 1/2, 5/8)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -568,8 +574,9 @@ def line2d(points, **options): A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') - sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line + sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line sage: L = [(z[1].real(), z[1].imag()) for z in vals] sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index 7676aebe02d..d34bd473829 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -132,8 +132,8 @@ def _allowed_options(self): EXAMPLES:: - sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) - sage: isinstance(M[0]._allowed_options(),dict) + sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) # needs sage.symbolic + sage: isinstance(M[0]._allowed_options(), dict) # needs sage.symbolic True """ return {'cmap':"""the name of a predefined colormap, @@ -158,8 +158,8 @@ def _repr_(self): EXAMPLES:: - sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) - sage: m = M[0]; m + sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) # needs sage.symbolic + sage: m = M[0]; m # needs sage.symbolic MatrixPlot defined by a 5 x 5 data grid """ return "MatrixPlot defined by a %s x %s data grid"%(self.xy_array_row, self.xy_array_col) @@ -388,14 +388,17 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): sage: m=random_matrix(RR,10) sage: m.subdivide([2,4],[6,8]) - sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3)) + sage: matrix_plot(m, subdivisions=True, + ....: subdivision_style=dict(color='red',thickness=3)) Graphics object consisting of 1 graphics primitive You can also specify your own subdivisions and separate styles for row or column subdivisions:: sage: m=random_matrix(RR,10) - sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)]) + sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], + ....: subdivision_style=[dict(color='red',thickness=3), + ....: dict(linestyle='--',thickness=6)]) Graphics object consisting of 1 graphics primitive Generally matrices are plotted with the (0,0) entry in the upper @@ -409,10 +412,9 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): A custom bounding box in which to draw the matrix can be specified using the ``xrange`` and ``yrange`` arguments:: - sage: P = matrix_plot(identity_matrix(10), xrange=(0, pi), yrange=(-pi, 0)) - sage: P + sage: P = matrix_plot(identity_matrix(10), xrange=(0, pi), yrange=(-pi, 0)); P # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: P.get_minmax_data() + sage: P.get_minmax_data() # needs sage.symbolic {'xmax': 3.14159..., 'xmin': 0.0, 'ymax': 0.0, 'ymin': -3.14159...} If the horizontal and vertical dimension of the image are very different, @@ -425,18 +427,19 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): Another random plot, but over `\GF{389}`:: - sage: m = random_matrix(GF(389), 10) - sage: matrix_plot(m, cmap='Oranges') + sage: m = random_matrix(GF(389), 10) # needs sage.rings.finite_rings + sage: matrix_plot(m, cmap='Oranges') # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive It also works if you lift it to the polynomial ring:: - sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') + sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive We have several options for colorbars:: - sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal') + sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, + ....: colorbar_orientation='horizontal') Graphics object consisting of 1 graphics primitive :: @@ -456,27 +459,28 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): Here we plot a random sparse matrix:: - sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in range(100)])) + sage: sparse = matrix(dict(((randint(0, 10), randint(0, 10)), 1) + ....: for i in range(100))) sage: matrix_plot(sparse) Graphics object consisting of 1 graphics primitive :: - sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True) - sage: matrix_plot(A,marker=',') + sage: A = random_matrix(ZZ, 100000, density=.00001, sparse=True) + sage: matrix_plot(A, marker=',') Graphics object consisting of 1 graphics primitive As with dense matrices, sparse matrix entries are automatically converted to floating point numbers before plotting. Thus the following works:: - sage: b=random_matrix(GF(2),200,sparse=True,density=0.01) - sage: matrix_plot(b) + sage: b = random_matrix(GF(2), 200, sparse=True, density=0.01) # needs sage.rings.finite_rings + sage: matrix_plot(b) # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive While this returns an error:: - sage: b=random_matrix(CDF,200,sparse=True,density=0.01) + sage: b = random_matrix(CDF, 200, sparse=True, density=0.01) sage: matrix_plot(b) Traceback (most recent call last): ... @@ -485,7 +489,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): To plot the absolute value of a complex matrix, use the ``apply_map`` method:: - sage: b=random_matrix(CDF,200,sparse=True,density=0.01) + sage: b = random_matrix(CDF, 200, sparse=True, density=0.01) sage: matrix_plot(b.apply_map(abs)) Graphics object consisting of 1 graphics primitive @@ -496,8 +500,8 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): As does plotting of NumPy arrays:: - sage: import numpy - sage: matrix_plot(numpy.random.rand(10, 10)) + sage: import numpy # needs numpy + sage: matrix_plot(numpy.random.rand(10, 10)) # needs numpy Graphics object consisting of 1 graphics primitive A plot title can be added to the matrix plot.:: diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index d0ec1c60295..72ee2c049b0 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting utilities """ diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index ae85183dc93..f22febca152 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Graphics arrays and insets diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index ced087a3814..69e78f16ab4 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" 2D plotting @@ -186,7 +187,7 @@ You can even have custom tick labels along with custom positioning. :: - sage: plot(x^2, (x,0,3), ticks=[[1,2.5],pi/2], tick_formatter=[["$x_1$","$x_2$"],pi]) # long time + sage: plot(x^2, (x,0,3), ticks=[[1,2.5],pi/2], tick_formatter=[["$x_1$","$x_2$"],pi]) # long time Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -339,7 +340,7 @@ Many concentric circles shrinking toward the origin:: - sage: show(sum(circle((i,0), i, hue=sin(i/10)) for i in [10,9.9,..,0])) # long time + sage: show(sum(circle((i,0), i, hue=sin(i/10)) for i in [10,9.9,..,0])) # long time .. PLOT:: @@ -419,7 +420,8 @@ def y(x): return x*sin(x**2) sage: g1 = plot(sin(x), 0, 2*pi) sage: g2 = plot(cos(x), 0, 2*pi, linestyle="--") - sage: (g1+g2).show(ticks=pi/6, tick_formatter=pi) # long time # show their sum, nicely formatted + sage: (g1 + g2).show(ticks=pi/6, # show their sum, nicely formatted # long time + ....: tick_formatter=pi) .. PLOT:: @@ -432,7 +434,8 @@ def y(x): return x*sin(x**2) sage: f(x) = (x-3)*(x-5)*(x-7)+40 sage: P = line([(2,0),(2,f(2))], color='black') sage: P += line([(8,0),(8,f(8))], color='black') - sage: P += polygon([(2,0),(2,f(2))] + [(x, f(x)) for x in [2,2.1,..,8]] + [(8,0),(2,0)], rgbcolor=(0.8,0.8,0.8),aspect_ratio='automatic') + sage: P += polygon([(2,0),(2,f(2))] + [(x, f(x)) for x in [2,2.1,..,8]] + [(8,0),(2,0)], + ....: rgbcolor=(0.8,0.8,0.8), aspect_ratio='automatic') sage: P += text("$\\int_{a}^b f(x) dx$", (5, 20), fontsize=16, color='black') sage: P += plot(f, (1, 8.5), thickness=3) sage: P # show the result @@ -515,7 +518,7 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 Verify that a clean sage startup does *not* import matplotlib:: - sage: os.system("sage -c \"if 'matplotlib' in sys.modules: sys.exit(1)\"") # long time + sage: os.system("sage -c \"if 'matplotlib' in sys.modules: sys.exit(1)\"") # long time 0 Verify that :trac:`10980` is fixed:: @@ -681,15 +684,17 @@ def SelectiveFormatter(formatter, skip_values): :: + sage: # needs numpy sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.pyplot as plt sage: import numpy - sage: fig=plt.figure() - sage: ax=fig.add_subplot(111) + sage: fig = plt.figure() + sage: ax = fig.add_subplot(111) sage: t = numpy.arange(0.0, 2.0, 0.01) sage: s = numpy.sin(2*numpy.pi*t) sage: p = ax.plot(t, s) - sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1]) + sage: formatter = SelectiveFormatter(ax.xaxis.get_major_formatter(), + ....: skip_values=[0,1]) sage: ax.xaxis.set_major_formatter(formatter) sage: import tempfile sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: @@ -715,15 +720,17 @@ def __init__(self, formatter, skip_values): EXAMPLES:: + sage: # needs numpy sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.pyplot as plt sage: import numpy - sage: fig=plt.figure() - sage: ax=fig.add_subplot(111) + sage: fig = plt.figure() + sage: ax = fig.add_subplot(111) sage: t = numpy.arange(0.0, 2.0, 0.01) sage: s = numpy.sin(2*numpy.pi*t) - sage: line=ax.plot(t, s) - sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1]) + sage: line = ax.plot(t, s) + sage: formatter = SelectiveFormatter(ax.xaxis.get_major_formatter(), + ....: skip_values=[0,1]) sage: ax.xaxis.set_major_formatter(formatter) sage: from tempfile import NamedTemporaryFile sage: with NamedTemporaryFile(suffix=".png") as f: @@ -740,7 +747,8 @@ def set_locs(self, locs): sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.ticker - sage: formatter=SelectiveFormatter(matplotlib.ticker.Formatter(),skip_values=[0,200]) + sage: formatter = SelectiveFormatter(matplotlib.ticker.Formatter(), + ....: skip_values=[0,200]) sage: formatter.set_locs([i*100 for i in range(10)]) """ self.formatter.set_locs([l for l in locs if l not in self.skip_values]) @@ -753,7 +761,8 @@ def __call__(self, x, *args, **kwds): sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.ticker - sage: formatter=SelectiveFormatter(matplotlib.ticker.FixedFormatter(['a','b']),skip_values=[0,2]) + sage: formatter = SelectiveFormatter(matplotlib.ticker.FixedFormatter(['a','b']), + ....: skip_values=[0,2]) sage: [formatter(i,1) for i in range(10)] ['', 'b', '', 'b', 'b', 'b', 'b', 'b', 'b', 'b'] """ @@ -1101,7 +1110,7 @@ def plot(funcs, *args, **kwds): :: - sage: p=plot(1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0) + sage: p = plot(1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0) sage: list(p[0]) [(0.0, 1.0), (1.0, 1.0), (2.0, 1.0), (3.0, 1.0)] @@ -1139,9 +1148,12 @@ def plot(funcs, *args, **kwds): By default, color will change from one primitive to the next. This may be controlled by modifying ``color`` option:: - sage: g1 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), color='blue', aspect_ratio=.8); g1 + sage: g1 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), + ....: color='blue', aspect_ratio=.8); g1 Graphics object consisting of 3 graphics primitives - sage: g2 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), color=['red','red','green'], linestyle=['-','--','-.'], aspect_ratio=.8); g2 + sage: g2 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), + ....: color=['red','red','green'], linestyle=['-','--','-.'], + ....: aspect_ratio=.8); g2 Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1210,7 +1222,7 @@ def plot(funcs, *args, **kwds): a graph is on both sides of both axes, as the axes only cross if the origin is actually part of the viewing area:: - sage: plot(x^3,(x,0,2)) # this one has the origin + sage: plot(x^3, (x,0,2)) # this one has the origin Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1220,7 +1232,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(x^3,(x,1,2)) # this one does not + sage: plot(x^3, (x,1,2)) # this one does not Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1232,7 +1244,7 @@ def plot(funcs, *args, **kwds): the labels have quite different orders of magnitude or are very large, scientific notation (the `e` notation for powers of ten) is used:: - sage: plot(x^2,(x,480,500)) # this one has no scientific notation + sage: plot(x^2, (x,480,500)) # this one has no scientific notation Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1242,7 +1254,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(x^2,(x,300,500)) # this one has scientific notation on y-axis + sage: plot(x^2, (x,300,500)) # this one has scientific notation on y-axis Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1322,7 +1334,7 @@ def plot(funcs, *args, **kwds): If `X` is a list of Sage objects and ``legend_label`` is 'automatic', then Sage will create labels for each function according to their internal representation:: - sage: plot([sin(x), tan(x), 1-x^2], legend_label='automatic') + sage: plot([sin(x), tan(x), 1 - x^2], legend_label='automatic') Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1365,7 +1377,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot_semilogy(exp, (1, 10)) # same thing + sage: plot_semilogy(exp, (1, 10)) # same thing Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1385,7 +1397,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(exp, (1, 10), scale='loglog', base=2) # long time # base of log is 2 + sage: plot(exp, (1, 10), scale='loglog', base=2) # base of log is 2 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1396,15 +1408,16 @@ def plot(funcs, *args, **kwds): We can also change the scale of the axes in the graphics just before displaying:: - sage: G = plot(exp, 1, 10) # long time - sage: G.show(scale=('semilogy', 2)) # long time + sage: G = plot(exp, 1, 10) # long time + sage: G.show(scale=('semilogy', 2)) # long time The algorithm used to insert extra points is actually pretty simple. On the picture drawn by the lines below:: sage: p = plot(x^2, (-0.5, 1.4)) + line([(0,0), (1,1)], color='green') sage: p += line([(0.5, 0.5), (0.5, 0.5^2)], color='purple') - sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), color='red', pointsize=20) + sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), + ....: color='red', pointsize=20) sage: p += text('A', (-0.05, 0.1), color='red') sage: p += text('B', (1.01, 1.1), color='red') sage: p += text('C', (0.48, 0.57), color='red') @@ -1444,8 +1457,8 @@ def plot(funcs, *args, **kwds): :: - sage: def h1(x): return abs(sqrt(x^3 - 1)) - sage: def h2(x): return -abs(sqrt(x^3 - 1)) + sage: def h1(x): return abs(sqrt(x^3 - 1)) + sage: def h2(x): return -abs(sqrt(x^3 - 1)) sage: P = plot([h1, h2], 1,4) sage: P # show the result Graphics object consisting of 2 graphics primitives @@ -1467,14 +1480,16 @@ def h2(x): return -abs(sqrt(x**3 - 1)) As a workaround, we can perform the trick:: - sage: p1 = line([(a,b) for a,b in zip(p[0].xdata,p[0].ydata) if (b>=-1 and b<=1)]) - sage: q1 = line([(a,b) for a,b in zip(q[0].xdata,q[0].ydata) if (b>=0 and b<=4)]) - sage: (p1+q1).show() + sage: p1 = line([(a,b) for a, b in zip(p[0].xdata, p[0].ydata) + ....: if b>=-1 and b<=1]) + sage: q1 = line([(a,b) for a, b in zip(q[0].xdata, q[0].ydata) + ....: if b>=0 and b<=4]) + sage: (p1 + q1).show() We can also directly plot the elliptic curve:: - sage: E = EllipticCurve([0,-1]) - sage: plot(E, (1, 4), color=hue(0.6)) + sage: E = EllipticCurve([0,-1]) # needs sage.schemes + sage: plot(E, (1, 4), color=hue(0.6)) # needs sage.schemes Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1600,8 +1615,10 @@ def h2(x): return -abs(sqrt(x**3 - 1)) sage: p1 = plot(sin(x), -pi, pi, fill='axis') sage: p2 = plot(sin(x), -pi, pi, fill='min', fillalpha=1) sage: p3 = plot(sin(x), -pi, pi, fill='max') - sage: p4 = plot(sin(x), -pi, pi, fill=(1-x)/3, fillcolor='blue', fillalpha=.2) - sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time + sage: p4 = plot(sin(x), -pi, pi, fill=(1-x)/3, + ....: fillcolor='blue', fillalpha=.2) + sage: graphics_array([[p1, p2], # long time + ....: [p3, p4]]).show(frame=True, axes=False) .. PLOT:: @@ -1615,11 +1632,15 @@ def h2(x): return -abs(sqrt(x**3 - 1)) The basic options for filling a list of plots:: sage: (f1, f2) = x*exp(-1*x^2)/.35, x*exp(-2*x^2)/.35 - sage: p1 = plot([f1, f2], -pi, pi, fill={1: [0]}, fillcolor='blue', fillalpha=.25, color='blue') + sage: p1 = plot([f1, f2], -pi, pi, fill={1: [0]}, + ....: fillcolor='blue', fillalpha=.25, color='blue') sage: p2 = plot([f1, f2], -pi, pi, fill={0: x/3, 1:[0]}, color=['blue']) - sage: p3 = plot([f1, f2], -pi, pi, fill=[0, [0]], fillcolor=['orange','red'], fillalpha=1, color={1: 'blue'}) - sage: p4 = plot([f1, f2], (x,-pi, pi), fill=[x/3, 0], fillcolor=['grey'], color=['red', 'blue']) - sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time + sage: p3 = plot([f1, f2], -pi, pi, fill=[0, [0]], + ....: fillcolor=['orange','red'], fillalpha=1, color={1: 'blue'}) + sage: p4 = plot([f1, f2], (x,-pi, pi), fill=[x/3, 0], + ....: fillcolor=['grey'], color=['red', 'blue']) + sage: graphics_array([[p1, p2], # long time + ....: [p3, p4]]).show(frame=True, axes=False) .. PLOT:: @@ -1633,7 +1654,8 @@ def h2(x): return -abs(sqrt(x**3 - 1)) A example about the growth of prime numbers:: - sage: plot(1.13*log(x), 1, 100, fill=lambda x: nth_prime(x)/floor(x), fillcolor='red') + sage: plot(1.13*log(x), 1, 100, + ....: fill=lambda x: nth_prime(x)/floor(x), fillcolor='red') Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1643,7 +1665,7 @@ def h2(x): return -abs(sqrt(x**3 - 1)) Fill the area between a function and its asymptote:: sage: f = (2*x^3+2*x-1)/((x-2)*(x+1)) - sage: plot([f, 2*x+2], -7,7, fill={0: [1]}, fillcolor='#ccc').show(ymin=-20, ymax=20) + sage: plot([f, 2*x+2], -7, 7, fill={0: [1]}, fillcolor='#ccc').show(ymin=-20, ymax=20) .. PLOT:: @@ -1670,16 +1692,18 @@ def b(n): return lambda x: bessel_J(n, x) like ``i:j`` will fill between the ith function and the line y=j:: sage: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) - sage: plot([b(c) for c in [1..5]], 0, 20, fill={i:[i-1] for i in [1..4]}, color={i:'blue' for i in [1..5]}, aspect_ratio=3, ymax=3) + sage: plot([b(c) for c in [1..5]], 0, 20, fill={i: [i-1] for i in [1..4]}, + ....: color={i: 'blue' for i in [1..5]}, aspect_ratio=3, ymax=3) Graphics object consisting of 9 graphics primitives - sage: plot([b(c) for c in [1..5]], 0, 20, fill={i:i-1 for i in [1..4]}, color='blue', aspect_ratio=3) # long time + sage: plot([b(c) for c in [1..5]], 0, 20, fill={i: i-1 for i in [1..4]}, # long time + ....: color='blue', aspect_ratio=3) Graphics object consisting of 9 graphics primitives .. PLOT:: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) g1 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:[i-1] for i in range(1,5)}, color={i:'blue' for i in range(1,6)}, aspect_ratio=3) - g2 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:i-1 for i in range(1,5)}, color='blue', aspect_ratio=3) # long time + g2 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:i-1 for i in range(1,5)}, color='blue', aspect_ratio=3) g1.ymax(3) g = graphics_array([[g1], [g2]]) sphinx_plot(g) @@ -1687,39 +1711,42 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) Extra options will get passed on to :meth:`~sage.plot.graphics.Graphics.show`, as long as they are valid:: - sage: plot(sin(x^2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) # These labels will be nicely typeset + sage: plot(sin(x^2), (x, -3, 3), # These labels will be nicely typeset + ....: title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) # These labels will be nicely typeset + g = plot(sin(x**2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) sphinx_plot(g) :: - sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not + sage: plot(sin(x^2), (x, -3, 3), # These will not + ....: title='Plot of sin(x^2)', axes_labels=['x','y']) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not + g = plot(sin(x**2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) sphinx_plot(g) :: - sage: plot(sin(x^2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) # Large axes labels (w.r.t. the tick marks) + sage: plot(sin(x^2), (x, -3, 3), # Large axes labels (w.r.t. the tick marks) + ....: axes_labels=['x','y'], axes_labels_size=2.5) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) # Large axes labels (w.r.t. the tick marks) + g = plot(sin(x**2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) sphinx_plot(g) :: sage: plot(sin(x^2), (x, -3, 3), figsize=[8,2]) Graphics object consisting of 1 graphics primitive - sage: plot(sin(x^2), (x, -3, 3)).show(figsize=[8,2]) # These are equivalent + sage: plot(sin(x^2), (x, -3, 3)).show(figsize=[8,2]) # These are equivalent .. PLOT:: @@ -1731,7 +1758,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7],[-1/2,0,1/2]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7], [-1/2,0,1/2]]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1741,7 +1768,10 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(2*x + 1, (x, 0, 5), ticks=[[0, 1, e, pi, sqrt(20)], [1, 3, 2*e + 1, 2*pi + 1, 2*sqrt(20) + 1]], tick_formatter="latex") + sage: plot(2*x + 1, (x, 0, 5), + ....: ticks=[[0, 1, e, pi, sqrt(20)], + ....: [1, 3, 2*e + 1, 2*pi + 1, 2*sqrt(20) + 1]], + ....: tick_formatter="latex") Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1753,7 +1783,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(sin(x),(x,0,2*pi),ticks=pi/3,tick_formatter=pi) + sage: plot(sin(x), (x,0,2*pi), ticks=pi/3, tick_formatter=pi) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1763,7 +1793,8 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) You can even have custom tick labels along with custom positioning. :: - sage: plot(x**2, (x,0,3), ticks=[[1,2.5],[0.5,1,2]], tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) + sage: plot(x**2, (x,0,3), ticks=[[1,2.5], [0.5,1,2]], + ....: tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1775,7 +1806,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) option as shown below. This also requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='type1') # optional - latex + sage: plot(x, typeset='type1') # optional - latex Graphics object consisting of 1 graphics primitive A example with excluded values:: @@ -1808,8 +1839,8 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) Excluded points can also be given by an equation:: - sage: g(x) = x^2-2*x-2 - sage: plot(1/g(x), (x, -3, 4), exclude=g(x)==0, ymin=-5, ymax=5) # long time + sage: g(x) = x^2 - 2*x - 2 + sage: plot(1/g(x), (x, -3, 4), exclude=g(x)==0, ymin=-5, ymax=5) # long time Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1821,7 +1852,8 @@ def g(x): return x**2-2*x-2 ``exclude`` and ``detect_poles`` can be used together:: sage: f(x) = (floor(x)+0.5) / (1-(x-0.5)^2) - sage: plot(f, (x, -3.5, 3.5), detect_poles='show', exclude=[-3..3], ymin=-5, ymax=5) + sage: plot(f, (x, -3.5, 3.5), detect_poles='show', exclude=[-3..3], + ....: ymin=-5, ymax=5) Graphics object consisting of 12 graphics primitives .. PLOT:: @@ -1841,7 +1873,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arcsec, (x, -2, 2)) # [-1, 1] is excluded automatically + g = plot(arcsec, (x, -2, 2)) sphinx_plot(g) :: @@ -1852,7 +1884,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arcsec, (x, -2, 2), exclude=[1.5]) # x=1.5 is also excluded + g = plot(arcsec, (x, -2, 2), exclude=[1.5]) sphinx_plot(g) :: @@ -1865,7 +1897,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(sqrt(x**2-1), -2, 2) # [-1, 1] is excluded automatically + g = plot(sqrt(x**2-1), -2, 2) sphinx_plot(g) :: @@ -1877,7 +1909,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arccsc, -2, 2) # [-1, 1] is excluded automatically + g = plot(arccsc, -2, 2) sphinx_plot(g) TESTS: @@ -2552,7 +2584,7 @@ def parametric_plot(funcs, *args, **kwargs): :: - sage: parametric_plot( (sin(t), sin(2*t)), (t, 0, 2*pi), color=hue(0.6) ) + sage: parametric_plot((sin(t), sin(2*t)), (t, 0, 2*pi), color=hue(0.6)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -2608,27 +2640,27 @@ def parametric_plot(funcs, *args, **kwargs): :: - sage: y=var('y') - sage: parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time` + sage: y = var('y') + sage: parametric_plot((5*cos(x), x*y, cos(x*y)), (x, -4, 4), (y, -4, 4)) # long time Graphics3d Object .. PLOT:: #AttributeError: 'sage.plot.plot3d.parametric_surface.ParametricSurf' object has no attribute 'plot' #y = var('y') - #g = parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time` + #g = parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time #sphinx_plot(g) :: - sage: t=var('t') - sage: parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time + sage: t = var('t') + sage: parametric_plot(vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time Graphics object consisting of 1 graphics primitive .. PLOT:: t = var('t') - g = parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time + g = parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time sphinx_plot(g) :: @@ -2694,7 +2726,7 @@ def parametric_plot(funcs, *args, **kwargs): One test for :trac:`7165`:: sage: m = SR.var('m') - sage: parametric_plot([real(exp(i*m)),imaginary(exp(i*m))], (m,0,7)) + sage: parametric_plot([real(exp(i*m)), imaginary(exp(i*m))], (m, 0, 7)) Graphics object consisting of 1 graphics primitive """ num_ranges = 0 @@ -2896,8 +2928,8 @@ def list_plot(data, plotjoined=False, **kwargs): You can provide a numpy array.:: - sage: import numpy - sage: list_plot(numpy.arange(10)) + sage: import numpy # needs numpy + sage: list_plot(numpy.arange(10)) # needs numpy Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -2908,7 +2940,7 @@ def list_plot(data, plotjoined=False, **kwargs): :: - sage: list_plot(numpy.array([[1,2], [2,3], [3,4]])) + sage: list_plot(numpy.array([[1,2], [2,3], [3,4]])) # needs numpy Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -3093,7 +3125,7 @@ def list_plot(data, plotjoined=False, **kwargs): # a tuple. # So, the only other check we need to do is whether data[0] is an # element of the Symbolic Ring. - if data[0] in sage.symbolic.ring.SR: + if isinstance(data[0], Expression): data = list(enumerate(data)) try: @@ -3135,7 +3167,7 @@ def plot_loglog(funcs, *args, **kwds): EXAMPLES:: - sage: plot_loglog(exp, (1,10)) # plot in loglog scale with base 10 + sage: plot_loglog(exp, (1,10)) # plot in loglog scale with base 10 Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -3145,12 +3177,12 @@ def plot_loglog(funcs, *args, **kwds): :: - sage: plot_loglog(exp, (1,10), base=2.1) # long time # with base 2.1 on both axes + sage: plot_loglog(exp, (1,10), base=2.1) # with base 2.1 on both axes # long time Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_loglog(exp, (1,10), base=2.1) # long time # with base 2.1 on both axes + g = plot_loglog(exp, (1,10), base=2.1) sphinx_plot(g) :: @@ -3183,27 +3215,27 @@ def plot_semilogx(funcs, *args, **kwds): EXAMPLES:: - sage: plot_semilogx(exp, (1,10)) # long time # plot in semilogx scale, base 10 + sage: plot_semilogx(exp, (1,10)) # plot in semilogx scale, base 10 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_semilogx(exp, (1,10)) # long time # plot in semilogx scale, base 10 + g = plot_semilogx(exp, (1,10)) sphinx_plot(g) :: - sage: plot_semilogx(exp, (1,10), base=2) # with base 2 + sage: plot_semilogx(exp, (1,10), base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_semilogx(exp, (1,10), base=2) # with base 2 + g = plot_semilogx(exp, (1,10), base=2) sphinx_plot(g) :: - sage: s = var('s') # Samples points logarithmically so graph is smooth + sage: s = var('s') # Samples points logarithmically so graph is smooth sage: f = 4000000/(4000000 + 4000*s*i - s*s) sage: plot_semilogx(20*log(abs(f), 10), (s, 1, 1e6)) Graphics object consisting of 1 graphics primitive @@ -3274,31 +3306,32 @@ def list_plot_loglog(data, plotjoined=False, **kwds): EXAMPLES:: sage: yl = [5**k for k in range(10)]; xl = [2**k for k in range(10)] - sage: list_plot_loglog(list(zip(xl, yl))) # long time # plot in loglog scale with base 10 + sage: list_plot_loglog(list(zip(xl, yl))) # use loglog scale with base 10 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [5**k for k in range(10)] xl = [2**k for k in range(10)] - g = list_plot_loglog(list(zip(xl, yl))) # long time # plot in loglog scale with base 10 + g = list_plot_loglog(list(zip(xl, yl))) sphinx_plot(g) :: - sage: list_plot_loglog(list(zip(xl, yl)), base=2.1) # long time # with base 2.1 on both axes + sage: list_plot_loglog(list(zip(xl, yl)), # with base 2.1 on both axes # long time + ....: base=2.1) Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [5**k for k in range(10)] xl = [2**k for k in range(10)] - g = list_plot_loglog(list(zip(xl, yl)), base=2.1) # long time # with base 2.1 on both axes + g = list_plot_loglog(list(zip(xl, yl)), base=2.1) sphinx_plot(g) :: - sage: list_plot_loglog(list(zip(xl, yl)), base=(2,5)) # long time + sage: list_plot_loglog(list(zip(xl, yl)), base=(2,5)) # long time Graphics object consisting of 1 graphics primitive .. warning:: @@ -3356,7 +3389,7 @@ def list_plot_semilogx(data, plotjoined=False, **kwds): :: sage: yl = [2**k for k in range(12)] - sage: list_plot_semilogx(yl) # plot empty due to (0,1) + sage: list_plot_semilogx(yl) # plot empty due to (0,1) Graphics object consisting of 1 graphics primitive We remove `(0,1)` to fix this.:: @@ -3366,12 +3399,12 @@ def list_plot_semilogx(data, plotjoined=False, **kwds): :: - sage: list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 + sage: list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 + g = list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) sphinx_plot(g) """ @@ -3393,13 +3426,13 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): EXAMPLES:: sage: yl = [2**k for k in range(12)] - sage: list_plot_semilogy(yl) # plot in semilogy scale, base 10 + sage: list_plot_semilogy(yl) # plot in semilogy scale, base 10 Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [2**k for k in range(12)] - g = list_plot_semilogy(yl) # plot in semilogy scale, base 10 + g = list_plot_semilogy(yl) # plot in semilogy scale, base 10 sphinx_plot(g) .. warning:: @@ -3412,7 +3445,7 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): :: sage: xl = [2**k for k in range(12)]; yl = range(len(xl)) - sage: list_plot_semilogy(list(zip(xl,yl))) # plot empty due to (1,0) + sage: list_plot_semilogy(list(zip(xl, yl))) # plot empty due to (1,0) doctest:warning ... Graphics object consisting of 1 graphics primitive @@ -3424,12 +3457,12 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): :: - sage: list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 + sage: list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 + g = list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) sphinx_plot(g) """ @@ -3466,7 +3499,7 @@ def reshape(v, n, m): EXAMPLES:: - sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in range(10)] + sage: L = [plot(sin(k*x), (x,-pi,pi)) for k in range(10)] sage: graphics_array(L,3,4) # long time (up to 4s on sage.math, 2012) Graphics Array of size 3 x 4 @@ -3536,17 +3569,18 @@ def graphics_array(array, nrows=None, ncols=None): Make some plots of `\sin` functions:: + sage: # long time sage: f(x) = sin(x) sage: g(x) = sin(2*x) sage: h(x) = sin(4*x) - sage: p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) # long time - sage: p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) # long time - sage: p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) # long time - sage: p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) # long time + sage: p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) + sage: p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) + sage: p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) + sage: p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) Now make a graphics array out of the plots:: - sage: graphics_array(((p1,p2), (p3,p4))) # long time + sage: graphics_array(((p1,p2), (p3,p4))) # long time Graphics Array of size 2 x 2 .. PLOT:: @@ -3554,26 +3588,25 @@ def graphics_array(array, nrows=None, ncols=None): def f(x): return sin(x) def g(x): return sin(2*x) def h(x): return sin(4*x) - p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) # long time - p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) # long time - p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) # long time - p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) # long time - g = graphics_array(((p1, p2), (p3, p4))) # long time + p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) + p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) + p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) + p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) + g = graphics_array(((p1, p2), (p3, p4))) sphinx_plot(g) One can also name the array, and then use :meth:`~sage.plot.multigraphics.MultiGraphics.show` or :meth:`~sage.plot.multigraphics.MultiGraphics.save`:: - sage: ga = graphics_array(((p1,p2), (p3,p4))) # long time + sage: ga = graphics_array(((p1,p2), (p3,p4))) # long time sage: ga.show() # long time; same output as above Here we give only one row:: - sage: p1 = plot(sin,(-4,4)) - sage: p2 = plot(cos,(-4,4)) - sage: ga = graphics_array([p1, p2]) - sage: ga + sage: p1 = plot(sin, (-4,4)) + sage: p2 = plot(cos, (-4,4)) + sage: ga = graphics_array([p1, p2]); ga Graphics Array of size 1 x 2 sage: ga.show() @@ -3830,7 +3863,12 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01, adaptive_recursion=0) [] sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01) - [(0.125*pi, 0.3826834323650898), (0.1875*pi, 0.5555702330196022), (0.25*pi, 0.7071067811865475), (0.3125*pi, 0.8314696123025452), (0.375*pi, 0.9238795325112867), (0.4375*pi, 0.9807852804032304), (0.5*pi, 1.0), (0.5625*pi, 0.9807852804032304), (0.625*pi, 0.9238795325112867), (0.6875*pi, 0.8314696123025455), (0.75*pi, 0.7071067811865476), (0.8125*pi, 0.5555702330196022), (0.875*pi, 0.3826834323650899)] + [(0.125*pi, 0.3826834323650898), (0.1875*pi, 0.5555702330196022), + (0.25*pi, 0.7071067811865475), (0.3125*pi, 0.8314696123025452), + (0.375*pi, 0.9238795325112867), (0.4375*pi, 0.9807852804032304), + (0.5*pi, 1.0), (0.5625*pi, 0.9807852804032304), (0.625*pi, 0.9238795325112867), + (0.6875*pi, 0.8314696123025455), (0.75*pi, 0.7071067811865476), + (0.8125*pi, 0.5555702330196022), (0.875*pi, 0.3826834323650899)] This shows that lowering ``adaptive_tolerance`` and raising ``adaptive_recursion`` both increase the number of subdivision diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 84acb7f6c89..85510d0c33a 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -841,6 +841,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: v = (1,2,3) sage: G = arrow3d((0, 0, 0), v) @@ -861,6 +862,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: G = Cone(1/5, 1) + Cone(1/5, 1, opacity=.25).rotateX(pi/2) sage: G.show(aspect_ratio=1) @@ -873,6 +875,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: G = Cone(1/5, 1) + Cone(1/5, 1, opacity=.25).rotateY(pi/3) sage: G.show(aspect_ratio=1) @@ -885,6 +888,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Box sage: G = Box(1/2, 1/3, 1/5) + Box(1/2, 1/3, 1/5, opacity=.25).rotateZ(pi/5) sage: G.show(aspect_ratio=1) @@ -1761,17 +1765,17 @@ end_scene""".format( EXAMPLES: We illustrate use of the ``aspect_ratio`` option:: - sage: x, y = var('x,y') - sage: p = plot3d(2*sin(x*y), (x, -pi, pi), (y, -pi, pi)) - sage: p.show(aspect_ratio=[1,1,1]) + sage: x, y = var('x,y') # needs sage.symbolic + sage: p = plot3d(2*sin(x*y), (x, -pi, pi), (y, -pi, pi)) # needs sage.symbolic + sage: p.show(aspect_ratio=[1,1,1]) # needs sage.symbolic This looks flattened, but filled with the plot:: - sage: p.show(frame_aspect_ratio=[1,1,1/16]) + sage: p.show(frame_aspect_ratio=[1,1,1/16]) # needs sage.symbolic This looks flattened, but the plot is square and smaller:: - sage: p.show(aspect_ratio=[1,1,1], frame_aspect_ratio=[1,1,1/8]) + sage: p.show(aspect_ratio=[1,1,1], frame_aspect_ratio=[1,1,1/8]) # needs sage.symbolic This example shows indirectly that the defaults from :func:`~sage.plot.plot.plot` are dealt with properly:: @@ -1782,17 +1786,17 @@ end_scene""".format( We use the 'canvas3d' backend from inside the notebook to get a view of the plot rendered inline using HTML canvas:: - sage: p.show(viewer='canvas3d') + sage: p.show(viewer='canvas3d') # needs sage.symbolic Sometimes shadows in Tachyon-produced images can lead to confusing plots. To remove them:: - sage: p.show(viewer="tachyon", shade="medium") + sage: p.show(viewer="tachyon", shade="medium") # needs sage.symbolic One can also pass Tachyon command line flags directly. For example, the following line produces the same result as the previous one:: - sage: p.show(viewer="tachyon", extra_opts="-mediumshade") + sage: p.show(viewer="tachyon", extra_opts="-mediumshade") # needs sage.symbolic """ from sage.repl.rich_output import get_display_manager dm = get_display_manager() @@ -1986,6 +1990,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.stl_binary() @@ -1998,9 +2003,9 @@ end_scene""".format( This works when faces have more then 3 sides:: - sage: P = polytopes.dodecahedron() - sage: Q = P.plot().all[-1] - sage: print(Q.stl_binary()[:40].decode('ascii')) + sage: P = polytopes.dodecahedron() # needs sage.geometry.polyhedron + sage: Q = P.plot().all[-1] # needs sage.geometry.polyhedron + sage: print(Q.stl_binary()[:40].decode('ascii')) # needs sage.geometry.polyhedron STL binary file / made by SageMath / ### """ import struct @@ -2033,6 +2038,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.stl_ascii_string() @@ -2059,9 +2065,9 @@ end_scene""".format( Now works when faces have more then 3 sides:: - sage: P = polytopes.dodecahedron() - sage: Q = P.plot().all[-1] - sage: print(Q.stl_ascii_string().splitlines()[:7]) + sage: P = polytopes.dodecahedron() # needs sage.geometry.polyhedron + sage: Q = P.plot().all[-1] # needs sage.geometry.polyhedron + sage: print(Q.stl_ascii_string().splitlines()[:7]) # needs sage.geometry.polyhedron ['solid surface', 'facet normal 0.0 0.5257311121191338 0.8506508083520399', ' outer loop', @@ -2128,6 +2134,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.ply_ascii_string() @@ -2202,6 +2209,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: a_amf = a.amf_ascii_string() @@ -2601,6 +2609,7 @@ class TransformGroup(Graphics3dGroup): EXAMPLES:: + sage: from math import pi sage: G = cube() sage: G.bounding_box() ((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)) diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index cfebf8a2f3b..60a51a3dcbe 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Implicit plots """ @@ -23,13 +24,13 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): marching cubes algorithm will be one less than this). Can be a triple of integers, to specify a different resolution in each of x,y,z. - - ``contour`` -- (default: 0) plot the isosurface f(x,y,z)==contour. Can be a - list, in which case multiple contours are plotted. + - ``contour`` -- (default: 0) plot the isosurface ``f(x,y,z) == contour``. + Can be a list, in which case multiple contours are plotted. - ``region`` -- (default: None) If region is given, it must be a Python - callable. Only segments of the surface where region(x,y,z) returns a - number >0 will be included in the plot. (Note that returning a Python - boolean is acceptable, since True == 1 and False == 0). + callable. Only segments of the surface where ``region(x,y,z)`` returns a + number `>0` will be included in the plot. (Note that returning a Python + boolean is acceptable, since ``True == 1`` and ``False == 0``). EXAMPLES:: @@ -51,8 +52,9 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): A nested set of spheres with a hole cut out:: sage: F = x^2 + y^2 + z^2 - sage: P = implicit_plot3d(F, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=[1,3,5], - ....: region=lambda x,y,z: x<=0.2 or y>=0.2 or z<=0.2, color='aquamarine') + sage: P = implicit_plot3d(F, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, + ....: contour=[1,3,5], color='aquamarine', + ....: region=lambda x,y,z: x<=0.2 or y>=0.2 or z<=0.2) sage: P.show(viewer='tachyon') # long time .. PLOT:: @@ -67,9 +69,11 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): `_):: sage: T = RDF(golden_ratio) - sage: F = 2 - (cos(x+T*y) + cos(x-T*y) + cos(y+T*z) + cos(y-T*z) + cos(z-T*x) + cos(z+T*x)) + sage: F = 2 - (cos(x+T*y) + cos(x-T*y) + cos(y+T*z) + ....: + cos(y-T*z) + cos(z-T*x) + cos(z+T*x)) sage: r = 4.77 - sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=40, color='darkkhaki').show(viewer='tachyon') + sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=40, color='darkkhaki').show(viewer='tachyon') .. PLOT:: @@ -87,7 +91,8 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): sage: F = (x^2+9/4*y^2+z^2-1)^3 - x^2*z^3 - 9/(80)*y^2*z^3 sage: r = 1.5 - sage: V = implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=80, color='red', smooth=False) + sage: V = implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=80, color='red', smooth=False) sage: V.show(viewer='tachyon') # long time .. PLOT:: @@ -101,13 +106,16 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): The same examples also work with the default Jmol viewer; for example:: sage: T = RDF(golden_ratio) - sage: F = 2 - (cos(x + T*y) + cos(x - T*y) + cos(y + T*z) + cos(y - T*z) + cos(z - T*x) + cos(z + T*x)) + sage: F = 2 - (cos(x + T*y) + cos(x - T*y) + cos(y + T*z) + ....: + cos(y - T*z) + cos(z - T*x) + cos(z + T*x)) sage: r = 4.77 - sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=40, color='deepskyblue').show() + sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=40, color='deepskyblue').show() - Here we use smooth=True with a Tachyon graph:: + Here we use ``smooth=True`` with a Tachyon graph:: - sage: implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, color='deepskyblue', smooth=True) + sage: implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: contour=4, color='deepskyblue', smooth=True) Graphics3d Object .. PLOT:: @@ -117,14 +125,15 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): P = implicit_plot3d(F, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, color='deepskyblue', smooth=True) sphinx_plot(P) - We explicitly specify a gradient function (in conjunction with smooth=True) + We explicitly specify a gradient function (in conjunction with ``smooth=True``) and invert the normals:: sage: gx = lambda x, y, z: -(2*x + y^2 + z^2) sage: gy = lambda x, y, z: -(x^2 + 2*y + z^2) sage: gz = lambda x, y, z: -(x^2 + y^2 + 2*z) - sage: implicit_plot3d(x^2+y^2+z^2, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, - ....: plot_points=40, smooth=True, gradient=(gx, gy, gz)).show(viewer='tachyon') + sage: implicit_plot3d(x^2+y^2+z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: contour=4, plot_points=40, smooth=True, + ....: gradient=(gx, gy, gz)).show(viewer='tachyon') .. PLOT:: @@ -138,8 +147,11 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): A graph of two metaballs interacting with each other:: - sage: def metaball(x0, y0, z0): return 1 / ((x-x0)^2+(y-y0)^2+(z-z0)^2) - sage: implicit_plot3d(metaball(-0.6,0,0) + metaball(0.6,0,0), (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=2, color='seagreen') + sage: def metaball(x0, y0, z0): + ....: return 1 / ((x-x0)^2+(y-y0)^2+(z-z0)^2) + sage: implicit_plot3d(metaball(-0.6,0,0) + metaball(0.6,0,0), + ....: (x,-2,2), (y,-2,2), (z,-2,2), + ....: plot_points=60, contour=2, color='seagreen') Graphics3d Object .. PLOT:: @@ -151,7 +163,7 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) One can also color the surface using a coloring function and a colormap as follows. Note that the coloring function must take - values in the interval [0,1]. :: + values in the interval `[0,1]`. :: sage: t = (sin(3*z)**2).function(x,y,z) sage: cm = colormaps.gist_rainbow @@ -173,8 +185,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) sage: x, y, z = var('x,y,z') sage: t = (x).function(x,y,z) sage: cm = colormaps.PiYG - sage: G = implicit_plot3d(x^4 + y^2 + z^2, (x,-2,2), - ....: (y,-2,2),(z,-2,2), contour=4, color=(t,cm), plot_points=40) + sage: G = implicit_plot3d(x^4 + y^2 + z^2, (x,-2,2), (y,-2,2),(z,-2,2), + ....: contour=4, color=(t,cm), plot_points=40) sage: G Graphics3d Object @@ -191,7 +203,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A kind of saddle:: - sage: implicit_plot3d(x^3 + y^2 - z^2, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=0, color='lightcoral') + sage: implicit_plot3d(x^3 + y^2 - z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: plot_points=60, contour=0, color='lightcoral') Graphics3d Object .. PLOT:: @@ -202,7 +215,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A smooth surface with six radial openings:: - sage: implicit_plot3d(-(cos(x) + cos(y) + cos(z)), (x,-4,4), (y,-4,4), (z,-4,4), color='orchid') + sage: implicit_plot3d(-(cos(x) + cos(y) + cos(z)), + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='orchid') Graphics3d Object .. PLOT:: @@ -267,7 +281,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Drope:: - sage: implicit_plot3d(z - 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2), (z,-1.7,1.7), color='darkcyan') + sage: implicit_plot3d(z - 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2), (z,-1.7,1.7), + ....: color='darkcyan') Graphics3d Object .. PLOT:: @@ -291,7 +306,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A simple hyperbolic surface:: - sage: implicit_plot3d(x^2 + y - z^2, (x,-1,1), (y,-1,1), (z,-1,1), color='darkslategray') + sage: implicit_plot3d(x^2 + y - z^2, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='darkslategray') Graphics3d Object .. PLOT:: @@ -302,7 +318,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A hyperboloid:: - sage: implicit_plot3d(x^2 + y^2 - z^2 -0.3, (x,-2,2), (y,-2,2), (z,-1.8,1.8), color='honeydew') + sage: implicit_plot3d(x^2 + y^2 - z^2 -0.3, (x,-2,2), (y,-2,2), (z,-1.8,1.8), + ....: color='honeydew') Graphics3d Object .. PLOT:: @@ -313,7 +330,7 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Dupin cyclide (:wikipedia:`Dupin_cyclide`) :: - sage: x, y, z , a, b, c, d = var('x,y,z,a,b,c,d') + sage: x, y, z, a, b, c, d = var('x,y,z,a,b,c,d') sage: a = 3.5 sage: b = 3 sage: c = sqrt(a^2 - b^2) @@ -335,7 +352,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Sinus:: - sage: implicit_plot3d(sin(pi*((x)^2+(y)^2))/2 + z, (x,-1,1), (y,-1,1), (z,-1,1), color='rosybrown') + sage: implicit_plot3d(sin(pi*((x)^2+(y)^2))/2 + z, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='rosybrown') Graphics3d Object .. PLOT:: @@ -346,7 +364,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A torus:: - sage: implicit_plot3d((sqrt(x*x+y*y)-3)^2 + z*z - 1, (x,-4,4), (y,-4,4), (z,-1,1), color='indigo') + sage: implicit_plot3d((sqrt(x*x+y*y)-3)^2 + z*z - 1, (x,-4,4), (y,-4,4), (z,-1,1), + ....: color='indigo') Graphics3d Object .. PLOT:: @@ -357,7 +376,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) An octahedron:: - sage: implicit_plot3d(abs(x) + abs(y) + abs(z) - 1, (x,-1,1), (y,-1,1), (z,-1,1), color='olive') + sage: implicit_plot3d(abs(x) + abs(y) + abs(z) - 1, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='olive') Graphics3d Object .. PLOT:: @@ -368,7 +388,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A cube:: - sage: implicit_plot3d(x^100 + y^100 + z^100 - 1, (x,-2,2), (y,-2,2), (z,-2,2), color='lightseagreen') + sage: implicit_plot3d(x^100 + y^100 + z^100 - 1, (x,-2,2), (y,-2,2), (z,-2,2), + ....: color='lightseagreen') Graphics3d Object .. PLOT:: @@ -379,7 +400,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Toupie:: - sage: implicit_plot3d((sqrt(x*x+y*y)-3)^3 + z*z - 1, (x,-4,4), (y,-4,4), (z,-6,6), color='mintcream') + sage: implicit_plot3d((sqrt(x*x+y*y)-3)^3 + z*z - 1, (x,-4,4), (y,-4,4), (z,-6,6), + ....: color='mintcream') Graphics3d Object .. PLOT:: @@ -404,7 +426,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Chmutov:: sage: F = x^4 + y^4 + z^4 - (x^2 + y^2 + z^2 - 0.3) - sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), color='lightskyblue') + sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), + ....: color='lightskyblue') Graphics3d Object .. PLOT:: @@ -417,7 +440,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Further Chmutov:: sage: F = 2*(x^2*(3-4*x^2)^2+y^2*(3-4*y^2)^2+z^2*(3-4*z^2)^2) - 3 - sage: implicit_plot3d(F, (x,-1.3,1.3), (y,-1.3,1.3), (z,-1.3,1.3), color='darksalmon') + sage: implicit_plot3d(F, (x,-1.3,1.3), (y,-1.3,1.3), (z,-1.3,1.3), + ....: color='darksalmon') Graphics3d Object .. PLOT:: @@ -454,7 +478,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Looks like a water droplet:: - sage: implicit_plot3d(x^2 +y^2 -(1-z)*z^2, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1,1), color='bisque') + sage: implicit_plot3d(x^2 + y^2 - (1-z)*z^2, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1,1), + ....: color='bisque') Graphics3d Object .. PLOT:: @@ -466,7 +491,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Sphere in a cage:: sage: F = (x^8+z^30+y^8-(x^4 + z^50 + y^4 -0.3)) * (x^2+y^2+z^2-0.5) - sage: implicit_plot3d(F, (x,-1.2,1.2), (y,-1.3,1.3), (z,-1.5,1.5), color='firebrick') + sage: implicit_plot3d(F, (x,-1.2,1.2), (y,-1.3,1.3), (z,-1.5,1.5), + ....: color='firebrick') Graphics3d Object .. PLOT:: @@ -478,8 +504,10 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Ortho circle:: - sage: F = ((x^2+y^2-1)^2+z^2) * ((y^2+z^2-1)^2+x^2) * ((z^2+x^2-1)^2+y^2)-0.075^2 * (1+3*(x^2+y^2+z^2)) - sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), color='lemonchiffon') + sage: F = (((x^2+y^2-1)^2+z^2) * ((y^2+z^2-1)^2+x^2) * ((z^2+x^2-1)^2+y^2) + ....: - 0.075^2 * (1+3*(x^2+y^2+z^2))) + sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), + ....: color='lemonchiffon') Graphics3d Object .. PLOT:: @@ -504,7 +532,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Two cylinders intersect to make a cross:: - sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) - 1, (x,-3,3), (y,-3,3), (z,-3,3), color='burlywood') + sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) - 1, (x,-3,3), (y,-3,3), (z,-3,3), + ....: color='burlywood') Graphics3d Object .. PLOT:: @@ -515,7 +544,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Three cylinders intersect in a similar fashion:: - sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) * (y^2+z^2-1)-1, (x,-3,3), (y,-3,3), (z,-3,3), color='aqua') + sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) * (y^2+z^2-1) - 1, + ....: (x,-3,3), (y,-3,3), (z,-3,3), color='aqua') Graphics3d Object .. PLOT:: @@ -526,7 +556,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A sphere-ish object with twelve holes, four on each XYZ plane:: - sage: implicit_plot3d(3*(cos(x)+cos(y)+cos(z)) + 4*cos(x)*cos(y)*cos(z), (x,-3,3), (y,-3,3), (z,-3,3), color='orangered') + sage: implicit_plot3d(3*(cos(x)+cos(y)+cos(z)) + 4*cos(x)*cos(y)*cos(z), + ....: (x,-3,3), (y,-3,3), (z,-3,3), color='orangered') Graphics3d Object .. PLOT:: @@ -537,7 +568,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A gyroid:: - sage: implicit_plot3d(cos(x)*sin(y) + cos(y)*sin(z) + cos(z)*sin(x), (x,-4,4), (y,-4,4), (z,-4,4), color='sandybrown') + sage: implicit_plot3d(cos(x)*sin(y) + cos(y)*sin(z) + cos(z)*sin(x), + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='sandybrown') Graphics3d Object .. PLOT:: @@ -548,7 +580,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Tetrahedra:: - sage: implicit_plot3d((x^2+y^2+z^2)^2 + 8*x*y*z - 10*(x^2+y^2+z^2) + 25, (x,-4,4), (y,-4,4), (z,-4,4), color='plum') + sage: implicit_plot3d((x^2+y^2+z^2)^2 + 8*x*y*z - 10*(x^2+y^2+z^2) + 25, + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='plum') Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index cc3b1634c8c..db8a3f226f3 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Graphics 3D object for representing and triangulating isosurfaces diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index d7d5e508f2a..7c2c9fb535b 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -248,7 +248,8 @@ def cut_edge_by_bisection(pointa, pointb, condition, eps=1.0e-6, N=100): EXAMPLES:: sage: from sage.plot.plot3d.index_face_set import cut_edge_by_bisection - sage: cut_edge_by_bisection((0.0,0.0,0.0),(1.0,1.0,0.0),( (lambda x,y,z: x**2+y**2+z**2<1) ),eps=1.0E-12) + sage: cut_edge_by_bisection((0.0,0.0,0.0), (1.0,1.0,0.0), + ....: lambda x,y,z: x**2+y**2+z**2 < 1, eps=1.0E-12) (0.7071067811864395, 0.7071067811864395, 0.0) """ cdef point_c a, b @@ -302,9 +303,10 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: sage: from sage.plot.plot3d.index_face_set import IndexFaceSet - sage: S = IndexFaceSet([[(1,0,0),(0,1,0),(0,0,1)],[(1,0,0),(0,1,0),(0,0,0)]]) + sage: S = IndexFaceSet([[(1,0,0),(0,1,0),(0,0,1)], [(1,0,0),(0,1,0),(0,0,0)]]) sage: S.face_list() - [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)]] + [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)]] sage: S.vertex_list() [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.0)] @@ -317,13 +319,13 @@ cdef class IndexFaceSet(PrimitiveObject): sage: S = IndexFaceSet(face_list, point_list, color='red') sage: S.face_list() [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 2.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 3.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 4.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 5.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 6.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 7.0)]] + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 2.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 3.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 4.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 5.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 6.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 7.0)]] sage: S.show() A simple example of colored IndexFaceSet (:trac:`12212`):: @@ -396,15 +398,18 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: + sage: # needs sage.symbolic sage: var('x,y,z') (x, y, z) - sage: G = implicit_plot3d(x^2+y^2+z^2 - 1, (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) + sage: G = implicit_plot3d(x^2+y^2+z^2 - 1, + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) sage: G.triangulate() # indirect doctest sage: len(G.face_list()) 44 sage: len(G.vertex_list()) 132 - sage: G = implicit_plot3d(x^2+y^2+z^2 - 100, (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) + sage: G = implicit_plot3d(x^2+y^2+z^2 - 100, + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) sage: G.triangulate() # indirect doctest sage: len(G.face_list()) 0 @@ -698,13 +703,13 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: S.index_faces_with_colors() [([0, 4, 5], '#ff0000'), - ([3, 4, 5], '#ff9900'), - ([2, 3, 4], '#cbff00'), - ([1, 3, 5], '#33ff00')] + ([3, 4, 5], '#ff9900'), + ([2, 3, 4], '#cbff00'), + ([1, 3, 5], '#33ff00')] When the texture is global, an error is raised:: @@ -847,7 +852,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: print(S.x3d_geometry()) @@ -896,9 +901,9 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: - sage: x,y = var('x,y') - sage: p = plot3d(sqrt(sin(x)*sin(y)), (x,0,2*pi),(y,0,2*pi)) - sage: p.bounding_box() + sage: x,y = var('x,y') # needs sage.symbolic + sage: p = plot3d(sqrt(sin(x)*sin(y)), (x,0,2*pi), (y,0,2*pi)) # needs sage.symbolic + sage: p.bounding_box() # needs sage.symbolic ((0.0, 0.0, 0.0), (6.283185307179586, 6.283185307179586, 0.9991889981715697)) """ if self.vcount == 0: @@ -931,7 +936,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: from sage.plot.plot3d.shapes import * sage: S = Box(1,2,3) - sage: len(S.partition(lambda x,y,z : floor(x+y+z))) + sage: len(S.partition(lambda x,y,z: floor(x+y+z))) 6 """ cdef Py_ssize_t i, j, ix, face_ix @@ -1006,12 +1011,12 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: - sage: var('x,y,z') + sage: var('x,y,z') # needs sage.symbolic (x, y, z) - sage: P = implicit_plot3d(z-x*y,(-2,2),(-2,2),(-2,2)) + sage: P = implicit_plot3d(z-x*y,(-2,2),(-2,2),(-2,2)) # needs sage.symbolic sage: def condi(x,y,z): ....: return bool(x*x+y*y+z*z <= Integer(1)) - sage: R = P.add_condition(condi,20);R + sage: R = P.add_condition(condi, 20); R # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1028,8 +1033,9 @@ cdef class IndexFaceSet(PrimitiveObject): ....: return bool(x*x+y*y <= 1.1) sage: cm = colormaps.hsv sage: cf = lambda x,y,z: float(x+y) % 1 - sage: P = implicit_plot3d(x**2+y**2+z**2-1-x**2*z+y**2*z,(-2,2),(-2,2),(-2,2),color=(cm,cf)) - sage: R = P.add_condition(condi,40); R + sage: P = implicit_plot3d(x**2+y**2+z**2-1-x**2*z+y**2*z, # needs sage.symbolic + ....: (-2,2),(-2,2),(-2,2),color=(cm,cf)) + sage: R = P.add_condition(condi,40); R # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1044,10 +1050,11 @@ cdef class IndexFaceSet(PrimitiveObject): An example with transparency:: - sage: P = implicit_plot3d(x**4+y**4+z**2-4,(x,-2,2),(y,-2,2),(z,-2,2),alpha=0.3) + sage: P = implicit_plot3d(x**4+y**4+z**2-4, (x,-2,2), (y,-2,2), (z,-2,2), # needs sage.symbolic + ....: alpha=0.3) sage: def cut(a,b,c): ....: return a*a+c*c > 2 - sage: Q = P.add_condition(cut,40); Q + sage: Q = P.add_condition(cut,40); Q # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1060,11 +1067,11 @@ cdef class IndexFaceSet(PrimitiveObject): A sombrero with quadrilaterals:: - sage: P = plot3d(-sin(2*x*x+2*y*y)*exp(-x*x-y*y),(x,-2,2),(y,-2,2), - ....: color='gold') + sage: P = plot3d(-sin(2*x*x+2*y*y)*exp(-x*x-y*y), (x,-2,2), (y,-2,2), # needs sage.symbolic + ....: color='gold') sage: def cut(x,y,z): ....: return x*x+y*y < 1 - sage: Q = P.add_condition(cut);Q + sage: Q = P.add_condition(cut);Q # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1079,6 +1086,7 @@ cdef class IndexFaceSet(PrimitiveObject): One test for preservation of transparency :trac:`28783`:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: P = plot3d(cos(x*y),(x,-2,2),(y,-2,2),color='red',opacity=0.1) sage: def condi(x,y,z): @@ -1093,7 +1101,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: p = polygon3d([[2,0,0], [0,2,0], [0,0,3]]) sage: def f(x,y,z): ....: return bool(x*x+y*y+z*z<=5) - sage: cut = p.add_condition(f,60,1.0e-12); cut.face_list() + sage: cut = p.add_condition(f,60,1.0e-12); cut.face_list() # needs sage.symbolic [[(0.556128491210302, 0.0, 2.165807263184547), (2.0, 0.0, 0.0), (0.0, 2.0, 0.0), @@ -1214,7 +1222,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: S.tachyon_repr(S.default_render_params()) ['TRI V0 2 0 0 V1 1 0 1 V2 1 1 0', diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 0158f856dbb..b8e4ddffce6 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -72,8 +72,9 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): We plot a matrix of values of ``sin``:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object @@ -85,9 +86,10 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sphinx_plot(list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3])) Though it does not change the shape of the graph, increasing - num_points can increase the clarity of the graph:: + ``num_points`` can increase the clarity of the graph:: - sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', num_points=40, + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -101,7 +103,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sage: import warnings sage: warnings.simplefilter('ignore', UserWarning) - sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -115,7 +118,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): We can make this look better by increasing the number of samples:: - sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', + ....: frame_aspect_ratio=[1, 1, 1/3], num_points=40) Graphics3d Object .. PLOT:: @@ -127,7 +131,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): Let us try a spline:: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -140,7 +145,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): That spline does not capture the oscillation very well; let's try a higher degree spline:: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', degree=5, + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -185,8 +191,11 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sage: l = [] sage: for i in range(-5, 5): ....: for j in range(-5, 5): - ....: l.append((normalvariate(0, 1), normalvariate(0, 1), normalvariate(0, 1))) - sage: L = list_plot3d(l, interpolation_type='clough', color='orange', num_points=100) + ....: l.append((normalvariate(0, 1), + ....: normalvariate(0, 1), + ....: normalvariate(0, 1))) + sage: L = list_plot3d(l, interpolation_type='clough', + ....: color='orange', num_points=100) sage: L Graphics3d Object @@ -308,7 +317,8 @@ def list_plot3d_matrix(m, **kwds): We plot a matrix that illustrates summation modulo `n`:: sage: n = 5 - sage: list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest + sage: list_plot3d(matrix(RDF, n, [(i+j) % n # indirect doctest + ....: for i in [1..n] for j in [1..n]])) Graphics3d Object .. PLOT:: @@ -320,9 +330,10 @@ def list_plot3d_matrix(m, **kwds): We plot a matrix of values of `sin`:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest Graphics3d Object .. PLOT:: @@ -333,7 +344,7 @@ def list_plot3d_matrix(m, **kwds): sphinx_plot(list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3])) :: - sage: list_plot3d(m, color='yellow', interpolation_type='linear') # indirect doctest + sage: list_plot3d(m, color='yellow', interpolation_type='linear') # indirect doctest Graphics3d Object .. PLOT:: @@ -350,7 +361,7 @@ def list_plot3d_matrix(m, **kwds): sage: n = 20 sage: cf = lambda x, y: ((2*(x-y)/n)**2) % 1 sage: list_plot3d(matrix(RDF, n, [cos(pi*(i+j)/n) for i in [1..n] - ....: for j in [1..n]]), color=(cf,cm)) + ....: for j in [1..n]]), color=(cf,cm)) Graphics3d Object .. PLOT:: @@ -412,7 +423,8 @@ def list_plot3d_array_of_arrays(v, interpolation_type, **kwds): With certain extra keywords (see :func:`list_plot3d_matrix`), this function will end up using :func:`list_plot3d_tuples`:: - sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], interpolation_type='spline')) + sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], + ....: interpolation_type='spline')) .. PLOT:: @@ -431,14 +443,14 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): INPUT: - - ``v`` - something that defines a set of points in 3 + - ``v`` -- something that defines a set of points in 3 space, for example: - a matrix - This will be if using an interpolation type other than - 'linear', or if using ``num_points`` with 'linear'; otherwise - see :func:`list_plot3d_matrix`. + This will be if using an ``interpolation_type`` other than + ``'linear'``, or if using ``num_points`` with ``'linear'``; + otherwise see :func:`list_plot3d_matrix`. - a list of 3-tuples @@ -447,33 +459,34 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): OPTIONAL KEYWORDS: - - ``interpolation_type`` - 'linear', 'clough' (CloughTocher2D), 'spline' + - ``interpolation_type`` -- one of ``'linear'``, ``'clough'`` + (CloughTocher2D), ``'spline'`` - 'linear' will perform linear interpolation + ``'linear'`` will perform linear interpolation The option 'clough' will interpolate by using a piecewise cubic interpolating Bezier polynomial on each triangle, using a Clough-Tocher scheme. The interpolant is guaranteed to be continuously differentiable. - The option 'spline' interpolates using a bivariate B-spline. + The option ``'spline'`` interpolates using a bivariate B-spline. - When v is a matrix the default is to use linear interpolation, when - v is a list of points the default is 'clough'. + When ``v`` is a matrix the default is to use linear interpolation, when + ``v`` is a list of points the default is ``'clough'``. - - ``degree`` - an integer between 1 and 5, controls the degree of spline + - ``degree`` -- an integer between 1 and 5, controls the degree of spline used for spline interpolation. For data that is highly oscillatory use higher values - - ``point_list`` - If point_list=True is passed, then if the array + - ``point_list`` -- If ``point_list=True`` is passed, then if the array is a list of lists of length three, it will be treated as an array of points rather than a `3\times n` array. - - ``num_points`` - Number of points to sample interpolating + - ``num_points`` -- Number of points to sample interpolating function in each direction. By default for an `n\times n` array this is `n`. - - ``**kwds`` - all other arguments are passed to the + - ``**kwds`` -- all other arguments are passed to the surface function OUTPUT: a 3d plot @@ -483,9 +496,11 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): All of these use this function; see :func:`list_plot3d` for other list plots:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, color='yellow', interpolation_type='linear', num_points=5) # indirect doctest + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: list_plot3d(m, color='yellow', interpolation_type='linear', # indirect doctest + ....: num_points=5) Graphics3d Object .. PLOT:: @@ -497,7 +512,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -509,7 +525,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]], point_list=True)) + sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]], + ....: point_list=True)) .. PLOT:: @@ -517,7 +534,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], color='yellow', num_points=50) # long time + sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], # long time + ....: color='yellow', num_points=50) Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index d1b352410da..afb2d6fa129 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic """ Parametric plots """ diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 4396c303561..11676df7dfe 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Parametric surface @@ -468,7 +468,8 @@ cdef class ParametricSurface(IndexFaceSet): sage: from sage.plot.plot3d.parametric_surface import MoebiusStrip sage: M = MoebiusStrip(7,3,2) sage: M.bounding_box() - ((-10.0, -7.53907349250478..., -2.9940801852848145), (10.0, 7.53907349250478..., 2.9940801852848145)) + ((-10.0, -7.53907349250478..., -2.9940801852848145), + (10.0, 7.53907349250478..., 2.9940801852848145)) """ # We must triangulate before computing the bounding box; otherwise # we'll get an empty bounding box, as the bounding box is computed @@ -493,7 +494,7 @@ cdef class ParametricSurface(IndexFaceSet): sage: def f(x,y): return x+y, sin(x)*sin(y), x*y # indirect doctests sage: P = ParametricSurface(f, (srange(0,10,0.1), srange(-5,5.0,0.1))) # indirect doctests sage: P.show() # indirect doctests - sage: S = MoebiusStrip(1,.2) # indirect doctests + sage: S = MoebiusStrip(1, .2) # indirect doctests sage: S.show() # indirect doctests """ cdef double u, v diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index eee95d3290f..be590739c3e 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -226,13 +226,14 @@ def tetrahedron(center=(0, 0, 0), size=1, **kwds): A Dodecahedral complex of 5 tetrahedra (a more elaborate example from Peter Jipsen):: - sage: v=(sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) - sage: t=acos(sqrt(5.)/3)/2 - sage: t1=tetrahedron(aspect_ratio=(1,1,1), opacity=0.5).rotateZ(t) - sage: t2=tetrahedron(color='red', opacity=0.5).rotateZ(t).rotate(v,2*pi/5) - sage: t3=tetrahedron(color='green', opacity=0.5).rotateZ(t).rotate(v,4*pi/5) - sage: t4=tetrahedron(color='yellow', opacity=0.5).rotateZ(t).rotate(v,6*pi/5) - sage: t5=tetrahedron(color='orange', opacity=0.5).rotateZ(t).rotate(v,8*pi/5) + sage: from math import pi + sage: v = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) + sage: t = acos(sqrt(5.)/3)/2 + sage: t1 = tetrahedron(aspect_ratio=(1,1,1), opacity=0.5).rotateZ(t) + sage: t2 = tetrahedron(color='red', opacity=0.5).rotateZ(t).rotate(v,2*pi/5) + sage: t3 = tetrahedron(color='green', opacity=0.5).rotateZ(t).rotate(v,4*pi/5) + sage: t4 = tetrahedron(color='yellow', opacity=0.5).rotateZ(t).rotate(v,6*pi/5) + sage: t5 = tetrahedron(color='orange', opacity=0.5).rotateZ(t).rotate(v,8*pi/5) sage: show(t1+t2+t3+t4+t5, frame=False, zoom=1.3) .. PLOT:: diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 9ba89595d70..41a1ad5de53 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1,10 +1,12 @@ +# sage.doctest: needs sage.symbolic r""" Plotting functions EXAMPLES:: sage: x, y = var('x y') - sage: W = plot3d(sin(pi*((x)^2 + (y)^2))/2, (x, -1, 1), (y, -1, 1), frame=False, color='purple', opacity=0.8) + sage: W = plot3d(sin(pi*((x)^2 + (y)^2))/2, (x, -1, 1), (y, -1, 1), + ....: frame=False, color='purple', opacity=0.8) sage: S = sphere((0, 0, 0), size=0.3, color='red', aspect_ratio=[1,1,1]) sage: show(W + S, figsize=8) @@ -30,7 +32,8 @@ sage: def f(x,y): ....: return math.sin(y^2 + x^2)/math.sqrt(x^2 + y^2 + 0.0001) - sage: P = plot3d(f, (-3, 3),(-3, 3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) + sage: P = plot3d(f, (-3, 3),(-3, 3), adaptive=True, + ....: color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sage: P.show() .. ONLY:: html @@ -121,11 +124,14 @@ def c(x, y): return float((x + y + x*y)/15) % 1 :: - sage: S += sphere((.45, -.1, .15), size=.1, color='white') + sphere((.51,-.1,.17), size=.05, color='black') - sage: S += sphere((.45, .1, .15), size=.1, color='white') + sphere((.51, .1,.17), size=.05, color='black') + sage: S += sphere((.45, -.1, .15), size=.1, color='white') + sage: S += sphere((.51,-.1,.17), size=.05, color='black') + sage: S += sphere((.45, .1, .15), size=.1, color='white') + sage: S += sphere((.51, .1,.17), size=.05, color='black') sage: S += sphere((.5, 0, -.2), size=.1, color='yellow') sage: def f(x,y): return math.exp(x/5)*math.cos(y) - sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, color=['red','yellow'], max_depth=10) + sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, + ....: color=['red','yellow'], max_depth=10) sage: cape_man = P.scale(.2) + S.translate(1, 0, 0) sage: cape_man.show(aspect_ratio=[1, 1, 1]) @@ -703,7 +709,8 @@ class SphericalElevation(_Coordinates): Plot a sin curve wrapped around the equator:: - sage: P1 = plot3d( (pi/12)*sin(8*theta), (r,0.99,1), (theta, 0, 2*pi), transformation=SE, plot_points=(10,200)) + sage: P1 = plot3d((pi/12)*sin(8*theta), (r,0.99,1), (theta, 0, 2*pi), + ....: transformation=SE, plot_points=(10,200)) sage: P2 = sphere(center=(0,0,0), size=1, color='red', opacity=0.3) sage: P1 + P2 Graphics3d Object @@ -736,10 +743,14 @@ class SphericalElevation(_Coordinates): sage: r, phi, theta = var('r phi theta') sage: SE = SphericalElevation('elevation', ['radius', 'azimuth']) sage: angles = [pi/18, pi/12, pi/6] - sage: P1 = [plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=SE, opacity=0.85, color='blue') for a in angles] + sage: P1 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=SE, + ....: opacity=0.85, color='blue') + ....: for a in angles] sage: S = Spherical('inclination', ['radius', 'azimuth']) - sage: P2 = [plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=S, opacity=0.85, color='red') for a in angles] + sage: P2 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=S, + ....: opacity=0.85, color='red') + ....: for a in angles] sage: show(sum(P1+P2), aspect_ratio=1) .. ONLY:: html @@ -1084,7 +1095,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: var('x,y') (x, y) - sage: plot3d(sin(x^2 + y^2),(x,-5,5),(y,-5,5), plot_points=200) + sage: plot3d(sin(x^2 + y^2), (x,-5,5), (y,-5,5), plot_points=200) Graphics3d Object .. ONLY:: html @@ -1152,8 +1163,10 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): Two wobby translucent planes:: sage: x,y = var('x,y') - sage: P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10), opacity=0.87, color='blue') - sage: Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10), opacity=0.3, color='red') + sage: P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10), + ....: opacity=0.87, color='blue') + sage: Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10), + ....: opacity=0.3, color='red') sage: P + Q Graphics3d Object diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index fe10e27f58f..d93d95cba57 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting 3D fields """ @@ -29,32 +30,33 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, INPUT: - - ``functions`` - a list of three functions, representing the x-, + - ``functions`` -- a list of three functions, representing the x-, y-, and z-coordinates of a vector - - ``xrange``, ``yrange``, and ``zrange`` - three tuples of the + - ``xrange``, ``yrange``, and ``zrange`` -- three tuples of the form (var, start, stop), giving the variables and ranges for each axis - - ``plot_points`` (default 5) - either a number or list of three + - ``plot_points`` -- (default 5) either a number or list of three numbers, specifying how many points to plot for each axis - - ``colors`` (default 'jet') - a color, list of colors (which are + - ``colors`` -- (default ``'jet'``) a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - - ``center_arrows`` (default False) - If True, draw the arrows + - ``center_arrows`` -- (default ``False``) If ``True``, draw the arrows centered on the points; otherwise, draw the arrows with the tail at the point - - any other keywords are passed on to the plot command for each arrow + - any other keywords are passed on to the :func:`plot` command for each arrow EXAMPLES: A 3d vector field:: - sage: x,y,z=var('x y z') - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi)) + sage: x,y,z = var('x y z') + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi)) Graphics3d Object .. PLOT:: @@ -64,7 +66,9 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with only a list of colors:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue']) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), + ....: colors=['red','green','blue']) Graphics3d Object .. PLOT:: @@ -74,7 +78,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with only one color:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors='red') + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), colors='red') Graphics3d Object .. PLOT:: @@ -84,7 +89,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with the same plot points for the three axes:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=4) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=4) Graphics3d Object .. PLOT:: @@ -94,7 +100,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with different number of plot points for each axis:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=[3,5,7]) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=[3,5,7]) Graphics3d Object .. PLOT:: @@ -104,7 +111,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with the arrows centered on the points:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), center_arrows=True) Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index 7c570b985f3..b140c463c29 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.plot """ Surfaces of revolution @@ -39,25 +40,25 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr INPUT: - - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple. + - ``curve`` -- A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple. - - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve. + - ``trange`` -- A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve. - - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved. + - ``phirange`` -- A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved. - - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis. + - ``parallel_axis`` -- A string (one of ``'x'``, ``'y'``, ``'z'``) that specifies the coordinate axis parallel to the revolution axis. - - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is: + - ``axis`` -- A 2-tuple that specifies the position of the revolution axis. If ``parallel_axis`` is: - - 'z' - then axis is the point in which the revolution axis intersects the `x y` plane. + - ``'z'`` -- then ``axis`` is the point in which the revolution axis intersects the `x` `y` plane. - - 'x' - then axis is the point in which the revolution axis intersects the `y z` plane. + - ``'x'`` -- then ``axis`` is the point in which the revolution axis intersects the `y` `z` plane. - - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane. + - ``'y'`` -- then ``axis`` is the point in which the revolution axis intersects the `x` `z` plane. - - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed. + - ``print_vector`` -- If ``True``, the parametrization of the surface of revolution will be printed. - - ``show_curve`` - If True, the curve will be displayed. + - ``show_curve`` -- If ``True``, the curve will be displayed. EXAMPLES: @@ -66,7 +67,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: f = u^2 - sage: revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(f, (u,0,2), + ....: show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -77,7 +79,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr If we move slightly the axis, we get a goblet-like surface:: - sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -90,9 +93,11 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: line = u sage: parabola = u^2 - sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x') - sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x') - sage: (sur1+sur2).show() + sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), + ....: show_curve=True, parallel_axis='x') + sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), + ....: show_curve=True, parallel_axis='x') + sage: (sur1 + sur2).show() .. PLOT:: @@ -109,7 +114,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: circle = (cos(u), sin(u)) - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -120,7 +126,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr An axis on `(0,y)` will produce a cylinder-like surface:: - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -131,7 +138,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr And any other axis will produce a torus-like surface:: - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -144,7 +152,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: curve = (u, cos(4*u), u^2) - sage: P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z',axis=(1,.2), opacity=0.5) + sage: P = revolution_plot3d(curve, (u,0,2), parallel_axis='z', axis=(1,.2), + ....: show_curve=True, opacity=0.5) sage: P.show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -158,7 +167,9 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: curve = (sin(3*u), .8*cos(4*u), cos(u)) - sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5).show(aspect_ratio=(1,1,1),frame=False) + sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), parallel_axis='z', + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1), + ....: frame=False) .. PLOT:: @@ -169,12 +180,13 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr One can also color the surface using a coloring function of two parameters and a colormap as follows. Note that the coloring - function must take values in the interval [0,1]. :: + function must take values in the interval `[0,1]`. :: sage: u, phi = var('u,phi') sage: def cf(u,phi): return sin(phi+u) ^ 2 sage: curve = (1+u^2/4, 0, u) - sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', + ....: color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -192,8 +204,8 @@ def cf(u, phi): return sin(phi+u) ** 2 sage: u, phi = var('u,phi') sage: def cf(u, phi): return float(2 * u / pi) % 1 sage: curve = (sin(u), 0, u) - sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis - ....: ='z', color=(colormaps.brg, cf)).show(aspect_ratio=1) + sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z', + ....: color=(colormaps.brg, cf)).show(aspect_ratio=1) .. PLOT:: diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 757a718a0df..9c820deda2b 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -12,8 +12,10 @@ EXAMPLES:: sage: from sage.plot.plot3d.shapes import * sage: S = Sphere(.5, color='yellow') sage: S += Cone(.5, .5, color='red').translate(0,0,.3) - sage: S += Sphere(.1, color='white').translate(.45,-.1,.15) + Sphere(.05, color='black').translate(.51,-.1,.17) - sage: S += Sphere(.1, color='white').translate(.45, .1,.15) + Sphere(.05, color='black').translate(.51, .1,.17) + sage: S += Sphere(.1, color='white').translate(.45,-.1,.15) + sage: S += Sphere(.05, color='black').translate(.51,-.1,.17) + sage: S += Sphere(.1, color='white').translate(.45, .1,.15) + sage: S += Sphere(.05, color='black').translate(.51, .1,.17) sage: S += Sphere(.1, color='yellow').translate(.5, 0, -.2) sage: S.show() sage: S.scale(1,1,2).show() @@ -78,7 +80,7 @@ def validate_frame_size(size): Traceback (most recent call last): ... ValueError: each box dimension must be nonnegative - sage: validate_frame_size([sqrt(-1),3,2]) + sage: validate_frame_size([sqrt(-1),3,2]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: each box dimension must coerce to a float @@ -125,7 +127,8 @@ class Box(IndexFaceSet): A stack of boxes:: - sage: show(sum([Box([2,3,1], color="red").translate((0,0,6*i)) for i in [0..3]])) + sage: show(sum(Box([2,3,1], color="red").translate((0,0,6*i)) + ....: for i in [0..3])) .. PLOT:: @@ -135,8 +138,10 @@ class Box(IndexFaceSet): A sinusoidal stack of multicolored boxes:: - sage: B = sum([Box([2,4,1/4], color=(i/4,i/5,1)).translate((sin(i),0,5-i)) for i in [0..20]]) - sage: show(B, figsize=6) + sage: B = sum(Box([2,4,1/4], # needs sage.symbolic + ....: color=(i/4,i/5,1)).translate((sin(i),0,5-i)) + ....: for i in [0..20]) + sage: show(B, figsize=6) # needs sage.symbolic .. PLOT:: @@ -265,7 +270,8 @@ cdef class Cone(ParametricSurface): EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cone - sage: c = Cone(3/2, 1, color='red') + Cone(1, 2, color='yellow').translate(3, 0, 0) + sage: c = Cone(3/2, 1, color='red') + sage: c += Cone(1, 2, color='yellow').translate(3, 0, 0) sage: c.show(aspect_ratio=1) .. PLOT:: @@ -286,7 +292,8 @@ cdef class Cone(ParametricSurface): A spiky plot of the sine function:: - sage: sum(Cone(.1, sin(n), color='yellow').translate(n, sin(n), 0) for n in [0..10, step=.1]) + sage: sum(Cone(.1, sin(n), color='yellow').translate(n, sin(n), 0) # needs sage.symbolic + ....: for n in [0..10, step=.1]) Graphics3d Object .. PLOT:: @@ -296,9 +303,11 @@ cdef class Cone(ParametricSurface): A Christmas tree:: - sage: T = sum(Cone(exp(-n/5), 4/3*exp(-n/5), color=(0, .5, 0)).translate(0, 0, -3*exp(-n/5)) for n in [1..7]) - sage: T += Cone(1/8, 1, color='brown').translate(0, 0, -3) - sage: T.show(aspect_ratio=1, frame=False) + sage: T = sum(Cone(exp(-n/5), 4/3*exp(-n/5), # needs sage.symbolic + ....: color=(0, .5, 0)).translate(0, 0, -3*exp(-n/5)) + ....: for n in [1..7]) + sage: T += Cone(1/8, 1, color='brown').translate(0, 0, -3) # needs sage.symbolic + sage: T.show(aspect_ratio=1, frame=False) # needs sage.symbolic .. PLOT:: @@ -376,12 +385,13 @@ cdef class Cylinder(ParametricSurface): - ``closed`` -- whether or not to include the ends (default ``True``) - - ``**kwds`` -- passed to the ParametricSurface constructor + - ``**kwds`` -- passed to the :class:`ParametricSurface` constructor EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cylinder - sage: c = Cylinder(3/2, 1, color='red') + Cylinder(1, 2, color='yellow').translate(3, 0, 0) + sage: c = Cylinder(3/2, 1, color='red') + sage: c += Cylinder(1, 2, color='yellow').translate(3, 0, 0) sage: c.show(aspect_ratio=1) .. PLOT:: @@ -402,8 +412,10 @@ cdef class Cylinder(ParametricSurface): Some gears:: + sage: # needs sage.symbolic sage: G = Cylinder(1, .5) + Cylinder(.25, 3).translate(0, 0, -3) - sage: G += sum(Cylinder(.2, 1).translate(cos(2*pi*n/9), sin(2*pi*n/9), 0) for n in [1..9]) + sage: G += sum(Cylinder(.2, 1).translate(cos(2*pi*n/9), sin(2*pi*n/9), 0) + ....: for n in [1..9]) sage: G += G.translate(2.3, 0, -.5) sage: G += G.translate(3.5, 2, -1) sage: G.show(aspect_ratio=1, frame=False) @@ -537,7 +549,8 @@ draw %s width %s {%s %s %s} {%s %s %s}\n%s sage: from sage.plot.plot3d.transform import Transformation sage: Cylinder(1, 5).get_endpoints() ((0, 0, 0), (0, 0, 5.0)) - sage: Cylinder(1, 5).get_endpoints(Transformation(trans=(1,2,3), scale=(2,2,2))) + sage: Cylinder(1, 5).get_endpoints(Transformation(trans=(1,2,3), + ....: scale=(2,2,2))) ((1.0, 2.0, 3.0), (1.0, 2.0, 13.0)) """ if transform is None: @@ -553,7 +566,8 @@ draw %s width %s {%s %s %s} {%s %s %s}\n%s sage: from sage.plot.plot3d.transform import Transformation sage: Cylinder(3, 1).get_radius() 3.0 - sage: Cylinder(3, 1).get_radius(Transformation(trans=(1,2,3), scale=(2,2,2))) + sage: Cylinder(3, 1).get_radius(Transformation(trans=(1,2,3), + ....: scale=(2,2,2))) 6.0 """ if transform is None: @@ -670,12 +684,12 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * INPUT: - - start -- (x,y,z) point; the starting point of the arrow - - end -- (x,y,z) point; the end point - - width -- (default: 1); how wide the arrow is - - radius -- (default: width/50.0) the radius of the arrow - - head_radius -- (default: 3*radius); radius of arrow head - - head_len -- (default: 3*head_radius); len of arrow head + - ``start`` -- (x,y,z) point; the starting point of the arrow + - ``end`` -- (x,y,z) point; the end point + - ``width`` -- (default: 1); how wide the arrow is + - ``radius`` -- (default: ``width/50.0``) the radius of the arrow + - ``head_radius`` -- (default: ``3*radius``); radius of arrow head + - ``head_len`` -- (default: ``3*head_radius``); len of arrow head EXAMPLES: @@ -708,7 +722,8 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * A fat arrow head:: - sage: arrow3d((2,1,0), (1,1,1), color='green', head_radius=0.3, aspect_ratio=[1,1,1]) + sage: arrow3d((2,1,0), (1,1,1), color='green', head_radius=0.3, + ....: aspect_ratio=[1,1,1]) Graphics3d Object .. PLOT:: @@ -717,7 +732,8 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * Many arrows arranged in a circle (flying spears?):: - sage: sum([arrow3d((cos(t),sin(t),0),(cos(t),sin(t),1)) for t in [0,0.3,..,2*pi]]) + sage: sum(arrow3d((cos(t),sin(t),0), (cos(t),sin(t),1)) # needs sage.symbolic + ....: for t in [0,0.3,..,2*pi]) Graphics3d Object .. PLOT:: @@ -730,7 +746,7 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * sphinx_plot(G) Change the width of the arrow. (Note: for an arrow that scales with zoom, please consider - the ``line3d`` function with the option ``arrow_head=True``):: + the :func:`line3d` function with the option ``arrow_head=True``):: sage: arrow3d((0,0,0), (1,1,1), width=1) Graphics3d Object @@ -804,7 +820,7 @@ cdef class Sphere(ParametricSurface): from sage.plot.plot3d.shapes import Sphere sphinx_plot(Sphere(3)) - Plot with aspect_ratio=1 to see it unsquashed:: + Plot with ``aspect_ratio=1`` to see it unsquashed:: sage: S = Sphere(3, color='blue') + Sphere(2, color='red').translate(0,3,0) sage: S.show(aspect_ratio=1) @@ -970,8 +986,8 @@ cdef class Torus(ParametricSurface): """ INPUT: - - R -- (default: 1) outer radius - - r -- (default: .3) inner radius + - ``R`` -- (default: ``1``) outer radius + - ``r`` -- (default: ``.3``) inner radius OUTPUT: @@ -998,7 +1014,8 @@ cdef class Torus(ParametricSurface): A rubberband ball:: - sage: show(sum([Torus(1, .03, color=(1, t/30.0, 0)).rotate((1,1,1),t) for t in range(30)])) + sage: show(sum(Torus(1, .03, color=(1, t/30.0, 0)).rotate((1,1,1), t) + ....: for t in range(30))) .. PLOT:: @@ -1007,8 +1024,12 @@ cdef class Torus(ParametricSurface): Mmm... doughnuts:: - sage: D = Torus(1, .4, color=(.5, .3, .2)) + Torus(1, .3, color='yellow').translate(0, 0, .15) - sage: G = sum(D.translate(RDF.random_element(-.2, .2), RDF.random_element(-.2, .2), .8*t) for t in range(10)) + sage: D = Torus(1, .4, color=(.5, .3, .2)) + sage: D += Torus(1, .3, color='yellow').translate(0, 0, .15) + sage: G = sum(D.translate(RDF.random_element(-.2, .2), + ....: RDF.random_element(-.2, .2), + ....: .8*t) + ....: for t in range(10)) sage: G.show(aspect_ratio=1, frame=False) .. PLOT:: diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index ae879508511..18e37bbfefe 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -64,8 +64,8 @@ def line3d(points, thickness=1, radius=None, arrow_head=False, **kwds): - ``color`` -- a string (``"red"``, ``"green"`` etc) or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - - ``opacity`` -- (default: 1) if less than 1 then is - transparent + - ``opacity`` -- (default: 1) if less than 1 then is + transparent EXAMPLES: @@ -117,6 +117,7 @@ def line3d(points, thickness=1, radius=None, arrow_head=False, **kwds): ....: (-sqrt(2.)/3,-sqrt(6.)/3,-1./3), (2*sqrt(2.)/3,0,-1./3)],\ ....: color=col, thickness=10, aspect_ratio=[1,1,1]) + sage: from math import pi sage: v = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) sage: t = acos(sqrt(5.)/3)/2 sage: t1 = tetra('blue').rotateZ(t) @@ -160,7 +161,7 @@ def tetra(col): This function should work for anything than can be turned into a list, such as iterators and such (see :trac:`10478`):: - sage: line3d(iter([(0,0,0), (sqrt(3), 2, 4)])) + sage: line3d(iter([(0,0,0), (sqrt(3), 2, 4)])) # needs sage.symbolic Graphics3d Object sage: line3d((x, x^2, x^3) for x in range(5)) Graphics3d Object @@ -210,13 +211,13 @@ def bezier3d(path, **options): - ``thickness`` -- (default: 2) - - ``color`` -- a string (``"red"``, ``"green"`` etc) - or a tuple (r, g, b) with r, g, b numbers between 0 and 1 + - ``color`` -- a string (``"red"``, ``"green"`` etc) + or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - ``opacity`` -- (default: 1) if less than 1 then is transparent - - ``aspect_ratio`` -- (default:[1,1,1]) + - ``aspect_ratio`` -- (default: [1,1,1]) The path is a list of curves, and each curve is a list of points. Each point is a tuple (x,y,z). @@ -248,9 +249,9 @@ def bezier3d(path, **options): EXAMPLES:: - sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)],[(.5,1,.2),(1,.5,0)],[(.7,.2,.5)]] - sage: b = bezier3d(path, color='green') - sage: b + sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)], + ....: [(.5,1,.2),(1,.5,0)], [(.7,.2,.5)]] + sage: b = bezier3d(path, color='green'); b # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -261,8 +262,7 @@ def bezier3d(path, **options): To construct a simple curve, create a list containing a single list:: sage: path = [[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]] - sage: curve = bezier3d(path, thickness=5, color='blue') - sage: curve + sage: curve = bezier3d(path, thickness=5, color='blue'); curve # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -274,13 +274,16 @@ def bezier3d(path, **options): Check for :trac:`31640`:: - sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]] - sage: bp = bezier_path(p2d) - sage: bp.plot3d() + sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], + ....: [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]] + sage: bp = bezier_path(p2d) # needs sage.symbolic + sage: bp.plot3d() # needs sage.symbolic Graphics3d Object - sage: p3d = p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]] - sage: bezier3d(p3d) + sage: p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], + ....: [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], + ....: [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]] + sage: bezier3d(p3d) # needs sage.symbolic Graphics3d Object """ from . import parametric_plot3d as P3D @@ -336,7 +339,8 @@ def polygon3d(points, **options): Some modern art -- a random polygon:: - sage: v = [(randrange(-5,5), randrange(-5,5), randrange(-5, 5)) for _ in range(10)] + sage: v = [(randrange(-5,5), randrange(-5,5), randrange(-5, 5)) + ....: for _ in range(10)] sage: polygon3d(v) Graphics3d Object @@ -347,7 +351,8 @@ def polygon3d(points, **options): A bent transparent green triangle:: - sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], color=(0,1,0), opacity=0.7) + sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], + ....: color=(0,1,0), opacity=0.7) Graphics3d Object .. PLOT:: @@ -356,7 +361,8 @@ def polygon3d(points, **options): This is the same as using ``alpha=0.7``:: - sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], color=(0,1,0), alpha=0.7) + sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], + ....: color=(0,1,0), alpha=0.7) Graphics3d Object .. PLOT:: @@ -373,7 +379,7 @@ def polygons3d(faces, points, **options): """ Draw the union of several polygons in 3d. - Useful to plot a polyhedron as just one ``IndexFaceSet``. + Useful to plot a polyhedron as just one :class:`IndexFaceSet`. INPUT: @@ -426,8 +432,8 @@ def frame3d(lower_left, upper_right, **kwds): This is usually used for making an actual plot:: - sage: y = var('y') - sage: plot3d(sin(x^2+y^2),(x,0,pi),(y,0,pi)) + sage: y = var('y') # needs sage.symbolic + sage: plot3d(sin(x^2+y^2), (x,0,pi), (y,0,pi)) # needs sage.symbolic Graphics3d Object """ x0, y0, z0 = lower_left @@ -483,10 +489,11 @@ def frame_labels(lower_left, upper_right, This is usually used for making an actual plot:: + sage: # needs sage.symbolic sage: y = var('y') - sage: P = plot3d(sin(x^2+y^2),(x,0,pi),(y,0,pi)) + sage: P = plot3d(sin(x^2+y^2), (x,0,pi), (y,0,pi)) sage: a,b = P._rescale_for_frame_aspect_ratio_and_zoom(1.0,[1,1,1],1) - sage: F = frame_labels(a,b,*P._box_for_aspect_ratio("automatic",a,b)) + sage: F = frame_labels(a, b, *P._box_for_aspect_ratio("automatic",a,b)) sage: F.jmol_repr(F.default_render_params())[0] [['select atomno = 1', 'color atom [76,76,76]', 'label "0.0"']] @@ -749,7 +756,7 @@ def sphere(center=(0, 0, 0), size=1, **kwds): Spheres of radii 1 and 2 one stuck into the other:: sage: sphere(color='orange') + sphere(color=(0,0,0.3), - ....: center=(0,0,-2),size=2,opacity=0.9) + ....: center=(0,0,-2), size=2, opacity=0.9) Graphics3d Object .. PLOT:: @@ -758,9 +765,9 @@ def sphere(center=(0, 0, 0), size=1, **kwds): We draw a transparent sphere on a saddle. :: - sage: u,v = var('u v') - sage: saddle = plot3d(u^2 - v^2, (u,-2,2), (v,-2,2)) - sage: sphere((0,0,1), color='red', opacity=0.5, aspect_ratio=[1,1,1]) + saddle + sage: u,v = var('u v') # needs sage.symbolic + sage: saddle = plot3d(u^2 - v^2, (u,-2,2), (v,-2,2)) # needs sage.symbolic + sage: sphere((0,0,1), color='red', opacity=0.5, aspect_ratio=[1,1,1]) + saddle # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1048,7 +1055,8 @@ class Line(PrimitiveObject): EXAMPLES:: sage: from sage.plot.plot3d.shapes2 import Line - sage: Line([(i*math.sin(i), i*math.cos(i), i/3) for i in range(30)], arrow_head=True) + sage: Line([(i*math.sin(i), i*math.cos(i), i/3) for i in range(30)], + ....: arrow_head=True) Graphics3d Object Smooth angles less than 90 degrees:: @@ -1060,10 +1068,10 @@ class Line(PrimitiveObject): sage: N = 11 sage: c = 0.4 - sage: sum([Line([(i,1,0), (i,0,0), (i,cos(2*pi*i/N), sin(2*pi*i/N))], - ....: corner_cutoff=c, - ....: color='red' if -cos(2*pi*i/N)<=c else 'blue') - ....: for i in range(N+1)]) + sage: sum(Line([(i,1,0), (i,0,0), (i,cos(2*pi*i/N), sin(2*pi*i/N))], # needs sage.symbolic + ....: corner_cutoff=c, + ....: color='red' if -cos(2*pi*i/N)<=c else 'blue') + ....: for i in range(N+1)) Graphics3d Object """ def __init__(self, points, thickness=5, corner_cutoff=0.5, @@ -1099,10 +1107,10 @@ def bounding_box(self): TESTS:: sage: from sage.plot.plot3d.shapes2 import Line - sage: L = Line([(i,i^2-1,-2*ln(i)) for i in [10,20,30]]) - sage: L.bounding_box() + sage: L = Line([(i, i^2 - 1, -2*ln(i)) for i in [10,20,30]]) # needs sage.symbolic + sage: L.bounding_box() # needs sage.symbolic ((10.0, 99.0, -6.802394763324311), - (30.0, 899.0, -4.605170185988092)) + (30.0, 899.0, -4.605170185988092)) """ try: return self.__bounding_box @@ -1117,8 +1125,9 @@ def tachyon_repr(self, render_params): TESTS:: - sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.tachyon_repr(L.default_render_params())[0] + sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.tachyon_repr(L.default_render_params())[0] # needs sage.symbolic 'FCylinder base 1.0 0.0 0.0 apex 0.9999500004166653 0.009999833334166664 0.0001 rad 0.005 texture...' """ T = render_params.transform @@ -1149,8 +1158,9 @@ def obj_repr(self, render_params): TESTS:: sage: from sage.plot.plot3d.shapes2 import Line - sage: L = Line([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.obj_repr(L.default_render_params())[0][0][0][2][:3] + sage: L = Line([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.obj_repr(L.default_render_params())[0][0][0][2][:3] # needs sage.symbolic ['v 0.99995 0.00999983 0.0001', 'v 1.02376 0.010195 -0.00750607', 'v 1.00007 0.0102504 -0.0248984'] @@ -1172,8 +1182,9 @@ def jmol_repr(self, render_params): TESTS:: - sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.jmol_repr(L.default_render_params())[0][:42] + sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.jmol_repr(L.default_render_params())[0][:42] # needs sage.symbolic 'draw line_1 diameter 1 curve {1.0 0.0 0.0}' """ T = render_params.transform @@ -1410,15 +1421,15 @@ def point3d(v, size=5, **kwds): - ``size`` -- (default: 5) size of the point (or points) - - ``color`` -- a string (``"red"``, ``"green"`` etc) - or a tuple (r, g, b) with r, g, b numbers between 0 and 1 + - ``color`` -- a string (``"red"``, ``"green"`` etc) + or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - ``opacity`` -- (default: 1) if less than 1 then is transparent EXAMPLES:: - sage: sum([point3d((i,i^2,i^3), size=5) for i in range(10)]) + sage: sum(point3d((i,i^2,i^3), size=5) for i in range(10)) Graphics3d Object .. PLOT:: @@ -1431,15 +1442,15 @@ def point3d(v, size=5, **kwds): sage: print(point(vector((2,3,4)))) Graphics3d Object - sage: c = polytopes.hypercube(3) - sage: v = c.vertices()[0]; v + sage: c = polytopes.hypercube(3) # needs sage.geometry.polyhedron + sage: v = c.vertices()[0]; v # needs sage.geometry.polyhedron A vertex at (1, -1, -1) - sage: print(point(v)) + sage: print(point(v)) # needs sage.geometry.polyhedron Graphics3d Object We check to make sure the options work:: - sage: point3d((4,3,2),size=20,color='red',opacity=.5) + sage: point3d((4,3,2), size=20, color='red', opacity=.5) Graphics3d Object .. PLOT:: @@ -1469,7 +1480,7 @@ def point3d(v, size=5, **kwds): We check that iterators of points are accepted (:trac:`13890`):: - sage: point3d(iter([(1,1,2),(2,3,4),(3,5,8)]),size=20,color='red') + sage: point3d(iter([(1,1,2),(2,3,4),(3,5,8)]), size=20, color='red') Graphics3d Object TESTS:: diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index 88c8eba2d51..9c5719f894e 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -34,7 +34,7 @@ flexibility. For example, here we directly use Tachyon to draw 3 spheres on the coordinate axes:: - sage: t = Tachyon(xres=500,yres=500, camera_position=(2,0,0)) + sage: t = Tachyon(xres=500, yres=500, camera_position=(2,0,0)) sage: t.light((4,3,2), 0.2, (1,1,1)) sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) sage: t.texture('t3', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0)) @@ -46,11 +46,12 @@ For scenes with many reflections it is helpful to increase the raydepth option, and turn on antialiasing. The following scene is an extreme case with many reflections between four cotangent spheres:: - sage: t = Tachyon(camera_position=(0,-4,1), xres = 800, yres = 600, raydepth = 12, aspectratio=.75, antialiasing = 4) + sage: t = Tachyon(camera_position=(0,-4,1), xres=800, yres=600, raydepth=12, + ....: aspectratio=.75, antialiasing=4) sage: t.light((0.02,0.012,0.001), 0.01, (1,0,0)) sage: t.light((0,0,10), 0.01, (0,0,1)) - sage: t.texture('s', color = (.8,1,1), opacity = .9, specular = .95, diffuse = .3, ambient = 0.05) - sage: t.texture('p', color = (0,0,1), opacity = 1, specular = .2) + sage: t.texture('s', color=(.8,1,1), opacity=.9, specular=.95, diffuse=.3, ambient=0.05) + sage: t.texture('p', color=(0,0,1), opacity=1, specular=.2) sage: t.sphere((-1,-.57735,-0.7071),1,'s') sage: t.sphere((1,-.57735,-0.7071),1,'s') sage: t.sphere((0,1.15465,-0.7071),1,'s') @@ -92,7 +93,7 @@ Finally there is the ``projection='perspective_dof'`` option. :: sage: T = Tachyon(xres=800, antialiasing=4, raydepth=10, - ....: projection='perspective_dof', focallength='1.0', aperture='.0025') + ....: projection='perspective_dof', focallength='1.0', aperture='.0025') sage: T.light((0,5,7), 1.0, (1,1,1)) sage: T.texture('t1', opacity=1, specular=.3) sage: T.texture('t2', opacity=1, specular=.3, color=(0,0,1)) @@ -113,7 +114,8 @@ cylinders or spheres. In this example an image is created and then used to tile the plane:: - sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), + ....: projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) sage: T.texture('t1',color=(0,0,1)) sage: for ed in cedges: ....: T.fcylinder(ed[0], ed[1], .05, 't1') @@ -121,15 +123,20 @@ sage: fname_png = tmp_filename(ext='.png') sage: fname_ppm = tmp_filename(ext='.ppm') sage: T.save(fname_png) - sage: r2 = os.system('convert '+fname_png+' '+fname_ppm) # optional -- ImageMagick - - sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) # optional -- ImageMagick - sage: T.texture('t1', color=(1,0,0), specular=.9) # optional -- ImageMagick - sage: T.texture('p1', color=(1,1,1), opacity=.1, imagefile=fname_ppm, texfunc=9) # optional -- ImageMagick - sage: T.sphere((0,0,0), .5, 't1') # optional -- ImageMagick - sage: T.plane((0,0,-1), (0,0,1), 'p1') # optional -- ImageMagick - sage: T.light((-4,-4,4), .1, (1,1,1)) # optional -- ImageMagick - sage: T.show() # optional -- ImageMagick + sage: r2 = os.system('convert '+fname_png+' '+fname_ppm) # optional -- ImageMagick + + sage: # optional - imagemagick + sage: T = Tachyon(xres=800, yres=600, + ....: camera_position=(-2.0,-.1,.3), + ....: projection='fisheye', + ....: frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T.texture('t1', color=(1,0,0), specular=.9) + sage: T.texture('p1', color=(1,1,1), opacity=.1, + ....: imagefile=fname_ppm, texfunc=9) + sage: T.sphere((0,0,0), .5, 't1') + sage: T.plane((0,0,-1), (0,0,1), 'p1') + sage: T.light((-4,-4,4), .1, (1,1,1)) + sage: T.show() AUTHOR: @@ -172,24 +179,24 @@ class Tachyon(WithEqualityById, SageObject): INPUT: - - ``xres`` - (default 350) - - ``yres`` - (default 350) - - ``zoom`` - (default 1.0) - - ``antialiasing`` - (default ``False``) - - ``aspectratio`` - (default 1.0) - - ``raydepth`` - (default 8) - - ``camera_position`` - (default (-3, 0, 0)) - - ``updir`` - (default (0, 0, 1)) - - ``look_at`` - (default (0,0,0)) - - ``viewdir`` - (default ``None``), otherwise list of three numbers - - ``projection`` - ``'PERSPECTIVE'`` (default), ``'perspective_dof'`` + - ``xres`` -- (default 350) + - ``yres`` -- (default 350) + - ``zoom`` -- (default 1.0) + - ``antialiasing`` -- (default ``False``) + - ``aspectratio`` -- (default 1.0) + - ``raydepth`` -- (default 8) + - ``camera_position`` -- (default (-3, 0, 0)) + - ``updir`` -- (default (0, 0, 1)) + - ``look_at`` -- (default (0,0,0)) + - ``viewdir`` -- (default ``None``), otherwise list of three numbers + - ``projection`` -- ``'PERSPECTIVE'`` (default), ``'perspective_dof'`` or ``'fisheye'``. - - ``frustum`` - (default ''), otherwise list of four numbers. Only - used with projection='fisheye'. - - ``focallength`` - (default ''), otherwise a number. Only used - with projection='perspective_dof'. - - ``aperture`` - (default ''), otherwise a number. Only used - with projection='perspective_dof'. + - ``frustum`` -- (default ``''``), otherwise list of four numbers. Only + used with ``projection='fisheye'``. + - ``focallength`` -- (default ''), otherwise a number. Only used + with ``projection='perspective_dof'``. + - ``aperture`` -- (default ''), otherwise a number. Only used + with ``projection='perspective_dof'``. OUTPUT: A Tachyon 3d scene. @@ -205,7 +212,7 @@ class Tachyon(WithEqualityById, SageObject): sage: t.light((4,3,2), 0.2, (1,1,1)) sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1.0,0,0)) sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.3, opacity=1.0, color=(0,1.0,0)) - sage: t.texture('t2', ambient=0.2,diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0)) + sage: t.texture('t2', ambient=0.2, diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0)) sage: k=0 sage: for i in srange(-1,1,0.05): ....: k += 1 @@ -252,25 +259,28 @@ class Tachyon(WithEqualityById, SageObject): Points on an elliptic curve, their height indicated by their height above the axis:: + sage: # needs sage.schemes sage: t = Tachyon(camera_position=(5,2,2), look_at=(0,1,0)) sage: t.light((10,3,2), 0.2, (1,1,1)) sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0)) sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,0,1)) - sage: E = EllipticCurve('37a') - sage: P = E([0,0]) - sage: Q = P + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E([0,0]) # needs sage.schemes + sage: Q = P # needs sage.schemes sage: n = 100 - sage: for i in range(n): # increase 20 for a better plot + sage: for i in range(n): # increase 20 for a better plot # needs sage.schemes ....: Q = Q + P ....: t.sphere((Q[1], Q[0], ZZ(i)/n), 0.1, 't%s'%(i%3)) - sage: t.show() + sage: t.show() # needs sage.schemes A beautiful picture of rational points on a rank 1 elliptic curve. :: - sage: t = Tachyon(xres=1000, yres=800, camera_position=(2,7,4), look_at=(2,0,0), raydepth=4) + sage: # needs sage.schemes + sage: t = Tachyon(xres=1000, yres=800, camera_position=(2,7,4), + ....: look_at=(2,0,0), raydepth=4) sage: t.light((10,3,2), 1, (1,1,1)) sage: t.light((10,-3,2), 1, (1,1,1)) sage: t.texture('black', color=(0,0,0)) @@ -279,26 +289,27 @@ class Tachyon(WithEqualityById, SageObject): sage: t.plane((0,0,0),(0,0,1),'grey') sage: t.cylinder((0,0,0),(1,0,0),.01,'black') sage: t.cylinder((0,0,0),(0,1,0),.01,'black') - sage: E = EllipticCurve('37a') - sage: P = E([0,0]) - sage: Q = P + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E([0,0]) # needs sage.schemes + sage: Q = P # needs sage.schemes sage: n = 100 - sage: for i in range(n): + sage: for i in range(n): # needs sage.schemes ....: Q = Q + P ....: c = i/n + .1 ....: t.texture('r%s'%i,color=(float(i/n),0,0)) ....: t.sphere((Q[0], -Q[1], .01), .04, 'r%s'%i) - sage: t.show() # long time, e.g., 10-20 seconds + sage: t.show() # long time # needs sage.schemes A beautiful spiral. :: - sage: t = Tachyon(xres=800,yres=800, camera_position=(2,5,2), look_at=(2.5,0,0)) + sage: t = Tachyon(xres=800, yres=800, camera_position=(2,5,2), look_at=(2.5,0,0)) sage: t.light((0,0,100), 1, (1,1,1)) - sage: t.texture('r', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) + sage: t.texture('r', ambient=0.1, diffuse=0.9, specular=0.5, + ....: opacity=1.0, color=(1,0,0)) sage: for i in srange(0,50,0.1): - ....: t.sphere((i/10,sin(i),cos(i)), 0.05, 'r') + ....: t.sphere((i/10.0,sin(i),cos(i)), 0.05, 'r') sage: t.texture('white', color=(1,1,1), opacity=1, specular=1, diffuse=1) sage: t.plane((0,0,-100), (0,0,-100), 'white') sage: t.show() @@ -314,15 +325,15 @@ class Tachyon(WithEqualityById, SageObject): Use of a fisheye lens perspective. :: - sage: T = Tachyon(xres=800, yres=600, camera_position=(-1.5,-1.5,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T = Tachyon(xres=800, yres=600, camera_position=(-1.5,-1.5,.3), + ....: projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) sage: T.texture('t1', color=(0,0,1)) sage: cedges = [[[1, 1, 1], [-1, 1, 1]], [[1, 1, 1], [1, -1, 1]], - ....: [[1, 1, 1], [1, 1, -1]], [[-1, 1, 1], [-1, -1, 1]], [[-1, 1, 1], - ....: [-1, 1, -1]], [[1, -1, 1], [-1, -1, 1]], [[1, -1, 1], - ....: [1, -1, -1]], - ....: [[-1, -1, 1], [-1, -1, -1]], [[1, 1, -1], [-1, 1, -1]], - ....: [[1, 1, -1], [1, -1, -1]], [[-1, 1, -1], [-1, -1, -1]], - ....: [[1, -1, -1], [-1, -1, -1]]] + ....: [[1, 1, 1], [1, 1, -1]], [[-1, 1, 1], [-1, -1, 1]], + ....: [[-1, 1, 1], [-1, 1, -1]], [[1, -1, 1], [-1, -1, 1]], + ....: [[1, -1, 1], [1, -1, -1]], [[-1, -1, 1], [-1, -1, -1]], + ....: [[1, 1, -1], [-1, 1, -1]], [[1, 1, -1], [1, -1, -1]], + ....: [[-1, 1, -1], [-1, -1, -1]], [[1, -1, -1], [-1, -1, -1]]] sage: for ed in cedges: ....: T.fcylinder(ed[0], ed[1], .05, 't1') sage: T.light((-4,-4,4), .1, (1,1,1)) @@ -331,7 +342,8 @@ class Tachyon(WithEqualityById, SageObject): Use of the ``projection='perspective_dof'`` option. This may not be implemented correctly. :: - sage: T = Tachyon(xres=800,antialiasing=4, raydepth=10, projection='perspective_dof', focallength='1.0', aperture='.0025') + sage: T = Tachyon(xres=800, antialiasing=4, raydepth=10, + ....: projection='perspective_dof', focallength='1.0', aperture='.0025') sage: T.light((0,5,7), 1.0, (1,1,1)) sage: T.texture('t1', opacity=1, specular=.3) sage: T.texture('t2', opacity=1, specular=.3, color=(0,0,1)) @@ -544,14 +556,17 @@ def show(self, **kwds): :: - sage: h = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: h = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: h.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: h.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: h.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: h.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: h.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: from sage.misc.verbose import set_verbose, get_verbose sage: set_verbose(0) - sage: h.show() + sage: h.show() # needs sage.symbolic This second example, using a "medium" global verbosity setting of 1, displays some extra technical information then @@ -559,13 +574,16 @@ def show(self, **kwds): :: - sage: s = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: s = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: s.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: s.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: s.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: s.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: s.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: set_verbose(1) - sage: s.show() + sage: s.show() # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -579,14 +597,17 @@ def show(self, **kwds): :: sage: set_verbose(0) - sage: d = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: d = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: d.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: d.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: d.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: d.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: d.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: get_verbose() 0 - sage: d.show(verbose=2) + sage: d.show(verbose=2) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -604,7 +625,7 @@ def _res(self): EXAMPLES:: - sage: t = Tachyon(xres = 300, yres = 700) + sage: t = Tachyon(xres=300, yres=700) sage: t._res() '\nresolution 300 700\n' """ @@ -617,7 +638,7 @@ def _camera(self): EXAMPLES:: - sage: t = Tachyon(raydepth = 16, zoom = 2, antialiasing = True) + sage: t = Tachyon(raydepth=16, zoom=2, antialiasing=True) sage: t._camera().split()[3:10] ['zoom', '2.0', 'aspectratio', '1.0', 'antialiasing', '1', 'raydepth'] """ @@ -764,7 +785,8 @@ def texture(self, name, ambient=0.2, diffuse=0.8, sage: t = Tachyon(camera_position=(2,5,4), look_at=(2,0,0), raydepth=6) sage: t.light((10,3,4), 1, (1,1,1)) - sage: t.texture('mirror', ambient=0.05, diffuse=0.05, specular=.9, opacity=0.9, color=(.8,.8,.8)) + sage: t.texture('mirror', ambient=0.05, diffuse=0.05, specular=.9, + ....: opacity=0.9, color=(.8,.8,.8)) sage: t.texture('grey', color=(.8,.8,.8), texfunc=3) sage: t.plane((0,0,0),(0,0,1),'grey') sage: t.sphere((4,-1,1), 1, 'mirror') @@ -987,12 +1009,15 @@ def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, Flat Triangles:: - sage: t = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: t = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture - sage: t.show(verbose=1) + sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: t.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture + sage: t.show(verbose=1) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -1000,13 +1025,16 @@ def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, Plotting with Smooth Triangles (requires explicit gradient function):: - sage: t = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: t = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: def g(x,y): return ( float(y*cos(x*y)), float(x*cos(x*y)), 1 ) - sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, grad_f = g) # increase min_depth for better picture - sage: t.show(verbose=1) + sage: def g(x,y): return (float(y*cos(x*y)), float(x*cos(x*y)), 1) + sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: t.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: grad_f=g) # increase min_depth for better picture + sage: t.show(verbose=1) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -1646,7 +1674,6 @@ def str(self): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q.str()[9:69] @@ -1662,7 +1689,6 @@ def __init__(self, f, t_0, t_f, tex, r=.1, cylinders=True, EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q._e_rel @@ -1690,7 +1716,6 @@ def _plot_step(self, depth, t_0, t_f, f_0, f_f): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q._plot_step(8,0,1,[0,0,0],[1,1,1]) @@ -1724,7 +1749,6 @@ def tol(self, est, val): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q.tol([0,0,0],[1,0,0]) diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index b57af986b59..28d509fe156 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting fields """ diff --git a/src/sage/plot/point.py b/src/sage/plot/point.py index 10a19a5b5e4..2bbe8cef07a 100644 --- a/src/sage/plot/point.py +++ b/src/sage/plot/point.py @@ -4,10 +4,12 @@ TESTS:: - sage: E = EllipticCurve('37a') - sage: P = E(0,0) - sage: def get_points(n): return sum([point(list(i*P)[:2], size=3) for i in range(-n,n) if i != 0 and (i*P)[0] < 3]) - sage: sum([get_points(15*n).plot3d(z=n) for n in range(1,10)]) + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E(0,0) # needs sage.schemes + sage: def get_points(n): + ....: return sum(point(list(i*P)[:2], size=3) + ....: for i in range(-n,n) if i != 0 and (i*P)[0] < 3) + sage: sum(get_points(15*n).plot3d(z=n) for n in range(1,10)) # needs sage.schemes Graphics3d Object """ @@ -40,15 +42,15 @@ class Point(GraphicPrimitive_xydata): INPUT: - - xdata -- list of x values for points in Point object + - ``xdata`` -- list of x values for points in Point object - - ydata -- list of y values for points in Point object + - ``ydata`` -- list of y values for points in Point object - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: - Note this should normally be used indirectly via ``point`` and friends:: + Note this should normally be used indirectly via :func:`point` and friends:: sage: from sage.plot.point import Point sage: P = Point([1,2],[2,3],{'alpha':.5}) @@ -369,9 +371,11 @@ def point(points, **kwds): Extra options will get passed on to show(), as long as they are valid:: - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) + sage: point([(cos(theta), sin(theta)) # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent + sage: point([(cos(theta), sin(theta)) # These are equivalent # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)]).show(frame=True) TESTS: @@ -502,8 +506,9 @@ def point2d(points, **options): The legend can be colored:: - sage: P = points([(0, 0), (1, 0)], pointsize=40, legend_label='origin', legend_color='red') - sage: P + plot(x^2, (x, 0, 1), legend_label='plot', legend_color='green') + sage: P = points([(0, 0), (1, 0)], pointsize=40, + ....: legend_label='origin', legend_color='red') + sage: P + plot(x^2, (x, 0, 1), legend_label='plot', legend_color='green') # needs sage.symbolic Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -514,9 +519,11 @@ def point2d(points, **options): Extra options will get passed on to show(), as long as they are valid:: - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) + sage: point([(cos(theta), sin(theta)) # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent + sage: point([(cos(theta), sin(theta)) # These are equivalent # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)]).show(frame=True) .. PLOT:: @@ -546,9 +553,9 @@ def point2d(points, **options): We can plot a single complex number:: - sage: point(1 + I, pointsize=100) + sage: point(1 + I, pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: point(sqrt(2) + I, pointsize=100) + sage: point(sqrt(2) + I, pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -561,7 +568,7 @@ def point2d(points, **options): We can also plot a list of complex numbers:: - sage: point([I, 1 + I, 2 + 2*I], pointsize=100) + sage: point([I, 1 + I, 2 + 2*I], pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: diff --git a/src/sage/plot/polygon.py b/src/sage/plot/polygon.py index 48518a36da0..6f2c2b3f78b 100644 --- a/src/sage/plot/polygon.py +++ b/src/sage/plot/polygon.py @@ -31,11 +31,11 @@ class Polygon(GraphicPrimitive_xydata): INPUT: - - xdata -- list of `x`-coordinates of points defining Polygon + - ``xdata`` -- list of `x`-coordinates of points defining Polygon - - ydata -- list of `y`-coordinates of points defining Polygon + - ``ydata`` -- list of `y`-coordinates of points defining Polygon - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: @@ -198,7 +198,8 @@ def plot3d(self, z=0, **kwds): A pentagon:: - sage: polygon([(cos(t), sin(t)) for t in srange(0, 2*pi, 2*pi/5)]).plot3d() + sage: polygon([(cos(t), sin(t)) # needs sage.symbolic + ....: for t in srange(0, 2*pi, 2*pi/5)]).plot3d() Graphics3d Object .. PLOT:: @@ -364,8 +365,8 @@ def polygon2d(points, **options): For filled polygons, one can use different colors for the border and the interior as follows:: - sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]] - sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False) + sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]] # needs sage.symbolic + sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -388,8 +389,8 @@ def polygon2d(points, **options): An aperiodic monotile, [Smi2023]_:: - sage: s = sqrt(3) - sage: polygon2d([[0, 0], [0, s], [1, s], [3/2, 3/2*s], [3, s], [3, 0], [4, 0], + sage: s = sqrt(3) # needs sage.symbolic + sage: polygon2d([[0, 0], [0, s], [1, s], [3/2, 3/2*s], [3, s], [3, 0], [4, 0], # needs sage.symbolic ....: [9/2, -1/2*s], [3, -s], [3/2, -1/2*s], [1, -s], [-1, -s], ....: [-3/2, -1/2*s]], axes=False) Graphics object consisting of 1 graphics primitive @@ -403,8 +404,8 @@ def polygon2d(points, **options): A purple hexagon:: - sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] - sage: polygon2d(L, rgbcolor=(1,0,1)) + sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] # needs sage.symbolic + sage: polygon2d(L, rgbcolor=(1,0,1)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -415,8 +416,9 @@ def polygon2d(points, **options): A green deltoid:: - sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) + sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)), # needs sage.symbolic + ....: 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -427,8 +429,9 @@ def polygon2d(points, **options): A blue hypotrochoid:: - sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) + sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100), # needs sage.symbolic + ....: 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -440,8 +443,9 @@ def polygon2d(points, **options): Another one:: sage: n = 4; h = 5; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) + sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100), # needs sage.symbolic + ....: n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -454,8 +458,9 @@ def polygon2d(points, **options): A purple epicycloid:: sage: m = 9; b = 1 - sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100),m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) + sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100), # needs sage.symbolic + ....: m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -467,8 +472,8 @@ def polygon2d(points, **options): A brown astroid:: - sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)^3] for i in range(200)] - sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) + sage: L = [[cos(pi*i/100)^3, sin(pi*i/100)^3] for i in range(200)] # needs sage.symbolic + sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -479,8 +484,9 @@ def polygon2d(points, **options): And, my favorite, a greenish blob:: - sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) + sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), # needs sage.symbolic + ....: sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -491,8 +497,9 @@ def polygon2d(points, **options): This one is for my wife:: - sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] - sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) + sage: L = [[sin(pi*i/100)+sin(pi*i/50), # needs sage.symbolic + ....: -(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] + sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -503,7 +510,7 @@ def polygon2d(points, **options): One can do the same one with a colored legend label:: - sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') + sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: diff --git a/src/sage/plot/step.py b/src/sage/plot/step.py index 461ab53d411..4023686f9bd 100644 --- a/src/sage/plot/step.py +++ b/src/sage/plot/step.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Step function plots """ @@ -30,10 +31,10 @@ def plot_step_function(v, vertical_lines=True, **kwds): - ``v`` -- list of pairs (a,b) - - ``vertical_lines`` -- bool (default: True) if True, draw + - ``vertical_lines`` -- bool (default: ``True``) if ``True``, draw vertical risers at each step of this step function. Technically these vertical lines are not part of the graph - of this function, but they look very nice in the plot so we + of this function, but they look very nice in the plot, so we include them by default EXAMPLES: @@ -59,7 +60,8 @@ def plot_step_function(v, vertical_lines=True, **kwds): We pass in many options and get something that looks like "Space Invaders":: sage: v = [(i, sin(i)) for i in range(5, 20)] - sage: plot_step_function(v, vertical_lines=False, thickness=30, rgbcolor='purple', axes=False) + sage: plot_step_function(v, vertical_lines=False, thickness=30, + ....: rgbcolor='purple', axes=False) Graphics object consisting of 14 graphics primitives .. PLOT:: diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index bd9156bf000..663d3aee70b 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Streamline plots """ @@ -199,7 +200,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We increase the density of the plot:: - sage: streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi), density=2) + sage: streamline_plot((y, (cos(x)-2) * sin(x)), + ....: (x,-pi,pi), (y,-pi,pi), density=2) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -211,7 +213,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We ignore function values that are infinite or NaN:: sage: x, y = var('x y') - sage: streamline_plot((-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), (x,-10,10), (y,-10,10)) + sage: streamline_plot((-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), + ....: (x,-10,10), (y,-10,10)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -225,7 +228,7 @@ def streamline_plot(f_g, xrange, yrange, **options): sage: streamline_plot((x, y), (x,-2,2), (y,-2,2), xmax=10) Graphics object consisting of 1 graphics primitive - sage: streamline_plot((x, y), (x,-2,2), (y,-2,2)).show(xmax=10) # These are equivalent + sage: streamline_plot((x, y), (x,-2,2), (y,-2,2)).show(xmax=10) # These are equivalent .. PLOT:: @@ -248,7 +251,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We choose some particular points the streamlines pass through:: sage: pts = [[1, 1], [-2, 2], [1, -3/2]] - sage: g = streamline_plot((x + y) / sqrt(x^2 + y^2), (x,-3,3), (y,-3,3), start_points=pts) + sage: g = streamline_plot((x + y) / sqrt(x^2 + y^2), + ....: (x,-3,3), (y,-3,3), start_points=pts) sage: g += point(pts, color='red') sage: g Graphics object consisting of 2 graphics primitives diff --git a/src/sage/plot/text.py b/src/sage/plot/text.py index 0795cf5debb..602cdfebddf 100644 --- a/src/sage/plot/text.py +++ b/src/sage/plot/text.py @@ -81,8 +81,8 @@ def _repr_(self): EXAMPLES:: - sage: T = text("I like cool constants", (pi,e)) - sage: t=T[0];t + sage: T = text("I like cool constants", (pi,e)) # needs sage.symbolic + sage: t = T[0];t # needs sage.symbolic Text 'I like cool constants' at the point (3.1415926535...,2.7182818284...) """ return "Text '%s' at the point (%s,%s)" % (self.string, self.x, self.y) @@ -273,7 +273,8 @@ def text(string, xy, **options): Larger font, bold, colored red and transparent text:: - sage: text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red') + sage: text("I had a dream!", (2,12), alpha=0.3, + ....: fontsize='large', fontweight='bold', color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -283,7 +284,8 @@ def text(string, xy, **options): By setting ``horizontal_alignment`` to 'left' the text is guaranteed to be in the lower left no matter what:: - sage: text("I got a horse and he lives in a tree", (0,0), axis_coords=True, horizontal_alignment='left') + sage: text("I got a horse and he lives in a tree", (0,0), + ....: axis_coords=True, horizontal_alignment='left') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -293,7 +295,8 @@ def text(string, xy, **options): Various rotations:: - sage: text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom') + sage: text("noitator", (0,0), rotation=45.0, + ....: horizontal_alignment='left', vertical_alignment='bottom') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -311,7 +314,7 @@ def text(string, xy, **options): You can also align text differently:: - sage: t1 = text("Hello",(1,1), vertical_alignment="top") + sage: t1 = text("Hello", (1,1), vertical_alignment="top") sage: t2 = text("World", (1,0.5), horizontal_alignment="left") sage: t1 + t2 # render the sum Graphics object consisting of 2 graphics primitives @@ -330,7 +333,7 @@ def text(string, xy, **options): Some examples of bounding box:: - sage: bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2} + sage: bbox = {'boxstyle': "rarrow,pad=0.3", 'fc': "cyan", 'ec': "b", 'lw': 2} sage: text("I feel good", (1,2), bounding_box=bbox) Graphics object consisting of 1 graphics primitive @@ -341,7 +344,7 @@ def text(string, xy, **options): :: - sage: text("So good", (0,0), bounding_box={'boxstyle':'round', 'fc':'w'}) + sage: text("So good", (0,0), bounding_box={'boxstyle': 'round', 'fc': 'w'}) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -371,8 +374,10 @@ def text(string, xy, **options): sage: PQ = point2d([(-a, a), (a, a)]) sage: botleft = dict(horizontal_alignment='left', vertical_alignment='bottom') sage: botright = dict(horizontal_alignment='right', vertical_alignment='bottom') - sage: tp = text(r'$z_P = e^{3i\pi/4}$', (-a, a), **botright) - sage: tq = text(r'$Q = (\frac{\sqrt{2}}{2}, \frac{\sqrt{2}}{2})$', (a, a), **botleft) + sage: tp = text(r'$z_P = e^{3i\pi/4}$', + ....: (-a, a), **botright) + sage: tq = text(r'$Q = (\frac{\sqrt{2}}{2}, \frac{\sqrt{2}}{2})$', + ....: (a, a), **botleft) sage: A + PQ + tp + tq Graphics object consisting of 4 graphics primitives diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 96247522baf..f678dc6b3b1 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -137,8 +137,7 @@ def __init__(self, a, b=None, c=None): """ from sage.rings.polynomial.multi_polynomial import MPolynomial if b is None and c is None: - if (isinstance(a, (list, tuple)) - and len(a) == 3): + if isinstance(a, (list, tuple)) and len(a) == 3: a, b, c = a elif a == 0: a = b = c = 0 @@ -215,8 +214,8 @@ def __mul__(self, right): return BinaryQF(self.__pari__().qfbcompraw(right)) # ...or a 2x2 matrix... if (isinstance(right.parent(), MatrixSpace) - and right.nrows() == right.ncols() == 2): - aa,bb,cc,dd = right.list() + and right.nrows() == right.ncols() == 2): + aa, bb, cc, dd = right.list() A = self.polynomial()(aa, cc) C = self.polynomial()(bb, dd) B = self.polynomial()(aa + bb, cc + dd) - A - C @@ -536,10 +535,10 @@ def from_polynomial(poly): if not isinstance(R, MPolynomialRing_base) or R.ngens() != 2: raise TypeError(f'not a bivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): - raise ValueError(f'polynomial has monomials of degree != 2') - x,y = R.gens() + raise ValueError('polynomial has monomials of degree != 2') + x, y = R.gens() coeffs = (poly.monomial_coefficient(mon) for mon in (x**2, x*y, y**2)) - a,b,c = map(ZZ, coeffs) + a, b, c = map(ZZ, coeffs) return BinaryQF(a, b, c) @cached_method @@ -924,7 +923,7 @@ def reduced_form(self, transformation=False, algorithm="default"): 'supported using PARI') if transformation: - y,g = self.__pari__().qfbredsl2() + y, g = self.__pari__().qfbredsl2() return BinaryQF(y), Matrix(ZZ, g) return BinaryQF(self.__pari__().qfbred()) @@ -1153,7 +1152,7 @@ def cycle(self, proper=False): 'implemented for non-square discriminants') if proper: # Prop 6.10.5 in Buchmann Vollmer - C = list(self.cycle(proper=False)) # make a copy so we can modify it + C = list(self.cycle(proper=False)) # make a copy that we can modify if len(C) % 2: C += C for i in range(len(C)//2): @@ -1316,7 +1315,7 @@ def is_equivalent(self, other, proper=True): sage: Q1.is_equivalent(Q2, proper=True) # optional - sage.libs.pari True """ - if type(other) != type(self): + if not isinstance(other, BinaryQF): raise TypeError("%s is not a BinaryQF" % other) if self.discriminant() != other.discriminant(): return False @@ -1342,7 +1341,7 @@ def is_equivalent(self, other, proper=True): return is_properly_equiv else: g = gcd(a, b) - return is_properly_equiv or ((gcd(ao,b) == g) and ((a*ao - g**2) % (b*g) == 0)) + return is_properly_equiv or ((gcd(ao, b) == g) and ((a*ao - g**2) % (b*g) == 0)) proper_cycle = otherred.cycle(proper=True) @@ -1654,13 +1653,13 @@ def solve_integer(self, n, *, algorithm="general"): # https://math.stackexchange.com/a/980075 w = self.discriminant().sqrt() r = (-self._b + (w if w != self._b else -w)) / (2*self._a) - p,q = r.as_integer_ratio() - g,u,v = p.xgcd(q) - M = Matrix(ZZ, [[v,p],[-u,q]]) + p, q = r.as_integer_ratio() + g, u, v = p.xgcd(q) + M = Matrix(ZZ, [[v, p], [-u, q]]) elif self._c: - M = Matrix(ZZ, [[0,1],[1,0]]) + M = Matrix(ZZ, [[0, 1], [1, 0]]) else: - M = Matrix(ZZ, [[1,0],[0,1]]) + M = Matrix(ZZ, [[1, 0], [0, 1]]) assert M.is_unit() Q = self.matrix_action_right(M) assert not Q._c @@ -1845,7 +1844,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): c = ZZ(0) # -b/2 < a <= b/2 for a in xsrange((-b/2).floor() + 1, (b/2).floor() + 1): - if (not primitive_only) or (gcd([a,b,c]) == 1): + if not primitive_only or (gcd([a, b, c]) == 1): form_list.append(BinaryQF(a, b, c)) # We follow the description of Buchmann/Vollmer 6.7.1. They # enumerate all reduced forms. We only want representatives. @@ -1879,14 +1878,14 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): a4 = 4*a s = D + a*a4 w = 1+(s-1).isqrt() if s > 0 else 0 - if w%2 != D%2: + if w % 2 != D % 2: w += 1 for b in xsrange(w, a+1, 2): t = b*b-D if t % a4 == 0: c = t // a4 - if (not primitive_only) or gcd([a, b, c]) == 1: - if b>0 and a>b and c>a: + if not primitive_only or gcd([a, b, c]) == 1: + if c > a > b > 0: form_list.append(BinaryQF([a, -b, c])) form_list.append(BinaryQF([a, b, c])) if not proper or D > 0: diff --git a/src/sage/quadratic_forms/count_local_2.pyx b/src/sage/quadratic_forms/count_local_2.pyx index 95228c64208..3ce05a3a413 100644 --- a/src/sage/quadratic_forms/count_local_2.pyx +++ b/src/sage/quadratic_forms/count_local_2.pyx @@ -2,7 +2,6 @@ r""" Optimized counting of congruence solutions """ from sage.arith.misc import is_prime, kronecker as kronecker_symbol, valuation -from sage.rings.finite_rings.integer_mod cimport IntegerMod_gmp from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing @@ -73,16 +72,16 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): # Compute the Gauss sum neg1 = -1 - if not (m % p): + if not m % p: if n % 2: - count = (p**(n-1)) + count = p**(n-1) else: - count = (p**(n-1)) + (p-1) * (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p) + count = p**(n-1) + (p-1) * (p**((n-2)//2)) * kronecker_symbol(((neg1**(n//2)) * Qdet) % p, p) else: if n % 2: - count = (p**(n-1)) + (p**((n-1)/2)) * kronecker_symbol(((neg1**((n-1)/2)) * Qdet * m) % p, p) + count = p**(n-1) + p**((n-1)//2) * kronecker_symbol(((neg1**((n-1)//2)) * Qdet * m) % p, p) else: - count = (p**(n-1)) - (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p) + count = p**(n-1) - p**((n-2)//2) * kronecker_symbol(((neg1**(n//2)) * Qdet) % p, p) # Return the result return count @@ -103,11 +102,6 @@ cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): R = p ** k Q1 = Q.change_ring(IntegerModRing(R)) - # Cython Variables - cdef IntegerMod_gmp zero, one - zero = IntegerMod_gmp(IntegerModRing(R), 0) - one = IntegerMod_gmp(IntegerModRing(R), 1) - # Initialize the counting vector count_vector = [0 for i in range(6)] @@ -119,7 +113,7 @@ cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): m1 = Mod(m, R) # Count the local solutions - for i from 0 <= i < R_n: + for i in range(R_n): # Perform a carry (when value = R-1) until we can increment freely ptr = len(v) @@ -128,20 +122,20 @@ cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): ptr += -1 # Only increment if we're not already at the zero vector =) - if (ptr > 0): + if ptr > 0: v[ptr-1] += 1 # Evaluate Q(v) quickly tmp_val = Mod(0, R) for a from 0 <= a < n: for b from a <= b < n: - tmp_val += Q1[a,b] * v[a] * v[b] + tmp_val += Q1[a, b] * v[a] * v[b] # Sort the solution by it's type - #if (Q1(v) == m1): - if (tmp_val == m1): + # if Q1(v) == m1: + if tmp_val == m1: solntype = local_solution_type_cdef(Q1, p, v, zvec, nzvec) - if (solntype != 0): + if solntype != 0: count_vector[solntype] += 1 # Generate the Bad-type and Total counts @@ -187,11 +181,6 @@ def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec): return CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec) - - - - - cdef local_solution_type_cdef(Q, p, w, zvec, nzvec): """ Internal routine to check if a given solution vector `w` (of `Q(w) = @@ -209,91 +198,87 @@ cdef local_solution_type_cdef(Q, p, w, zvec, nzvec): # Check if the solution satisfies the zvec "zero" congruence conditions # (either zvec is empty or its components index the zero vector mod p) - if (zvec is None) or (not zvec): + if zvec is None or not zvec: zero_flag = True else: zero_flag = False i = 0 - while ( (i < len(zvec)) and ((w[zvec[i]] % p) == 0) ): # Increment so long as our entry is zero (mod p) + while i < len(zvec) and not w[zvec[i]] % p: # Increment so long as our entry is zero (mod p) i += 1 - if (i == len(zvec)): # If we make it through all entries then the solution is zero (mod p) + if i == len(zvec): # If we make it through all entries then the solution is zero (mod p) zero_flag = True - # DIAGNOSTIC - #print("IsLocalSolutionType: Finished the Zero congruence condition test \n") + # print("IsLocalSolutionType: Finished the Zero congruence condition test \n") if not zero_flag: return 0 # DIAGNOSTIC - #print("IsLocalSolutionType: Passed the Zero congruence condition test \n") + # print("IsLocalSolutionType: Passed the Zero congruence condition test \n") # Check if the solution satisfies the nzvec "nonzero" congruence conditions # (nzvec is non-empty and its components index a non-zero vector mod p) - if (nzvec is None): + if nzvec is None: nonzero_flag = True - elif (len(nzvec) == 0): + elif len(nzvec) == 0: nonzero_flag = False # Trivially no solutions in this case! else: nonzero_flag = False i = 0 - while ((not nonzero_flag) and (i < len(nzvec))): - if ((w[nzvec[i]] % p) != 0): + while not nonzero_flag and i < len(nzvec): + if w[nzvec[i]] % p: nonzero_flag = True # The non-zero condition is satisfied when we find one non-zero entry i += 1 if not nonzero_flag: return 0 - # Check if the solution has the appropriate (local) type: # ------------------------------------------------------- # 1: Check Good-type - for i from 0 <= i < n: - if (((w[i] % p) != 0) and ((Q[i,i] % p) != 0)): + for i in range(n): + if w[i] % p and Q[i, i] % p: return 1 - if (p == 2): - for i from 0 <= i < (n - 1): - if (((Q[i,i+1] % p) != 0) and (((w[i] % p) != 0) or ((w[i+1] % p) != 0))): + if p == 2: + for i in range(n - 1): + if Q[i, i+1] % p and (w[i] % p or w[i+1] % p): return 1 - # 2: Check Zero-type Zero_flag = True - for i from 0 <= i < n: - if ((w[i] % p) != 0): + for i in range(n): + if w[i] % p: Zero_flag = False if Zero_flag: return 2 - # Check if wS1 is zero or not wS1_nonzero_flag = False for i from 0 <= i < n: # Compute the valuation of each index, allowing for off-diagonal terms - if (Q[i,i] == 0): - if (i == 0): - val = valuation(Q[i,i+1], p) # Look at the term to the right - elif (i == n - 1): - val = valuation(Q[i-1,i], p) # Look at the term above + if Q[i, i] == 0: + if i == 0: + val = valuation(Q[i, i+1], p) # Look at the term to the right + elif i == n - 1: + val = valuation(Q[i-1, i], p) # Look at the term above else: - val = valuation(Q[i,i+1] + Q[i-1,i], p) # Finds the valuation of the off-diagonal term since only one isn't zero + val = valuation(Q[i, i+1] + Q[i-1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero else: - val = valuation(Q[i,i], p) + val = valuation(Q[i, i], p) # Test each index - if ((val == 1) and ((w[i] % p) != 0)): + if val == 1 and w[i] % p: wS1_nonzero_flag = True # 4: Check Bad-type I - if (wS1_nonzero_flag is True): + if wS1_nonzero_flag: return 4 # 5: Check Bad-type II - if (wS1_nonzero_flag is False): + if not wS1_nonzero_flag: return 5 # Error if we get here! =o diff --git a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx index f4dc35176a2..95e82e669dc 100644 --- a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx +++ b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx @@ -4,14 +4,15 @@ def QFEvaluateVector(Q, v): r""" Evaluate this quadratic form `Q` on a vector or matrix of elements - coercible to the base ring of the quadratic form. If a vector - is given, then the output will be the ring element `Q(v)`, but if a - matrix is given, then the output will be the quadratic form `Q'` - which in matrix notation is given by: + coercible to the base ring of the quadratic form. + + If a vector is given, then the output will be the ring element + `Q(v)`, but if a matrix is given, then the output will be the + quadratic form `Q'` which in matrix notation is given by: .. MATH:: - Q' = v^t\cdot Q\cdot v. + Q' = v^t\cdot Q\cdot v. .. NOTE:: @@ -43,7 +44,6 @@ def QFEvaluateVector(Q, v): return QFEvaluateVector_cdef(Q, v) - cdef QFEvaluateVector_cdef(Q, v): r""" Routine to quickly evaluate a quadratic form `Q` on a vector `v`. See @@ -54,16 +54,15 @@ cdef QFEvaluateVector_cdef(Q, v): # (In matrix notation: A^t * Q * A) n = Q.dim() - tmp_val = Q.base_ring()(0) - for i from 0 <= i < n: - for j from i <= j < n: - tmp_val += Q[i,j] * v[i] * v[j] + tmp_val = Q.base_ring().zero() + for i in range(n): + for j in range(i, n): + tmp_val += Q[i, j] * v[i] * v[j] # Return the value (over R) return Q.base_ring().coerce(tmp_val) - def QFEvaluateMatrix(Q, M, Q2): r""" Evaluate this quadratic form `Q` on a matrix `M` of elements coercible @@ -72,7 +71,7 @@ def QFEvaluateMatrix(Q, M, Q2): .. MATH:: - Q_2 = M^t\cdot Q\cdot M. + Q_2 = M^t\cdot Q\cdot M. .. NOTE:: @@ -125,14 +124,17 @@ cdef QFEvaluateMatrix_cdef(Q, M, Q2): # TODO: Check the dimensions of M are compatible with those of Q and Q2 # Evaluate Q(M) into Q2 - for k from 0 <= k < m: - for l from k <= l < m: - tmp_sum = Q2.base_ring()(0) - for i from 0 <= i < n: - for j from i <= j < n: - if (k == l): - tmp_sum += Q[i,j] * (M[i,k] * M[j,l]) - else: - tmp_sum += Q[i,j] * (M[i,k] * M[j,l] + M[i,l] * M[j,k]) - Q2[k,l] = tmp_sum + for k in range(m): + for l in range(k, m): + tmp_sum = Q2.base_ring().zero() + if k == l: + for i in range(n): + for j in range(i, n): + tmp_sum += Q[i, j] * (M[i, k] * M[j, l]) + else: + for i in range(n): + for j in range(i, n): + tmp_sum += Q[i, j] * (M[i, k] * M[j, l] + + M[i, l] * M[j, k]) + Q2[k, l] = tmp_sum return Q2 diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index 11cbdde579c..4ea72a97b1b 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -68,6 +68,7 @@ from sage.repl.load import load_wrap from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE from sage.misc.lazy_import import LazyImport +from sage.misc.misc import run_once @magics_class class SageMagics(Magics): @@ -583,41 +584,6 @@ def all_globals(): return all_jupyter -# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop -from functools import wraps -def run_once(func): - """ - Runs a function (successfully) only once. - - The running can be reset by setting the ``has_run`` attribute to False - - TESTS:: - - sage: from sage.repl.ipython_extension import run_once - sage: @run_once - ....: def foo(work): - ....: if work: - ....: return 'foo worked' - ....: raise RuntimeError("foo didn't work") - sage: foo(False) - Traceback (most recent call last): - ... - RuntimeError: foo didn't work - sage: foo(True) - 'foo worked' - sage: foo(False) - sage: foo(True) - """ - @wraps(func) - def wrapper(*args, **kwargs): - if not wrapper.has_run: - result = func(*args, **kwargs) - wrapper.has_run = True - return result - wrapper.has_run = False - return wrapper - - @run_once def load_ipython_extension(ip): """ diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index fb62627c9dc..b8dff4c3903 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -591,7 +591,7 @@ def __eq__(self, other): """ if self is other: return True - if type(self) != type(other): + if type(self) is not type(other): return False return ((self.base_ring(), self.variable_name(), self.category()) == (other.base_ring(), other.variable_name(), other.category())) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b7b49d32dc9..b07319382d3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -4075,7 +4075,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if isinstance(data, MutablePoset): return self.element_class(self, data, simplify=simplify, convert=convert) - if type(data) == self.element_class and data.parent() == self: + if type(data) is self.element_class and data.parent() == self: return data if isinstance(data, AsymptoticExpansion): @@ -4984,7 +4984,7 @@ def __eq__(self, other): sage: F_X == F_Y False """ - return (type(self) == type(other) + return (type(self) is type(other) and self.growth_group == other.growth_group and self._default_prec_ == other._default_prec_ and self._category_ == other._category_ diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 26b38b88303..27c14592bca 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2775,7 +2775,7 @@ def __eq__(self, other): sage: F == G False """ - return type(self) == type(other) and self.var == other.var + return type(self) is type(other) and self.var == other.var def __ne__(self, other): r""" diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 79510d42eca..f93535e8d8e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -486,7 +486,7 @@ def convert_factors(data, raw_data): elif data is None: raise ValueError('%s cannot be converted.' % (data,)) - elif type(data) == self.element_class and data.parent() == self: + elif type(data) is self.element_class and data.parent() == self: return data elif isinstance(data, str): diff --git a/src/sage/rings/finite_rings/conway_polynomials.py b/src/sage/rings/finite_rings/conway_polynomials.py index d947fa25cc8..35604cbcd07 100644 --- a/src/sage/rings/finite_rings/conway_polynomials.py +++ b/src/sage/rings/finite_rings/conway_polynomials.py @@ -11,10 +11,13 @@ """ from sage.misc.fast_methods import WithEqualityById +from sage.misc.lazy_import import lazy_import from sage.structure.sage_object import SageObject from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.integer import Integer -import sage.databases.conway + +lazy_import('sage.databases.conway', 'ConwayPolynomials') + def conway_polynomial(p, n): """ @@ -45,11 +48,11 @@ def conway_polynomial(p, n): EXAMPLES:: - sage: conway_polynomial(2,5) + sage: conway_polynomial(2,5) # needs conway_polynomials x^5 + x^2 + 1 - sage: conway_polynomial(101,5) + sage: conway_polynomial(101,5) # needs conway_polynomials x^5 + 2*x + 99 - sage: conway_polynomial(97,101) + sage: conway_polynomial(97,101) # needs conway_polynomials Traceback (most recent call last): ... RuntimeError: requested Conway polynomial not in database. @@ -57,7 +60,7 @@ def conway_polynomial(p, n): (p, n) = (int(p), int(n)) R = FiniteField(p)['x'] try: - return R(sage.databases.conway.ConwayPolynomials()[p][n]) + return R(ConwayPolynomials()[p][n]) except KeyError: raise RuntimeError("requested Conway polynomial not in database.") @@ -82,7 +85,7 @@ def exists_conway_polynomial(p, n): EXAMPLES:: - sage: exists_conway_polynomial(2,3) + sage: exists_conway_polynomial(2,3) # needs conway_polynomials True sage: exists_conway_polynomial(2,-1) False @@ -91,7 +94,10 @@ def exists_conway_polynomial(p, n): sage: exists_conway_polynomial(6,6) False """ - return sage.databases.conway.ConwayPolynomials().has_polynomial(p,n) + try: + return ConwayPolynomials().has_polynomial(p,n) + except ImportError: + return False class PseudoConwayLattice(WithEqualityById, SageObject): r""" @@ -127,6 +133,7 @@ class PseudoConwayLattice(WithEqualityById, SageObject): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) @@ -154,11 +161,13 @@ def __init__(self, p, use_database=True): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: PCL.polynomial(3) x^3 + 2*x + 1 + sage: # needs sage.rings.finite_rings sage: PCL = PseudoConwayLattice(5, use_database=False) sage: PCL.polynomial(12) x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2 @@ -171,9 +180,13 @@ def __init__(self, p, use_database=True): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: - C = sage.databases.conway.ConwayPolynomials() - self.nodes = {n: self.ring(C.polynomial(p, n)) - for n in C.degrees(p)} + try: + C = ConwayPolynomials() + except ImportError: + self.nodes = {} + else: + self.nodes = {n: self.ring(C.polynomial(p, n)) + for n in C.degrees(p)} else: self.nodes = {} @@ -199,6 +212,7 @@ def polynomial(self, n): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) @@ -267,6 +281,7 @@ def check_consistency(self, n): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.check_consistency(6) @@ -301,6 +316,7 @@ def _find_pow_of_frobenius(p, n, x, y): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import _find_pow_of_frobenius sage: K. = GF(3^14) sage: x = K.multiplicative_generator() @@ -380,6 +396,7 @@ def _frobenius_shift(K, generators, check_only=False): EXAMPLES:: + sage: # needs sage.libs.ntl sage.rings.finite_rings sage: R. = GF(2)[] sage: f30 = x^30 + x^28 + x^27 + x^25 + x^24 + x^20 + x^19 + x^18 + x^16 + x^15 + x^12 + x^10 + x^7 + x^2 + 1 sage: f20 = x^20 + x^19 + x^15 + x^13 + x^12 + x^11 + x^9 + x^8 + x^7 + x^4 + x^2 + x + 1 diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 5dc87c95f49..e9ab5b5d4ab 100755 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings """ Base class for finite field elements @@ -711,23 +711,23 @@ cdef class FinitePolyExtElement(FiniteRingElement): EXAMPLES:: - sage: k. = FiniteField(9, impl='givaro', modulus='primitive') - sage: a.is_square() + sage: k. = FiniteField(9, impl='givaro', modulus='primitive') # needs sage.libs.linbox + sage: a.is_square() # needs sage.libs.linbox False - sage: (a**2).is_square() + sage: (a**2).is_square() # needs sage.libs.linbox True - sage: k. = FiniteField(4, impl='ntl', modulus='primitive') - sage: (a**2).is_square() + sage: k. = FiniteField(4, impl='ntl', modulus='primitive') # needs sage.libs.ntl + sage: (a**2).is_square() # needs sage.libs.ntl True - sage: k. = FiniteField(17^5, impl='pari_ffelt', modulus='primitive') - sage: a.is_square() + sage: k. = FiniteField(17^5, impl='pari_ffelt', modulus='primitive') # needs sage.libs.pari + sage: a.is_square() # needs sage.libs.pari False - sage: (a**2).is_square() + sage: (a**2).is_square() # needs sage.libs.pari True :: - sage: k(0).is_square() + sage: k(0).is_square() # needs sage.libs.linbox True """ K = self.parent() @@ -1049,6 +1049,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): TESTS:: + sage: # needs sage.modules sage: p = random_prime(2^99) sage: k = randrange(2,10) sage: F. = GF((p, k)) @@ -1086,7 +1087,7 @@ cdef class Cache_base(SageObject): EXAMPLES:: sage: k. = GF(2^48) - sage: k._cache.fetch_int(2^33 + 2 + 1) + sage: k._cache.fetch_int(2^33 + 2 + 1) # needs sage.libs.ntl a^33 + a + 1 """ raise NotImplementedError("this must be implemented by subclasses") diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 57c48ac2858..b83f259abcc 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -28,13 +28,16 @@ from .element_base cimport FinitePolyExtElement from .integer_mod import IntegerMod_abstract import sage.rings.integer -from sage.modules.free_module_element import FreeModuleElement from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial_element import MPolynomial from sage.rings.rational import Rational from sage.structure.richcmp cimport rich_to_bool +try: + from sage.modules.free_module_element import FreeModuleElement +except ImportError: + FreeModuleElement = () from sage.interfaces.abc import GapElement @@ -1330,9 +1333,10 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): EXAMPLES:: + sage: # needs sage.libs.gap sage: F = FiniteField(2^3, 'aa', impl='pari_ffelt') sage: aa = F.multiplicative_generator() - sage: gap(aa) # indirect doctest + sage: gap(aa) # indirect doctest Z(2^3) sage: b = F.multiplicative_generator() sage: a = b^3 @@ -1347,6 +1351,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): You can specify the instance of the Gap interpreter that is used:: + sage: # needs sage.libs.gap sage: F = FiniteField(next_prime(200)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator() sage: a._gap_ (gap) @@ -1356,6 +1361,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): Gap only supports relatively small finite fields:: + sage: # needs sage.libs.gap sage: F = FiniteField(next_prime(1000)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator() sage: a._gap_init_() diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 4f4d7f64c72..7e2eed91153 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1,12 +1,12 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings """ Base class for finite fields TESTS:: - sage: K. = NumberField(x^2 + 1) - sage: F = K.factor(3)[0][0].residue_field() - sage: loads(dumps(F)) == F + sage: K. = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: F = K.factor(3)[0][0].residue_field() # needs sage.rings.number_field + sage: loads(dumps(F)) == F # needs sage.rings.number_field True AUTHORS: @@ -226,13 +226,14 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: GF(97,'a')._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: GF(97,'a')._magma_init_(magma) 'GF(97)' - sage: GF(9,'a')._magma_init_(magma) # optional - magma + sage: GF(9,'a')._magma_init_(magma) 'SageCreateWithNames(ext,["a"])' - sage: magma(GF(9,'a')) # optional - magma + sage: magma(GF(9,'a')) Finite field of size 3^2 - sage: magma(GF(9,'a')).1 # optional - magma + sage: magma(GF(9,'a')).1 a """ if self.degree() == 1: @@ -337,11 +338,11 @@ cdef class FiniteField(Field): sage: L = [] sage: from sage.rings.finite_rings.finite_field_base import FiniteField - sage: for impl in ("givaro", "pari", "ntl"): - ....: k = GF(8, impl=impl, names="z") - ....: print(list(FiniteField.__iter__(k))) + sage: print(list(FiniteField.__iter__(GF(8, impl="givaro", names="z")))) # needs sage.libs.linbox [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] + sage: print(list(FiniteField.__iter__(GF(8, impl="pari", names="z")))) [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] + sage: print(list(FiniteField.__iter__(GF(8, impl="ntl", names="z")))) # needs sage.libs.ntl [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] """ cdef Py_ssize_t n = self.degree() @@ -1011,7 +1012,7 @@ cdef class FiniteField(Field): The given modulus is always made monic:: - sage: k. = GF(7^2, modulus=2*x^2-3, impl="pari_ffelt") + sage: k. = GF(7^2, modulus=2*x^2 - 3, impl="pari_ffelt") sage: k.modulus() x^2 + 2 @@ -1021,19 +1022,19 @@ cdef class FiniteField(Field): sage: GF(2, impl="modn").modulus() x + 1 - sage: GF(2, impl="givaro").modulus() + sage: GF(2, impl="givaro").modulus() # needs sage.libs.linbox x + 1 - sage: GF(2, impl="ntl").modulus() + sage: GF(2, impl="ntl").modulus() # needs sage.libs.ntl x + 1 sage: GF(2, impl="modn", modulus=x).modulus() x - sage: GF(2, impl="givaro", modulus=x).modulus() + sage: GF(2, impl="givaro", modulus=x).modulus() # needs sage.libs.linbox x - sage: GF(2, impl="ntl", modulus=x).modulus() + sage: GF(2, impl="ntl", modulus=x).modulus() # needs sage.libs.ntl x - sage: GF(13^2, 'a', impl="givaro", modulus=x^2+2).modulus() + sage: GF(13^2, 'a', impl="givaro", modulus=x^2 + 2).modulus() # needs sage.libs.linbox x^2 + 2 - sage: GF(13^2, 'a', impl="pari_ffelt", modulus=x^2+2).modulus() + sage: GF(13^2, 'a', impl="pari_ffelt", modulus=x^2 + 2).modulus() # needs sage.libs.pari x^2 + 2 """ # Normally, this is set by the constructor of the implementation @@ -1085,6 +1086,7 @@ cdef class FiniteField(Field): sage: f(F.gen()) 0 + sage: # needs sage.libs.ntl sage: k. = GF(2^20, impl='ntl') sage: k.polynomial() a^20 + a^10 + a^9 + a^7 + a^6 + a^5 + a^4 + a + 1 @@ -1121,12 +1123,12 @@ cdef class FiniteField(Field): EXAMPLES:: sage: k = GF(19^4, 'a') - sage: k.random_element().parent() is k + sage: k.random_element().parent() is k # needs sage.modules True Passes extra positional or keyword arguments through:: - sage: k.random_element(prob=0) + sage: k.random_element(prob=0) # needs sage.modules 0 """ @@ -1143,7 +1145,7 @@ cdef class FiniteField(Field): EXAMPLES:: sage: k = GF(2^8,'a') - sage: k.some_elements() # random output + sage: k.some_elements() # random output # needs sage.modules [a^4 + a^3 + 1, a^6 + a^4 + a^3, a^5 + a^4 + a, a^2 + a] """ return [self.random_element() for i in range(4)] @@ -1204,9 +1206,10 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: GF(27,'a').vector_space(map=False) + sage: GF(27,'a').vector_space(map=False) # needs sage.modules Vector space of dimension 3 over Finite Field of size 3 + sage: # needs sage.modules sage: F = GF(8) sage: E = GF(64) sage: V, from_V, to_V = E.vector_space(F, map=True) @@ -1221,6 +1224,7 @@ cdef class FiniteField(Field): sage: all(to_V(c * e) == c * to_V(e) for e in E for c in F) True + sage: # needs sage.modules sage: basis = [E.gen(), E.gen() + 1] sage: W, from_W, to_W = E.vector_space(F, basis, map=True) sage: all(from_W(to_W(e)) == e for e in E) @@ -1233,7 +1237,8 @@ cdef class FiniteField(Field): (1, 0) (0, 1) - sage: F = GF(9, 't', modulus=(x^2+x-1)) + sage: # needs sage.modules + sage: F = GF(9, 't', modulus=x^2 + x - 1) sage: E = GF(81) sage: h = Hom(F,E).an_element() sage: V, from_V, to_V = E.vector_space(h, map=True) @@ -1397,16 +1402,16 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: K. = Qq(49); k = K.residue_field() - sage: k.convert_map_from(K) + sage: K. = Qq(49); k = K.residue_field() # needs sage.rings.padics + sage: k.convert_map_from(K) # needs sage.rings.padics Reduction morphism: From: 7-adic Unramified Extension Field in a defined by x^2 + 6*x + 3 To: Finite Field in a0 of size 7^2 Check that :trac:`8240 is resolved:: - sage: R. = Zq(81); k = R.residue_field() - sage: k.convert_map_from(R) + sage: R. = Zq(81); k = R.residue_field() # needs sage.rings.padics + sage: k.convert_map_from(R) # needs sage.rings.padics Reduction morphism: From: 3-adic Unramified Extension Ring in a defined by x^4 + 2*x^3 + 2 To: Finite Field in a0 of size 3^4 @@ -1513,13 +1518,16 @@ cdef class FiniteField(Field): To: Finite Field in b of size 5^2 Defn: 1 |--> 1 sage: f.parent() - Set of field embeddings from Finite Field of size 5 to Finite Field in b of size 5^2 + Set of field embeddings + from Finite Field of size 5 + to Finite Field in b of size 5^2 Extensions of non-prime finite fields by polynomials are not yet supported: we fall back to generic code:: sage: k.extension(x^5 + x^2 + x - 1) - Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 with modulus x^5 + x^2 + x + 2 + Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 + with modulus x^5 + x^2 + x + 2 TESTS: @@ -1798,12 +1806,14 @@ cdef class FiniteField(Field): Ring morphism: From: Finite Field in z3 of size 2^3 To: Finite Field in z21 of size 2^21 - Defn: z3 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^11 + z21^9 + z21^8 + z21^6 + z21^2), + Defn: z3 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^11 + + z21^9 + z21^8 + z21^6 + z21^2), (Finite Field in z7 of size 2^7, Ring morphism: From: Finite Field in z7 of size 2^7 To: Finite Field in z21 of size 2^21 - Defn: z7 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^14 + z21^6 + z21^4 + z21^3 + z21), + Defn: z7 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^14 + + z21^6 + z21^4 + z21^3 + z21), (Finite Field in z21 of size 2^21, Identity endomorphism of Finite Field in z21 of size 2^21)] """ @@ -1946,8 +1956,8 @@ cdef class FiniteField(Field): sage: Frob = k.frobenius_endomorphism(); Frob Frobenius endomorphism t |--> t^3 on Finite Field in t of size 3^5 - sage: a = k.random_element() - sage: Frob(a) == a^3 + sage: a = k.random_element() # needs sage.modules + sage: Frob(a) == a^3 # needs sage.modules True We can specify a power:: @@ -1983,8 +1993,8 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: G = GF(3^6).galois_group() - sage: G + sage: # needs sage.groups + sage: G = GF(3^6).galois_group(); G Galois group C6 of GF(3^6) sage: F = G.gen() sage: F^2 @@ -2040,13 +2050,14 @@ cdef class FiniteField(Field): EXAMPLES:: sage: F. = GF(2^4) - sage: F.dual_basis(basis=None, check=False) + sage: F.dual_basis(basis=None, check=False) # needs sage.modules [a^3 + 1, a^2, a, 1] We can test that the dual basis returned satisfies the defining property of a dual basis: `\mathrm{Tr}(e_i d_j) = \delta_{i,j}, 0 \leq i,j \leq n-1` :: + sage: # needs sage.modules sage: F. = GF(7^4) sage: e = [4*a^3, 2*a^3 + a^2 + 3*a + 5, ....: 3*a^3 + 5*a^2 + 4*a + 2, 2*a^3 + 2*a^2 + 2] @@ -2060,17 +2071,18 @@ cdef class FiniteField(Field): We can test that if `d` is the dual basis of `e`, then `e` is the dual basis of `d`:: + sage: # needs sage.modules sage: F. = GF(7^8) sage: e = [a^0, a^1, a^2, a^3, a^4, a^5, a^6, a^7] sage: d = F.dual_basis(e, check=False); d [6*a^6 + 4*a^5 + 4*a^4 + a^3 + 6*a^2 + 3, - 6*a^7 + 4*a^6 + 4*a^5 + 2*a^4 + a^2, - 4*a^6 + 5*a^5 + 5*a^4 + 4*a^3 + 5*a^2 + a + 6, - 5*a^7 + a^6 + a^4 + 4*a^3 + 4*a^2 + 1, - 2*a^7 + 5*a^6 + a^5 + a^3 + 5*a^2 + 2*a + 4, - a^7 + 2*a^6 + 5*a^5 + a^4 + 5*a^2 + 4*a + 4, - a^7 + a^6 + 2*a^5 + 5*a^4 + a^3 + 4*a^2 + 4*a + 6, - 5*a^7 + a^6 + a^5 + 2*a^4 + 5*a^3 + 6*a] + 6*a^7 + 4*a^6 + 4*a^5 + 2*a^4 + a^2, + 4*a^6 + 5*a^5 + 5*a^4 + 4*a^3 + 5*a^2 + a + 6, + 5*a^7 + a^6 + a^4 + 4*a^3 + 4*a^2 + 1, + 2*a^7 + 5*a^6 + a^5 + a^3 + 5*a^2 + 2*a + 4, + a^7 + 2*a^6 + 5*a^5 + a^4 + 5*a^2 + 4*a + 4, + a^7 + a^6 + 2*a^5 + 5*a^4 + a^3 + 4*a^2 + 4*a + 6, + 5*a^7 + a^6 + a^5 + 2*a^4 + 5*a^3 + 6*a] sage: F.dual_basis(d) [1, a, a^2, a^3, a^4, a^5, a^6, a^7] @@ -2078,12 +2090,12 @@ cdef class FiniteField(Field): :: sage: F. = GF(2^3) - sage: F.dual_basis([a], check=True) + sage: F.dual_basis([a], check=True) # needs sage.modules Traceback (most recent call last): ... ValueError: basis length should be 3, not 1 - sage: F.dual_basis([a^0, a, a^0 + a], check=True) + sage: F.dual_basis([a^0, a, a^0 + a], check=True) # needs sage.modules Traceback (most recent call last): ... ValueError: value of 'basis' keyword is not a basis diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 0ea8a3b0805..2c5dfbc664f 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings r""" Finite fields @@ -73,7 +73,7 @@ :: - sage: k = GF(5^2,'c'); type(k) + sage: k = GF(5^2,'c'); type(k) # needs sage.libs.linbox One can also give the cardinality `q=p^n` as the tuple `(p,n)`:: @@ -83,7 +83,7 @@ :: - sage: k = GF(2^16,'c'); type(k) + sage: k = GF(2^16,'c'); type(k) # needs sage.libs.ntl :: @@ -125,6 +125,7 @@ :: + sage: # needs sage.libs.linbox sage: k = GF(9,'alpha'); type(k) sage: k.base_ring() @@ -189,6 +190,12 @@ except ImportError: FiniteField_givaro = None +try: + from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e +except ImportError: + FiniteField_ntl_gf2e = None + + from sage.structure.factory import UniqueFactory @@ -437,8 +444,8 @@ class FiniteFieldFactory(UniqueFactory): Using pseudo-Conway polynomials is slow for highly composite extension degrees:: - sage: k = GF(3^120) # long time -- about 3 seconds - sage: GF(3^40).gen().minimal_polynomial()(k.gen()^((3^120-1)/(3^40-1))) # long time because of previous line + sage: k = GF(3^120) # long time (about 3 seconds) + sage: GF(3^40).gen().minimal_polynomial()(k.gen()^((3^120-1)/(3^40-1))) # long time (because of previous line) 0 Before :trac:`17569`, the boolean keyword argument ``conway`` @@ -502,12 +509,12 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, """ EXAMPLES:: - sage: GF.create_key_and_extra_args(9, 'a') + sage: GF.create_key_and_extra_args(9, 'a') # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) The order `q` can also be given as a pair `(p,n)`:: - sage: GF.create_key_and_extra_args((3, 2), 'a') + sage: GF.create_key_and_extra_args((3, 2), 'a') # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) We do not take invalid keyword arguments and raise a value error @@ -521,28 +528,28 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, Moreover, ``repr`` and ``elem_cache`` are ignored when not using givaro:: - sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') + sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') # needs sage.libs.ntl ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) - sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) + sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) # needs sage.libs.ntl ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) - sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') + sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') # needs sage.libs.ntl True We handle extra arguments for the givaro finite field and create unique objects for their defaults:: - sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly') + sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly') # needs sage.libs.linbox True - sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True) + sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True) # needs sage.libs.linbox True - sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False) + sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False) # needs sage.libs.linbox True We explicitly take ``structure``, ``implementation`` and ``prec`` attributes for compatibility with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor` but we ignore them as they are not used, see :trac:`21433`:: - sage: GF.create_key_and_extra_args(9, 'a', structure=None) + sage: GF.create_key_and_extra_args(9, 'a', structure=None) # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) TESTS:: @@ -619,9 +626,9 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, name = normalize_names(1, name) if impl is None: - if order < zech_log_bound: + if order < zech_log_bound and FiniteField_givaro is not None: impl = 'givaro' - elif p == 2: + elif p == 2 and FiniteField_ntl_gf2e is not None: impl = 'ntl' else: impl = 'pari_ffelt' @@ -678,8 +685,8 @@ def create_object(self, version, key, **kwds): We try to create finite fields with various implementations:: sage: k = GF(2, impl='modn') - sage: k = GF(2, impl='givaro') - sage: k = GF(2, impl='ntl') + sage: k = GF(2, impl='givaro') # needs sage.libs.linbox + sage: k = GF(2, impl='ntl') # needs sage.libs.ntl sage: k = GF(2, impl='pari') Traceback (most recent call last): ... @@ -692,18 +699,18 @@ def create_object(self, version, key, **kwds): Traceback (most recent call last): ... ValueError: the 'modn' implementation requires a prime order - sage: k. = GF(2^15, impl='givaro') - sage: k. = GF(2^15, impl='ntl') + sage: k. = GF(2^15, impl='givaro') # needs sage.libs.linbox + sage: k. = GF(2^15, impl='ntl') # needs sage.libs.ntl sage: k. = GF(2^15, impl='pari') sage: k. = GF(3^60, impl='modn') Traceback (most recent call last): ... ValueError: the 'modn' implementation requires a prime order - sage: k. = GF(3^60, impl='givaro') + sage: k. = GF(3^60, impl='givaro') # needs sage.libs.linbox Traceback (most recent call last): ... ValueError: q must be < 2^16 - sage: k. = GF(3^60, impl='ntl') + sage: k. = GF(3^60, impl='ntl') # needs sage.libs.ntl Traceback (most recent call last): ... ValueError: q must be a 2-power @@ -772,7 +779,6 @@ def create_object(self, version, key, **kwds): if impl == 'givaro': K = FiniteField_givaro(order, name, modulus, repr, elem_cache) elif impl == 'ntl': - from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e K = FiniteField_ntl_gf2e(order, name, modulus) elif impl == 'pari_ffelt' or impl == 'pari': from .finite_field_pari_ffelt import FiniteField_pari_ffelt diff --git a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py index 74df0d752dc..c60a7a563a7 100644 --- a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py +++ b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py @@ -213,12 +213,12 @@ def _pari_frobenius(self, k=1): TESTS:: sage: F = FiniteField(37^10, 'a', impl='pari_ffelt') - sage: x = F.random_element() - sage: all(x**(37**k) == F(F._pari_frobenius(k).ffmap(x)) for k in range(1, 30) if k % 10 != 0) + sage: x = F.random_element() # needs sage.modules + sage: all(x**(37**k) == F(F._pari_frobenius(k).ffmap(x)) # needs sage.modules + ....: for k in range(1, 30) if k % 10 != 0) True - sage: F(F._pari_frobenius(-1).ffmap(x))**37 == x + sage: F(F._pari_frobenius(-1).ffmap(x))**37 == x # needs sage.modules True - """ k = k % self.degree() if k == 0: diff --git a/src/sage/rings/finite_rings/finite_field_prime_modn.py b/src/sage/rings/finite_rings/finite_field_prime_modn.py index afd18b7d64d..8bb35604697 100644 --- a/src/sage/rings/finite_rings/finite_field_prime_modn.py +++ b/src/sage/rings/finite_rings/finite_field_prime_modn.py @@ -47,7 +47,7 @@ class FiniteField_prime_modn(FiniteField_generic, integer_mod_ring.IntegerModRin sage: FiniteField(3) Finite Field of size 3 - sage: FiniteField(next_prime(1000)) + sage: FiniteField(next_prime(1000)) # needs sage.rings.finite_rings Finite Field of size 1009 """ def __init__(self, p, check=True, modulus=None): @@ -104,8 +104,11 @@ def _coerce_map_from_(self, S): 5 sage: 12 % 7 5 - sage: ZZ.residue_field(7).hom(GF(7))(1) # See trac 11319 + + sage: ZZ.residue_field(7).hom(GF(7))(1) # See trac 11319 # needs sage.rings.finite_rings 1 + + sage: # needs sage.rings.finite_rings sage.rings.number_field sage: K. = QuadraticField(337) # See trac 11319 sage: pp = K.ideal(13).factor()[0][0] sage: RF13 = K.residue_field(pp) @@ -117,19 +120,19 @@ def _coerce_map_from_(self, S): Check that :trac:`19573` is resolved:: - sage: Integers(9).hom(GF(3)) + sage: Integers(9).hom(GF(3)) # needs sage.rings.finite_rings Natural morphism: From: Ring of integers modulo 9 To: Finite Field of size 3 - sage: Integers(9).hom(GF(5)) + sage: Integers(9).hom(GF(5)) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: natural coercion morphism from Ring of integers modulo 9 to Finite Field of size 5 not defined There is no coercion from a `p`-adic ring to its residue field:: - sage: GF(3).has_coerce_map_from(Zp(3)) + sage: GF(3).has_coerce_map_from(Zp(3)) # needs sage.rings.padics False """ if S is int: @@ -155,6 +158,7 @@ def _convert_map_from_(self, R): EXAMPLES:: + sage: # needs sage.rings.padics sage: GF(3).convert_map_from(Qp(3)) Reduction morphism: From: 3-adic Field with capped relative precision 20 @@ -201,6 +205,7 @@ def is_prime_field(self): sage: k.is_prime_field() True + sage: # needs sage.rings.finite_rings sage: k. = GF(3^2) sage: k.is_prime_field() False @@ -271,6 +276,8 @@ def gen(self, n=0): sage: k = GF(13) sage: k.gen() 1 + + sage: # needs sage.rings.finite_rings sage: k = GF(1009, modulus="primitive") sage: k.gen() # this gives a primitive element 11 @@ -304,6 +311,7 @@ def __iter__(self): We can even start iterating over something that would be too big to actually enumerate:: + sage: # needs sage.rings.finite_rings sage: K = GF(next_prime(2^256)) sage: all = iter(K) sage: next(all) diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index 23240b9d5b1..fa38753d79f 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Finite field morphisms diff --git a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx index acf63449e5a..e141120d918 100644 --- a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx @@ -53,16 +53,16 @@ cdef class FiniteFieldHomomorphism_prime(FiniteFieldHomomorphism_generic): sage: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime sage: k = GF(3) - sage: K. = GF(3^4) - sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f + sage: K. = GF(3^4) # needs sage.rings.finite_rings + sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f # needs sage.rings.finite_rings Ring morphism: From: Finite Field of size 3 To: Finite Field in T of size 3^4 Defn: 1 |--> 1 - sage: k. = GF(3^2) - sage: K. = GF(3^4) - sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f + sage: k. = GF(3^2) # needs sage.rings.finite_rings + sage: K. = GF(3^4) # needs sage.rings.finite_rings + sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: The domain is not a finite prime field @@ -79,6 +79,7 @@ cdef class FiniteFieldHomomorphism_prime(FiniteFieldHomomorphism_generic): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime sage: k = GF(3) sage: K. = GF(3^5) diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index ef629016983..dfce6a12f1a 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Homset for finite fields diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 9a77aadd7c3..b9461bd362e 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -85,7 +85,13 @@ from sage.arith.long cimport ( integer_check_long, integer_check_long_py, is_small_python_int) import sage.rings.rational as rational -from sage.libs.pari.all import pari, PariError + +try: + from sage.libs.pari.all import pari, PariError +except ImportError: + class PariError(Exception): + pass + import sage.rings.integer_ring as integer_ring import sage.rings.rational_field @@ -108,7 +114,6 @@ from sage.structure.parent cimport Parent from sage.arith.misc import CRT as crt from sage.arith.functions import lcm -from sage.groups.generic import discrete_log cdef Integer one_Z = Integer(1) @@ -346,11 +351,11 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: TestSuite(Zmod(2^10 * 3^5)).run() sage: TestSuite(Zmod(2^30 * 3^50 * 5^20)).run() - sage: GF(29)(SR(1/3)) # optional - sage.rings.finite_rings sage.symbolic + sage: GF(29)(SR(1/3)) # needs sage.rings.finite_rings sage.symbolic 10 sage: Integers(30)(QQ['x'](1/7)) 13 - sage: Integers(30)(SR(1/4)) # optional - sage.symbolic + sage: Integers(30)(SR(1/4)) # needs sage.symbolic Traceback (most recent call last): ... ZeroDivisionError: inverse of Mod(4, 30) does not exist @@ -502,7 +507,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: sage: a = Integers(90384098234^3) - sage: factor(a.order()) # optional - sage.libs.pari + sage: factor(a.order()) # needs sage.libs.pari 2^3 * 191^3 * 236607587^3 sage: b = a(2*191) sage: b.is_nilpotent() @@ -542,14 +547,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # needs sage.libs.gap sage: a = Mod(2,19) - sage: gap(a) # optional - sage.libs.gap + sage: gap(a) Z(19) - sage: gap(Mod(3, next_prime(10000))) # optional - sage.libs.gap + sage: gap(Mod(3, next_prime(10000))) Z(10007)^6190 - sage: gap(Mod(3, next_prime(100000))) # optional - sage.libs.gap + sage: gap(Mod(3, next_prime(100000))) ZmodpZObj( 3, 100003 ) - sage: gap(Mod(4, 48)) # optional - sage.libs.gap + sage: gap(Mod(4, 48)) ZmodnZObj( 4, 48 ) """ return '%s*One(ZmodnZ(%s))' % (self, self.__modulus.sageInteger) @@ -560,11 +566,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # optional - magma sage: a = Integers(15)(4) - sage: b = magma(a) # optional - magma - sage: b.Type() # optional - magma + sage: b = magma(a) + sage: b.Type() RngIntResElt - sage: b^2 # optional - magma + sage: b^2 1 """ return '%s!%s'%(self.parent()._magma_init_(magma), self) @@ -580,14 +587,14 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: a._axiom_init_() '4 :: IntegerMod(15)' - sage: aa = axiom(a); aa #optional - axiom + sage: aa = axiom(a); aa # optional - axiom 4 - sage: aa.type() #optional - axiom + sage: aa.type() # optional - axiom IntegerMod 15 - sage: aa = fricas(a); aa #optional - fricas + sage: aa = fricas(a); aa # optional - fricas 4 - sage: aa.typeOf() #optional - fricas + sage: aa.typeOf() # optional - fricas IntegerMod(15) """ @@ -602,18 +609,18 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: K = GF(7) # optional - sage.rings.finite_rings - sage: sage_input(K(5), verify=True) # optional - sage.rings.finite_rings + sage: K = GF(7) + sage: sage_input(K(5), verify=True) # Verified GF(7)(5) - sage: sage_input(K(5) * polygen(K), verify=True) # optional - sage.rings.finite_rings + sage: sage_input(K(5) * polygen(K), verify=True) # Verified R. = GF(7)[] 5*x sage: from sage.misc.sage_input import SageInputBuilder - sage: K(5)._sage_input_(SageInputBuilder(), False) # optional - sage.rings.finite_rings + sage: K(5)._sage_input_(SageInputBuilder(), False) {call: {call: {atomic:GF}({atomic:7})}({atomic:5})} - sage: K(5)._sage_input_(SageInputBuilder(), True) # optional - sage.rings.finite_rings + sage: K(5)._sage_input_(SageInputBuilder(), True) {atomic:5} """ v = sib.int(self.lift()) @@ -649,40 +656,42 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: r = Integers(125) - sage: b = r.multiplicative_generator()^3 # optional - sage.libs.pari - sage: a = b^17 # optional - sage.libs.pari - sage: a.log(b) # optional - sage.libs.pari + sage: b = r.multiplicative_generator()^3 + sage: a = b^17 + sage: a.log(b) 17 - sage: a.log() # optional - sage.libs.pari + sage: a.log() 51 A bigger example:: - sage: FF = FiniteField(2^32 + 61) # optional - sage.rings.finite_rings - sage: c = FF(4294967356) # optional - sage.rings.finite_rings - sage: x = FF(2) # optional - sage.rings.finite_rings - sage: a = c.log(x) # optional - sage.rings.finite_rings - sage: a # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: FF = FiniteField(2^32 + 61) + sage: c = FF(4294967356) + sage: x = FF(2) + sage: a = c.log(x) + sage: a 2147483678 - sage: x^a # optional - sage.rings.finite_rings + sage: x^a 4294967356 An example with a highly composite modulus:: sage: m = 2^99 * 77^7 * 123456789 * 13712923537615486607^2 - sage: (Mod(5,m)^5735816763073854953388147237921).log(5) # optional - sage.libs.pari + sage: (Mod(5,m)^5735816763073854953388147237921).log(5) # needs sage.libs.pari 5735816763073854953388147237921 Errors are generated if the logarithm doesn't exist or the inputs are not units:: - sage: Mod(3, 7).log(Mod(2, 7)) # optional - sage.libs.pari + sage: Mod(3, 7).log(Mod(2, 7)) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 3 found to base 2 modulo 7 - sage: a = Mod(16, 100); b = Mod(4, 100) # optional - sage.libs.pari - sage: a.log(b) # optional - sage.libs.pari + sage: a = Mod(16, 100); b = Mod(4, 100) + sage: a.log(b) Traceback (most recent call last): ... ValueError: logarithm of 16 is not defined since it is not a unit modulo 100 @@ -691,51 +700,52 @@ cdef class IntegerMod_abstract(FiniteRingElement): We check that :trac:`9205` is fixed:: - sage: Mod(5, 9).log(Mod(2, 9)) # optional - sage.libs.pari + sage: Mod(5, 9).log(Mod(2, 9)) # needs sage.libs.pari 5 We test against a bug (side effect on PARI) fixed in :trac:`9438`:: + sage: # needs sage.libs.pari sage: R. = QQ[] - sage: pari(b) # optional - sage.libs.pari + sage: pari(b) b - sage: GF(7)(5).log() # optional - sage.rings.finite_rings + sage: GF(7)(5).log() 5 - sage: pari(b) # optional - sage.libs.pari + sage: pari(b) b We test that :trac:`23927` is fixed:: sage: x = mod(48475563673907791151, 10^20 + 763)^2 sage: e = 25248843418589594761 - sage: (x^e).log(x) == e # optional - sage.libs.pari + sage: (x^e).log(x) == e # needs sage.libs.pari True Examples like this took extremely long before :trac:`32375`:: - sage: (Mod(5, 123337052926643**4) ^ (10^50-1)).log(5) # optional - sage.libs.pari + sage: (Mod(5, 123337052926643**4) ^ (10^50-1)).log(5) # needs sage.libs.pari 99999999999999999999999999999999999999999999999999 We check that non-existence of solutions is detected: No local solutions:: - sage: Mod(1111, 1234567).log(1111**3) # optional - sage.libs.pari + sage: Mod(1111, 1234567).log(1111**3) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 1111 found to base 961261 modulo 1234567 (no solution modulo 9721) Incompatible local solutions:: - sage: Mod(230, 323).log(173) # optional - sage.libs.pari + sage: Mod(230, 323).log(173) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 230 found to base 173 modulo 323 (incompatible local solutions) We test that :trac:`12419` is fixed:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: R(1).factor() # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: R(1).factor() 1 AUTHORS: @@ -781,6 +791,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): if p == 2 and e >= 3: # (ZZ/2^e)* is not cyclic; must not give unsolvable DLPs to Pari try: + from sage.groups.generic import discrete_log v = discrete_log(a_red, b_red, nb) except ValueError: raise ValueError(f"no logarithm of {self} found to base {b} modulo {self.modulus()}" @@ -815,9 +826,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: sage: m = Mod(3, 1568) - sage: v = m.generalised_log(); v # optional - sage.libs.pari + sage: v = m.generalised_log(); v # needs sage.libs.pari [1, 3, 1] - sage: prod([Zmod(1568).unit_gens()[i] ** v[i] for i in [0..2]]) # optional - sage.libs.pari + sage: prod([Zmod(1568).unit_gens()[i] ** v[i] for i in [0..2]]) # needs sage.libs.pari 3 .. SEEALSO:: @@ -866,11 +877,11 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: k = GF(3) # optional - sage.rings.finite_rings - sage: a = k.gen() # optional - sage.rings.finite_rings - sage: a.charpoly('x') # optional - sage.rings.finite_rings + sage: k = GF(3) + sage: a = k.gen() + sage: a.charpoly('x') x + 2 - sage: a + 2 # optional - sage.rings.finite_rings + sage: a + 2 0 AUTHORS: @@ -886,7 +897,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: GF(241, 'a')(1).minpoly() # optional - sage.rings.finite_rings + sage: GF(241, 'a')(1).minpoly() x + 240 """ return self.charpoly(var) @@ -897,7 +908,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: GF(241, 'a')(1).minimal_polynomial(var = 'z') # optional - sage.rings.finite_rings + sage: GF(241, 'a')(1).minimal_polynomial(var = 'z') z + 240 """ return self.minpoly(var) @@ -908,12 +919,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: k = GF(7) # optional - sage.rings.finite_rings - sage: a = k.gen(); a # optional - sage.rings.finite_rings + sage: k = GF(7) + sage: a = k.gen(); a 1 - sage: a.polynomial() # optional - sage.rings.finite_rings + sage: a.polynomial() 1 - sage: type(a.polynomial()) # optional - sage.rings.finite_rings + sage: type(a.polynomial()) # needs sage.rings.finite_rings """ R = self.parent()[var] @@ -926,9 +937,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: k = GF(691) # optional - sage.rings.finite_rings - sage: a = k(389) # optional - sage.rings.finite_rings - sage: a.norm() # optional - sage.rings.finite_rings + sage: k = GF(691) + sage: a = k(389) + sage: a.norm() 389 AUTHORS: @@ -944,9 +955,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: k = GF(691) # optional - sage.rings.finite_rings - sage: a = k(389) # optional - sage.rings.finite_rings - sage: a.trace() # optional - sage.rings.finite_rings + sage: k = GF(691) + sage: a = k(389) + sage: a.trace() 389 AUTHORS: @@ -1027,25 +1038,27 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: Mod(3, 17).is_square() False - sage: Mod(9, 17).is_square() # optional - sage.libs.pari + + sage: # needs sage.libs.pari + sage: Mod(9, 17).is_square() True - sage: Mod(9, 17*19^2).is_square() # optional - sage.libs.pari + sage: Mod(9, 17*19^2).is_square() True - sage: Mod(-1, 17^30).is_square() # optional - sage.libs.pari + sage: Mod(-1, 17^30).is_square() True - sage: Mod(1/9, next_prime(2^40)).is_square() # optional - sage.libs.pari + sage: Mod(1/9, next_prime(2^40)).is_square() True - sage: Mod(1/25, next_prime(2^90)).is_square() # optional - sage.libs.pari + sage: Mod(1/25, next_prime(2^90)).is_square() True TESTS:: - sage: Mod(1/25, 2^8).is_square() # optional - sage.libs.pari + sage: Mod(1/25, 2^8).is_square() # needs sage.libs.pari True - sage: Mod(1/25, 2^40).is_square() # optional - sage.libs.pari + sage: Mod(1/25, 2^40).is_square() # needs sage.libs.pari True - sage: for p,q,r in cartesian_product_iterator([[3,5],[11,13],[17,19]]): # long time # optional - sage.libs.pari + sage: for p,q,r in cartesian_product_iterator([[3,5],[11,13],[17,19]]): # long time, needs sage.libs.pari ....: for ep,eq,er in cartesian_product_iterator([[0,1,2,3],[0,1,2,3],[0,1,2,3]]): ....: for e2 in [0, 1, 2, 3, 4]: ....: n = p^ep * q^eq * r^er * 2^e2 @@ -1123,16 +1136,18 @@ cdef class IntegerMod_abstract(FiniteRingElement): 86 sage: mod(7, 18).sqrt() 5 - sage: a = mod(14, 5^60).sqrt() # optional - sage.libs.pari - sage: a*a # optional - sage.libs.pari + + sage: # needs sage.libs.pari + sage: a = mod(14, 5^60).sqrt() + sage: a*a 14 - sage: mod(15, 389).sqrt(extend=False) # optional - sage.libs.pari + sage: mod(15, 389).sqrt(extend=False) Traceback (most recent call last): ... ValueError: self must be a square - sage: Mod(1/9, next_prime(2^40)).sqrt()^(-2) # optional - sage.libs.pari + sage: Mod(1/9, next_prime(2^40)).sqrt()^(-2) 9 - sage: Mod(1/25, next_prime(2^90)).sqrt()^(-2) # optional - sage.libs.pari + sage: Mod(1/25, next_prime(2^90)).sqrt()^(-2) 25 :: @@ -1147,7 +1162,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: y = x.sqrt(); y sqrt359 sage: y.parent() - Univariate Quotient Polynomial Ring in sqrt359 over Ring of integers modulo 360 with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in sqrt359 over + Ring of integers modulo 360 with modulus x^2 + 1 sage: y^2 359 @@ -1166,24 +1182,26 @@ cdef class IntegerMod_abstract(FiniteRingElement): :: + sage: # needs sage.libs.pari sage: R = Integers(5*13^3*37); R Ring of integers modulo 406445 - sage: v = R(-1).sqrt(all=True); v # optional - sage.libs.pari + sage: v = R(-1).sqrt(all=True); v [78853, 111808, 160142, 193097, 213348, 246303, 294637, 327592] - sage: [x^2 for x in v] # optional - sage.libs.pari + sage: [x^2 for x in v] [406444, 406444, 406444, 406444, 406444, 406444, 406444, 406444] - sage: v = R(169).sqrt(all=True); min(v), -max(v), len(v) # optional - sage.libs.pari + sage: v = R(169).sqrt(all=True); min(v), -max(v), len(v) (13, 13, 104) - sage: all(x^2 == 169 for x in v) # optional - sage.libs.pari + sage: all(x^2 == 169 for x in v) True :: - sage: t = FiniteField(next_prime(2^100))(4) # optional - sage.rings.finite_rings - sage: t.sqrt(extend=False, all=True) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: t = FiniteField(next_prime(2^100))(4) + sage: t.sqrt(extend=False, all=True) [2, 1267650600228229401496703205651] - sage: t = FiniteField(next_prime(2^100))(2) # optional - sage.rings.finite_rings - sage: t.sqrt(extend=False, all=True) # optional - sage.rings.finite_rings + sage: t = FiniteField(next_prime(2^100))(2) + sage: t.sqrt(extend=False, all=True) [] Modulo a power of 2:: @@ -1375,39 +1393,42 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: K = GF(31) # optional - sage.rings.finite_rings - sage: a = K(22) # optional - sage.rings.finite_rings - sage: K(22).nth_root(7) # optional - sage.rings.finite_rings + sage: K = GF(31) + sage: a = K(22) + sage: K(22).nth_root(7) 13 - sage: K(25).nth_root(5) # optional - sage.rings.finite_rings + sage: K(25).nth_root(5) 5 - sage: K(23).nth_root(3) # optional - sage.rings.finite_rings + sage: K(23).nth_root(3) 29 - sage: mod(225, 2^5*3^2).nth_root(4, all=True) # optional - sage.rings.padics + + sage: # needs sage.rings.padics + sage: mod(225, 2^5*3^2).nth_root(4, all=True) [225, 129, 33, 63, 255, 159, 9, 201, 105, 279, 183, 87, 81, 273, 177, 207, 111, 15, 153, 57, 249, 135, 39, 231] - sage: mod(275, 2^5*7^4).nth_root(7, all=True) # optional - sage.rings.padics + sage: mod(275, 2^5*7^4).nth_root(7, all=True) [58235, 25307, 69211, 36283, 3355, 47259, 14331] - sage: mod(1,8).nth_root(2, all=True) # optional - sage.rings.padics + sage: mod(1,8).nth_root(2, all=True) [1, 7, 5, 3] - sage: mod(4,8).nth_root(2, all=True) # optional - sage.rings.padics + sage: mod(4,8).nth_root(2, all=True) [2, 6] - sage: mod(1,16).nth_root(4, all=True) # optional - sage.rings.padics + sage: mod(1,16).nth_root(4, all=True) [1, 15, 13, 3, 9, 7, 5, 11] - sage: (mod(22,31)^200).nth_root(200) # optional - sage.groups + + sage: (mod(22,31)^200).nth_root(200) 5 - sage: mod(3,6).nth_root(0, all=True) # optional - sage.rings.padics + sage: mod(3,6).nth_root(0, all=True) [] sage: mod(3,6).nth_root(0) Traceback (most recent call last): ... ValueError - sage: mod(1,6).nth_root(0, all=True) # optional - sage.rings.padics + sage: mod(1,6).nth_root(0, all=True) [1, 2, 3, 4, 5] TESTS:: - sage: for p in [1009,2003,10007,100003]: # optional - sage.rings.finite_rings + sage: for p in [1009,2003,10007,100003]: # needs sage.rings.finite_rings ....: K = GF(p) ....: for r in (p-1).divisors(): ....: if r == 1: continue @@ -1417,7 +1438,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): ....: if (y^41).nth_root(41*r)**(41*r) != y^41: raise RuntimeError ....: if (y^307).nth_root(307*r)**(307*r) != y^307: raise RuntimeError - sage: for t in range(200): # optional - sage.libs.pari + sage: for t in range(200): # needs sage.libs.pari ....: n = randint(1,2^63) ....: K = Integers(n) ....: b = K.random_element() @@ -1432,12 +1453,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): We check that :trac:`13172` is resolved:: - sage: mod(-1, 4489).nth_root(2, all=True) # optional - sage.rings.padics + sage: mod(-1, 4489).nth_root(2, all=True) # needs sage.rings.padics [] We check that :trac:`32084` is fixed:: - sage: mod(24, 25).nth_root(50)^50 # optional - sage.rings.padics + sage: mod(24, 25).nth_root(50)^50 # needs sage.rings.padics 24 Check that the code path cunningham might be used:: @@ -1574,7 +1595,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): TESTS:: - sage: for n in range(2,100): # long time + sage: for n in range(2,100): # long time ....: K = Integers(n) ....: elist = list(range(1,min(2*n+2,100))) ....: for e in random_sublist(elist, 5/len(elist)): @@ -1623,11 +1644,11 @@ cdef class IntegerMod_abstract(FiniteRingElement): This method is also inherited by prime finite fields elements:: - sage: k = GF(97) # optional - sage.rings.finite_rings - sage: a = k(RationalField()('2/3')) # optional - sage.rings.finite_rings - sage: a # optional - sage.rings.finite_rings + sage: k = GF(97) + sage: a = k(RationalField()('2/3')) + sage: a 33 - sage: a.rational_reconstruction() # optional - sage.rings.finite_rings + sage: a.rational_reconstruction() 2/3 """ return self.lift().rational_reconstruction(self.modulus()) @@ -1737,16 +1758,16 @@ cdef class IntegerMod_abstract(FiniteRingElement): True sage: mod(3, 4).is_primitive_root() True - sage: mod(2, 7).is_primitive_root() # optional - sage.libs.pari + sage: mod(2, 7).is_primitive_root() False - sage: mod(3, 98).is_primitive_root() # optional - sage.libs.pari + sage: mod(3, 98).is_primitive_root() # needs sage.libs.pari True - sage: mod(11, 1009^2).is_primitive_root() # optional - sage.libs.pari + sage: mod(11, 1009^2).is_primitive_root() # needs sage.libs.pari True TESTS:: - sage: for p in prime_range(3,12): # optional - sage.libs.pari + sage: for p in prime_range(3,12): # needs sage.libs.pari ....: for k in range(1,4): ....: for even in [1,2]: ....: n = even*p^k @@ -1759,14 +1780,14 @@ cdef class IntegerMod_abstract(FiniteRingElement): `0` is not a primitive root mod `n` (:trac:`23624`) except for `n=0`:: - sage: mod(0, 17).is_primitive_root() # optional - sage.libs.pari + sage: mod(0, 17).is_primitive_root() False - sage: all(not mod(0, n).is_primitive_root() for n in srange(2, 20)) # optional - sage.libs.pari + sage: all(not mod(0, n).is_primitive_root() for n in srange(2, 20)) # needs sage.libs.pari True sage: mod(0, 1).is_primitive_root() True - sage: all(not mod(p^j, p^k).is_primitive_root() # optional - sage.libs.pari + sage: all(not mod(p^j, p^k).is_primitive_root() # needs sage.libs.pari ....: for p in prime_range(3, 12) ....: for k in srange(1, 4) ....: for j in srange(0, k)) @@ -1821,11 +1842,11 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: Mod(-1, 5).multiplicative_order() # optional - sage.libs.pari + sage: Mod(-1, 5).multiplicative_order() # needs sage.libs.pari 2 - sage: Mod(1, 5).multiplicative_order() # optional - sage.libs.pari + sage: Mod(1, 5).multiplicative_order() # needs sage.libs.pari 1 - sage: Mod(0, 5).multiplicative_order() # optional - sage.libs.pari + sage: Mod(0, 5).multiplicative_order() # needs sage.libs.pari Traceback (most recent call last): ... ArithmeticError: multiplicative order of 0 not defined @@ -1903,7 +1924,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: GF(7)(3) // 5 # optional - sage.rings.finite_rings + sage: GF(7)(3) // 5 2 """ return self._mul_(~right) @@ -1930,9 +1951,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: F. = GF(13) # optional - sage.rings.finite_rings - sage: V = F.vector_space(map=False) # optional - sage.rings.finite_rings - sage: V(a) # optional - sage.rings.finite_rings + sage: F. = GF(13) + sage: V = F.vector_space(map=False) # needs sage.modules + sage: V(a) # needs sage.modules (1) """ return self.parent().vector_space(map=False)([self]) @@ -1975,8 +1996,8 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): r""" EXAMPLES:: - sage: p = next_prime(2^32) # optional - sage.libs.pari - sage: GF(p)(int(p + 1)) # optional - sage.rings.finite_rings + sage: p = next_prime(2^32) # needs sage.libs.pari + sage: GF(p)(int(p + 1)) # needs sage.libs.pari sage.rings.finite_rings 1 """ mpz_set_si(self.value, value) @@ -2248,9 +2269,9 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sage: R = Integers(10^10) sage: R(2)^1000 5668069376 - sage: p = next_prime(11^10) # optional - sage.libs.pari - sage: R = Integers(p) # optional - sage.libs.pari - sage: R(9876)^(p-1) # optional - sage.libs.pari + sage: p = next_prime(11^10) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(9876)^(p-1) # needs sage.libs.pari 1 sage: mod(3, 10^100)^-2 8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889 @@ -2263,14 +2284,14 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): We define ``0^0`` to be unity, :trac:`13894`:: - sage: p = next_prime(11^10) # optional - sage.libs.pari - sage: R = Integers(p) # optional - sage.libs.pari - sage: R(0)^0 # optional - sage.libs.pari + sage: p = next_prime(11^10) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(0)^0 1 The value returned from ``0^0`` should belong to our ring:: - sage: type(R(0)^0) == type(R(0)) # optional - sage.libs.pari + sage: type(R(0)^0) == type(R(0)) True When the modulus is ``1``, the only element in the ring is @@ -2906,16 +2927,18 @@ cdef class IntegerMod_int(IntegerMod_abstract): 86 sage: mod(7, 18).sqrt() 5 - sage: a = mod(14, 5^60).sqrt() # optional - sage.libs.pari - sage: a*a # optional - sage.libs.pari + + sage: # needs sage.libs.pari + sage: a = mod(14, 5^60).sqrt() + sage: a*a 14 sage: mod(15, 389).sqrt(extend=False) Traceback (most recent call last): ... ValueError: self must be a square - sage: Mod(1/9, next_prime(2^40)).sqrt()^(-2) # optional - sage.libs.pari + sage: Mod(1/9, next_prime(2^40)).sqrt()^(-2) 9 - sage: Mod(1/25, next_prime(2^90)).sqrt()^(-2) # optional - sage.libs.pari + sage: Mod(1/25, next_prime(2^90)).sqrt()^(-2) 25 :: @@ -2947,20 +2970,21 @@ cdef class IntegerMod_int(IntegerMod_abstract): [1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359] sage: R(0).sqrt(all=True) [0, 60, 120, 180, 240, 300] - sage: GF(107)(0).sqrt(all=True) # optional - sage.rings.finite_rings + sage: GF(107)(0).sqrt(all=True) [0] :: + sage: # needs sage.libs.pari sage: R = Integers(5*13^3*37); R Ring of integers modulo 406445 - sage: v = R(-1).sqrt(all=True); v # optional - sage.libs.pari + sage: v = R(-1).sqrt(all=True); v [78853, 111808, 160142, 193097, 213348, 246303, 294637, 327592] - sage: [x^2 for x in v] # optional - sage.libs.pari + sage: [x^2 for x in v] [406444, 406444, 406444, 406444, 406444, 406444, 406444, 406444] - sage: v = R(169).sqrt(all=True); min(v), -max(v), len(v) # optional - sage.libs.pari + sage: v = R(169).sqrt(all=True); min(v), -max(v), len(v) (13, 13, 104) - sage: all(x^2 == 169 for x in v) # optional - sage.libs.pari + sage: all(x^2 == 169 for x in v) True Modulo a power of 2:: @@ -2979,7 +3003,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): Check for :trac:`30797`:: - sage: GF(103)(-1).sqrt(extend=False, all=True) # optional - sage.rings.finite_rings + sage: GF(103)(-1).sqrt(extend=False, all=True) [] """ cdef int_fast32_t i, n = self.__modulus.int32 @@ -3546,9 +3570,9 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: R = Integers(10) sage: R(2)^10 4 - sage: p = next_prime(10^5) # optional - sage.libs.pari - sage: R = Integers(p) # optional - sage.libs.pari - sage: R(1234)^(p - 1) # optional - sage.libs.pari + sage: p = next_prime(10^5) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(1234)^(p - 1) # needs sage.libs.pari 1 sage: R = Integers(17^5) sage: R(17)^5 @@ -3574,14 +3598,14 @@ cdef class IntegerMod_int64(IntegerMod_abstract): We define ``0^0`` to be unity, :trac:`13894`:: - sage: p = next_prime(10^5) # optional - sage.libs.pari - sage: R = Integers(p) # optional - sage.libs.pari - sage: R(0)^0 # optional - sage.libs.pari + sage: p = next_prime(10^5) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(0)^0 1 The value returned from ``0^0`` should belong to our ring:: - sage: type(R(0)^0) == type(R(0)) # optional - sage.libs.pari + sage: type(R(0)^0) == type(R(0)) True When the modulus is ``1``, the only element in the ring is @@ -3902,10 +3926,10 @@ def square_root_mod_prime_power(IntegerMod_abstract a, p, e): :: sage: a = Mod(72, 97^10) - sage: b = square_root_mod_prime_power(a, 97, 10) # optional - sage.libs.pari - sage: b^2 == a # optional - sage.libs.pari + sage: b = square_root_mod_prime_power(a, 97, 10) # needs sage.libs.pari + sage: b^2 == a # needs sage.libs.pari True - sage: mod(100, 5^7).sqrt()^2 # optional - sage.libs.pari + sage: mod(100, 5^7).sqrt()^2 # needs sage.libs.pari 100 TESTS: @@ -3913,15 +3937,15 @@ def square_root_mod_prime_power(IntegerMod_abstract a, p, e): A big example for the binary case (:trac:`33961`):: sage: y = Mod(-7, 2^777) - sage: hex(y.sqrt()^2 - y) # optional - sage.libs.pari + sage: hex(y.sqrt()^2 - y) # needs sage.libs.pari '0x0' Testing with random squares in random rings:: - sage: p = random_prime(999) # optional - sage.libs.pari - sage: e = randrange(1, 999) # optional - sage.libs.pari - sage: x = Zmod(p^e).random_element() # optional - sage.libs.pari - sage: (x^2).sqrt()^2 == x^2 # optional - sage.libs.pari + sage: p = random_prime(999) + sage: e = randrange(1, 999) + sage: x = Zmod(p^e).random_element() + sage: (x^2).sqrt()^2 == x^2 # needs sage.libs.pari True """ if a.is_zero() or a.is_one(): @@ -4016,7 +4040,7 @@ cpdef square_root_mod_prime(IntegerMod_abstract a, p=None): :: sage: from sage.rings.finite_rings.integer_mod import square_root_mod_prime # sqrt() uses brute force for small p - sage: all(square_root_mod_prime(a*a)^2 == a*a # optional - sage.libs.pari + sage: all(square_root_mod_prime(a*a)^2 == a*a # needs sage.libs.pari ....: for p in prime_range(100) ....: for a in Integers(p)) True @@ -4099,7 +4123,7 @@ def lucas_q1(mm, IntegerMod_abstract P): TESTS:: sage: from sage.rings.finite_rings.integer_mod import lucas_q1 - sage: all(lucas_q1(k, a) == BinaryRecurrenceSequence(a, -1, 2, a)(k) # optional - sage.combinat + sage: all(lucas_q1(k, a) == BinaryRecurrenceSequence(a, -1, 2, a)(k) # needs sage.combinat sage.modules ....: for a in Integers(23) ....: for k in range(13)) True @@ -4167,7 +4191,7 @@ def lucas(k, P, Q=1, n=None): sage: p = randint(0,100000) sage: q = randint(0,100000) sage: n = randint(1,100) - sage: all(lucas(k, p, q, n)[0] == Mod(lucas_number2(k, p, q), n) # optional - sage.combinat + sage: all(lucas(k, p, q, n)[0] == Mod(lucas_number2(k, p, q), n) # needs sage.combinat sage.libs.gap ....: for k in Integers(20)) True sage: from sage.rings.finite_rings.integer_mod import lucas @@ -4175,7 +4199,8 @@ def lucas(k, P, Q=1, n=None): sage: q = randint(0,100000) sage: n = randint(1,100) sage: k = randint(0,100) - sage: lucas(k, p, q, n) == [Mod(lucas_number2(k, p, q), n), Mod(q^(int(k/2)), n)] # optional - sage.combinat + sage: lucas(k, p, q, n) == [Mod(lucas_number2(k, p, q), n), # needs sage.combinat sage.libs.gap + ....: Mod(q^(int(k/2)), n)] True EXAMPLES:: @@ -4453,7 +4478,7 @@ cdef class IntegerMod_to_Integer(Map): EXAMPLES:: - sage: ZZ.convert_map_from(GF(2)) # optional - sage.rings.finite_rings + sage: ZZ.convert_map_from(GF(2)) Lifting map: From: Finite Field of size 2 To: Integer Ring @@ -4465,7 +4490,7 @@ cdef class IntegerMod_to_Integer(Map): Lifting maps are morphisms in the category of sets (see :trac:`15618`):: - sage: ZZ.convert_map_from(GF(2)).parent() # optional - sage.rings.finite_rings + sage: ZZ.convert_map_from(GF(2)).parent() Set of Morphisms from Finite Field of size 2 to Integer Ring in Category of sets """ import sage.categories.homset diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index f34faa4e9a9..20a876f4192 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -16,16 +16,16 @@ :: sage: r = Integers(7) - sage: s = GF(7) # optional - sage.rings.finite_rings - sage: r.has_coerce_map_from(s) # optional - sage.rings.finite_rings + sage: s = GF(7) + sage: r.has_coerce_map_from(s) False - sage: s.has_coerce_map_from(r) # optional - sage.rings.finite_rings + sage: s.has_coerce_map_from(r) # needs sage.rings.finite_rings True - sage: s(1) + r(1) # optional - sage.rings.finite_rings + sage: s(1) + r(1) # needs sage.rings.finite_rings 2 - sage: parent(s(1) + r(1)) # optional - sage.rings.finite_rings + sage: parent(s(1) + r(1)) # needs sage.rings.finite_rings Finite Field of size 7 - sage: parent(r(1) + s(1)) # optional - sage.rings.finite_rings + sage: parent(r(1) + s(1)) # needs sage.rings.finite_rings Finite Field of size 7 We list the elements of `\ZZ/3\ZZ`:: @@ -72,7 +72,11 @@ import sage.rings.integer_ring as integer_ring import sage.rings.quotient_ring as quotient_ring -from sage.libs.pari.all import pari, PariError +try: + from sage.libs.pari.all import pari, PariError +except ImportError: + class PariError(Exception): + pass from sage.misc.cachefunc import cached_method @@ -259,9 +263,9 @@ def is_IntegerModRing(x): Use isinstance(..., sage.rings.abc.IntegerModRing) instead. See https://github.com/sagemath/sage/issues/32606 for details. True - sage: is_IntegerModRing(GF(13)) # optional - sage.rings.finite_rings + sage: is_IntegerModRing(GF(13)) True - sage: is_IntegerModRing(GF(4, 'a')) # optional - sage.rings.finite_rings + sage: is_IntegerModRing(GF(4, 'a')) # needs sage.rings.finite_rings False sage: is_IntegerModRing(10) False @@ -290,9 +294,9 @@ def _unit_gens_primepowercase(p, r): sage: from sage.rings.finite_rings.integer_mod_ring import _unit_gens_primepowercase sage: _unit_gens_primepowercase(2, 3) [(7, 2), (5, 2)] - sage: _unit_gens_primepowercase(17, 1) # optional - sage.libs.pari + sage: _unit_gens_primepowercase(17, 1) # needs sage.libs.pari [(3, 16)] - sage: _unit_gens_primepowercase(3, 3) # optional - sage.libs.pari + sage: _unit_gens_primepowercase(3, 3) # needs sage.libs.pari [(2, 18)] """ pr = p**r @@ -344,14 +348,16 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. 29 sage: FF.order() 29 - sage: gens = FF.unit_gens() # optional - sage.groups - sage: a = gens[0] # optional - sage.groups - sage: a # optional - sage.groups + + sage: # needs sage.groups + sage: gens = FF.unit_gens() + sage: a = gens[0] + sage: a 2 - sage: a.is_square() # optional - sage.groups + sage: a.is_square() False - sage: def pow(i): return a**i # optional - sage.groups - sage: [pow(i) for i in range(16)] # optional - sage.groups + sage: def pow(i): return a**i + sage: [pow(i) for i in range(16)] [1, 2, 4, 8, 16, 3, 6, 12, 24, 19, 9, 18, 7, 14, 28, 27] sage: TestSuite(FF).run() @@ -404,24 +410,27 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. 16 sage: Z16.characteristic() 16 - sage: gens = Z16.unit_gens() # optional - sage.groups - sage: gens # optional - sage.groups + + sage: # needs sage.groups + sage: gens = Z16.unit_gens() + sage: gens (15, 5) - sage: a = gens[0] # optional - sage.groups - sage: b = gens[1] # optional - sage.groups - sage: def powa(i): return a**i # optional - sage.groups - sage: def powb(i): return b**i # optional - sage.groups - sage: gp_exp = FF.unit_group_exponent() # optional - sage.groups - sage: gp_exp # optional - sage.groups + sage: a = gens[0] + sage: b = gens[1] + sage: def powa(i): return a**i + sage: def powb(i): return b**i + sage: gp_exp = FF.unit_group_exponent() + sage: gp_exp 28 - sage: [powa(i) for i in range(15)] # optional - sage.groups + sage: [powa(i) for i in range(15)] [1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1] - sage: [powb(i) for i in range(15)] # optional - sage.groups + sage: [powb(i) for i in range(15)] [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9] - sage: a.multiplicative_order() # optional - sage.groups + sage: a.multiplicative_order() 2 - sage: b.multiplicative_order() # optional - sage.groups + sage: b.multiplicative_order() 4 + sage: TestSuite(Z16).run() Saving and loading:: @@ -639,22 +648,23 @@ def multiplicative_subgroups(self): EXAMPLES:: - sage: Integers(5).multiplicative_subgroups() # optional - sage.groups + sage: # needs sage.groups + sage: Integers(5).multiplicative_subgroups() ((2,), (4,), ()) - sage: Integers(15).multiplicative_subgroups() # optional - sage.groups + sage: Integers(15).multiplicative_subgroups() ((11, 7), (11, 4), (2,), (11,), (14,), (7,), (4,), ()) - sage: Integers(2).multiplicative_subgroups() # optional - sage.groups + sage: Integers(2).multiplicative_subgroups() ((),) - sage: len(Integers(341).multiplicative_subgroups()) # optional - sage.groups + sage: len(Integers(341).multiplicative_subgroups()) 80 TESTS:: - sage: IntegerModRing(1).multiplicative_subgroups() # optional - sage.groups + sage: IntegerModRing(1).multiplicative_subgroups() # needs sage.groups ((),) - sage: IntegerModRing(2).multiplicative_subgroups() # optional - sage.groups + sage: IntegerModRing(2).multiplicative_subgroups() # needs sage.groups ((),) - sage: IntegerModRing(3).multiplicative_subgroups() # optional - sage.groups + sage: IntegerModRing(3).multiplicative_subgroups() # needs sage.groups ((2,), ()) """ return tuple(tuple(g.value() for g in H.gens()) @@ -668,7 +678,7 @@ def is_integral_domain(self, proof=None): sage: Integers(389).is_integral_domain() True - sage: Integers(389^2).is_integral_domain() # optional - sage.libs.pari + sage: Integers(389^2).is_integral_domain() # needs sage.libs.pari False TESTS: @@ -689,7 +699,7 @@ def is_unique_factorization_domain(self, proof=None): sage: Integers(389).is_unique_factorization_domain() True - sage: Integers(389^2).is_unique_factorization_domain() # optional - sage.libs.pari + sage: Integers(389^2).is_unique_factorization_domain() # needs sage.libs.pari False """ return self.is_field(proof) @@ -791,10 +801,10 @@ def field(self): sage: R = Integers(7); R Ring of integers modulo 7 - sage: R.field() # optional - sage.rings.finite_rings + sage: R.field() Finite Field of size 7 sage: R = Integers(9) - sage: R.field() # optional - sage.rings.finite_rings + sage: R.field() Traceback (most recent call last): ... ValueError: self must be a field @@ -828,8 +838,8 @@ def _pseudo_fraction_field(self): This should be very fast:: - sage: R. = Integers(next_prime(10^101)*next_prime(10^100))[] # optional - sage.libs.pari - sage: x / R.base_ring()(2) # optional - sage.libs.pari + sage: R. = Integers(next_prime(10^101)*next_prime(10^100))[] # needs sage.libs.pari + sage: x / R.base_ring()(2) # needs sage.libs.pari 500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000401*x """ return self @@ -848,18 +858,18 @@ def multiplicative_group_is_cyclic(self): sage: R.multiplicative_group_is_cyclic() True sage: R = Integers(9) - sage: R.multiplicative_group_is_cyclic() # optional - sage.libs.pari + sage: R.multiplicative_group_is_cyclic() # needs sage.libs.pari True - sage: Integers(8).multiplicative_group_is_cyclic() # optional - sage.libs.pari + sage: Integers(8).multiplicative_group_is_cyclic() False - sage: Integers(4).multiplicative_group_is_cyclic() # optional - sage.libs.pari + sage: Integers(4).multiplicative_group_is_cyclic() True - sage: Integers(25*3).multiplicative_group_is_cyclic() # optional - sage.libs.pari + sage: Integers(25*3).multiplicative_group_is_cyclic() # needs sage.libs.pari False We test that :trac:`5250` is fixed:: - sage: Integers(162).multiplicative_group_is_cyclic() # optional - sage.libs.pari + sage: Integers(162).multiplicative_group_is_cyclic() # needs sage.libs.pari True """ n = self.order() @@ -884,26 +894,27 @@ def multiplicative_generator(self): EXAMPLES:: + sage: # needs sage.groups sage.libs.pari sage: R = Integers(7); R Ring of integers modulo 7 - sage: R.multiplicative_generator() # optional - sage.libs.pari + sage: R.multiplicative_generator() 3 sage: R = Integers(9) - sage: R.multiplicative_generator() # optional - sage.libs.pari + sage: R.multiplicative_generator() 2 - sage: Integers(8).multiplicative_generator() # optional - sage.libs.pari + sage: Integers(8).multiplicative_generator() Traceback (most recent call last): ... ValueError: multiplicative group of this ring is not cyclic - sage: Integers(4).multiplicative_generator() # optional - sage.libs.pari + sage: Integers(4).multiplicative_generator() 3 - sage: Integers(25*3).multiplicative_generator() # optional - sage.libs.pari + sage: Integers(25*3).multiplicative_generator() Traceback (most recent call last): ... ValueError: multiplicative group of this ring is not cyclic - sage: Integers(25*3).unit_gens() # optional - sage.libs.pari + sage: Integers(25*3).unit_gens() (26, 52) - sage: Integers(162).unit_gens() # optional - sage.libs.pari + sage: Integers(162).unit_gens() (83,) """ try: @@ -928,9 +939,9 @@ def quadratic_nonresidue(self): EXAMPLES:: sage: R = Integers(17) - sage: R.quadratic_nonresidue() # optional - sage.libs.pari + sage: R.quadratic_nonresidue() # needs sage.libs.pari 3 - sage: R(3).is_square() # optional - sage.libs.pari + sage: R(3).is_square() False """ try: @@ -955,18 +966,19 @@ def square_roots_of_one(self): sage: R = Integers(2^10) sage: [x for x in R if x^2 == 1] [1, 511, 513, 1023] - sage: R.square_roots_of_one() # optional - sage.libs.pari + sage: R.square_roots_of_one() (1, 511, 513, 1023) :: - sage: v = Integers(9*5).square_roots_of_one(); v # optional - sage.libs.pari + sage: # needs sage.libs.pari + sage: v = Integers(9*5).square_roots_of_one(); v (1, 19, 26, 44) - sage: [x^2 for x in v] # optional - sage.libs.pari + sage: [x^2 for x in v] [1, 1, 1, 1] - sage: v = Integers(9*5*8).square_roots_of_one(); v # optional - sage.libs.pari + sage: v = Integers(9*5*8).square_roots_of_one(); v (1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359) - sage: [x^2 for x in v] # optional - sage.libs.pari + sage: [x^2 for x in v] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ try: @@ -1133,7 +1145,7 @@ def _pari_order(self): EXAMPLES:: - sage: Zmod(87)._pari_order() # optional - sage.libs.pari + sage: Zmod(87)._pari_order() # needs sage.libs.pari 87 """ try: @@ -1146,14 +1158,15 @@ def _element_constructor_(self, x): """ TESTS:: - sage: K2 = GF(2) # optional - sage.rings.finite_rings - sage: K3 = GF(3) # optional - sage.rings.finite_rings - sage: K8 = GF(8, 'a') # optional - sage.rings.finite_rings - sage: K8(5) # indirect doctest # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K2 = GF(2) + sage: K3 = GF(3) + sage: K8 = GF(8, 'a') + sage: K8(5) # indirect doctest 1 - sage: K8('a+1') # optional - sage.rings.finite_rings + sage: K8('a+1') a + 1 - sage: K8(K2(1)) # optional - sage.rings.finite_rings + sage: K8(K2(1)) 1 The following test refers to :trac:`6468`:: @@ -1165,7 +1178,7 @@ def _element_constructor_(self, x): ....: raise PariError sage: P = foo_parent() sage: F = foo(P) - sage: GF(2)(F) # optional - sage.rings.finite_rings + sage: GF(2)(F) Traceback (most recent call last): ... TypeError: error coercing to finite field @@ -1173,21 +1186,21 @@ def _element_constructor_(self, x): The following test refers to :trac:`8970`:: sage: R = Zmod(13); a = R(2) - sage: a == R(gap(a)) # optional - sage.libs.gap + sage: a == R(gap(a)) # needs sage.libs.gap True libgap interface (:trac:`23714`):: - sage: a = libgap.eval("Z(13)^2") # optional - sage.libs.gap - sage: a.sage() # optional - sage.libs.gap + sage: a = libgap.eval("Z(13)^2") # needs sage.libs.gap + sage: a.sage() # needs sage.libs.gap 4 - sage: libgap(a.sage()) == a # optional - sage.libs.gap + sage: libgap(a.sage()) == a # needs sage.libs.gap True better syntax for libgap interface:: - sage: a = libgap.Z(13)^2 # optional - sage.libs.gap - sage: libgap(a.sage()) == a # optional - sage.libs.gap + sage: a = libgap.Z(13)^2 # needs sage.libs.gap + sage: libgap(a.sage()) == a # needs sage.libs.gap True """ try: @@ -1225,7 +1238,7 @@ def _coerce_map_from_(self, S): EXAMPLES:: sage: R = Integers(15) - sage: f = R.coerce_map_from(Integers(450)); f # indirect doctest + sage: f = R.coerce_map_from(Integers(450)); f # indirect doctest Natural morphism: From: Ring of integers modulo 450 To: Ring of integers modulo 15 @@ -1296,7 +1309,7 @@ def _convert_map_from_(self, other): EXAMPLES:: - sage: Zmod(81).convert_map_from(Qp(3)) # optional - sage.rings.padics + sage: Zmod(81).convert_map_from(Qp(3)) # needs sage.rings.padics Reduction morphism: From: 3-adic Field with capped relative precision 20 To: Ring of integers modulo 81 @@ -1321,9 +1334,9 @@ def __richcmp__(self, other, op): Ring of integers modulo 13 sage: Z11 == Z11, Z11 == Z12, Z11 == Z13 (True, False, False) - sage: F = GF(11); F # optional - sage.rings.finite_rings + sage: F = GF(11); F Finite Field of size 11 - sage: Z11 == F # optional - sage.rings.finite_rings + sage: Z11 == F False In :trac:`15229`, the following was implemented:: @@ -1332,7 +1345,7 @@ def __richcmp__(self, other, op): sage: R2 = IntegerModRing(5, is_field=True) sage: R1 is R2 # used to return False True - sage: R2 == GF(5) # optional - sage.rings.finite_rings + sage: R2 == GF(5) False """ @@ -1344,7 +1357,7 @@ def __richcmp__(self, other, op): try: c = bool(other.__class__.__base__ != self.__class__.__base__) except AttributeError: # __base__ does not always exists - c = bool(type(other) != type(self)) + c = bool(type(other) is not type(self)) if c: return NotImplemented return richcmp(self.__order, other.__order, op) @@ -1366,12 +1379,12 @@ def unit_gens(self, **kwds): EXAMPLES:: sage: R = IntegerModRing(18) - sage: R.unit_gens() # optional - sage.groups + sage: R.unit_gens() # needs sage.groups (11,) sage: R = IntegerModRing(17) - sage: R.unit_gens() # optional - sage.groups + sage: R.unit_gens() # needs sage.groups (3,) - sage: IntegerModRing(next_prime(10^30)).unit_gens() # optional - sage.groups + sage: IntegerModRing(next_prime(10^30)).unit_gens() # needs sage.groups (5,) The choice of generators is affected by the optional keyword @@ -1379,18 +1392,18 @@ def unit_gens(self, **kwds): See :meth:`unit_group` for details. :: sage: A = Zmod(55) - sage: A.unit_gens(algorithm='sage') # optional - sage.groups + sage: A.unit_gens(algorithm='sage') # needs sage.groups (12, 46) - sage: A.unit_gens(algorithm='pari') # optional - sage.groups sage.libs.pari + sage: A.unit_gens(algorithm='pari') # needs sage.groups sage.libs.pari (2, 21) TESTS:: - sage: IntegerModRing(2).unit_gens() # optional - sage.groups + sage: IntegerModRing(2).unit_gens() # needs sage.groups () - sage: IntegerModRing(4).unit_gens() # optional - sage.groups + sage: IntegerModRing(4).unit_gens() # needs sage.groups (3,) - sage: IntegerModRing(8).unit_gens() # optional - sage.groups + sage: IntegerModRing(8).unit_gens() # needs sage.groups (7, 5) """ @@ -1401,10 +1414,10 @@ def unit_group_exponent(self): EXAMPLES:: sage: R = IntegerModRing(17) - sage: R.unit_group_exponent() # optional - sage.groups + sage: R.unit_group_exponent() # needs sage.groups 16 sage: R = IntegerModRing(18) - sage: R.unit_group_exponent() # optional - sage.groups + sage: R.unit_group_exponent() # needs sage.groups 6 """ return self.unit_group().exponent() @@ -1416,7 +1429,7 @@ def unit_group_order(self): EXAMPLES:: sage: R = Integers(500) - sage: R.unit_group_order() # optional - sage.groups + sage: R.unit_group_order() # needs sage.groups 200 """ return self.unit_group().order() @@ -1454,53 +1467,56 @@ def unit_group(self, algorithm='sage'): differ in various ways. In the following example, the same cyclic factors are computed, but in a different order:: + sage: # needs sage.groups sage: A = Zmod(15) - sage: G = A.unit_group(); G # optional - sage.groups + sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C4 - sage: G.gens_values() # optional - sage.groups + sage: G.gens_values() (11, 7) - sage: H = A.unit_group(algorithm='pari'); H # optional - sage.groups sage.libs.pari + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C4 x C2 - sage: H.gens_values() # optional - sage.groups sage.libs.pari + sage: H.gens_values() # needs sage.libs.pari (7, 11) Here are two examples where the cyclic factors are isomorphic, but are ordered differently and have different generators:: + sage: # needs sage.groups sage: A = Zmod(40) - sage: G = A.unit_group(); G # optional - sage.groups + sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C2 x C4 - sage: G.gens_values() # optional - sage.groups + sage: G.gens_values() (31, 21, 17) - sage: H = A.unit_group(algorithm='pari'); H # optional - sage.groups sage.libs.pari + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C4 x C2 x C2 - sage: H.gens_values() # optional - sage.groups sage.libs.pari + sage: H.gens_values() # needs sage.libs.pari (17, 31, 21) + sage: # needs sage.groups sage: A = Zmod(192) - sage: G = A.unit_group(); G # optional - sage.groups + sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C16 x C2 - sage: G.gens_values() # optional - sage.groups + sage: G.gens_values() (127, 133, 65) - sage: H = A.unit_group(algorithm='pari'); H # optional - sage.groups sage.libs.pari + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C16 x C2 x C2 - sage: H.gens_values() # optional - sage.groups sage.libs.pari + sage: H.gens_values() # needs sage.libs.pari (133, 127, 65) In the following examples, the cyclic factors are not even isomorphic:: sage: A = Zmod(319) - sage: A.unit_group() # optional - sage.groups + sage: A.unit_group() # needs sage.groups Multiplicative Abelian group isomorphic to C10 x C28 - sage: A.unit_group(algorithm='pari') # optional - sage.groups sage.libs.pari + sage: A.unit_group(algorithm='pari') # needs sage.groups sage.libs.pari Multiplicative Abelian group isomorphic to C140 x C2 sage: A = Zmod(30.factorial()) - sage: A.unit_group() # optional - sage.groups + sage: A.unit_group() # needs sage.groups Multiplicative Abelian group isomorphic to C2 x C16777216 x C3188646 x C62500 x C2058 x C110 x C156 x C16 x C18 x C22 x C28 - sage: A.unit_group(algorithm='pari') # optional - sage.groups sage.libs.pari + sage: A.unit_group(algorithm='pari') # needs sage.groups sage.libs.pari Multiplicative Abelian group isomorphic to C20499647385305088000000 x C55440 x C12 x C12 x C4 x C2 x C2 x C2 x C2 x C2 x C2 @@ -1508,18 +1524,19 @@ def unit_group(self, algorithm='sage'): We test the cases where the unit group is trivial:: + sage: # needs sage.groups sage: A = Zmod(1) - sage: A.unit_group() # optional - sage.groups + sage: A.unit_group() Trivial Abelian group - sage: A.unit_group(algorithm='pari') # optional - sage.groups sage.libs.pari + sage: A.unit_group(algorithm='pari') # needs sage.libs.pari Trivial Abelian group sage: A = Zmod(2) - sage: A.unit_group() # optional - sage.groups + sage: A.unit_group() Trivial Abelian group - sage: A.unit_group(algorithm='pari') # optional - sage.groups sage.libs.pari + sage: A.unit_group(algorithm='pari') # needs sage.libs.pari Trivial Abelian group - sage: Zmod(3).unit_group(algorithm='bogus') # optional - sage.groups + sage: Zmod(3).unit_group(algorithm='bogus') # needs sage.groups Traceback (most recent call last): ... ValueError: unknown algorithm 'bogus' for computing the unit group @@ -1583,7 +1600,7 @@ def _gap_init_(self): sage: R = Integers(12345678900) sage: R Ring of integers modulo 12345678900 - sage: gap(R) # indirect doctest # optional - sage.libs.gap + sage: gap(R) # indirect doctest # needs sage.libs.gap (Integers mod 12345678900) """ return 'ZmodnZ({})'.format(self.order()) @@ -1595,7 +1612,7 @@ def _magma_init_(self, magma): sage: R = Integers(12345678900) sage: R Ring of integers modulo 12345678900 - sage: magma(R) # indirect doctest, optional - magma + sage: magma(R) # indirect doctest, optional - magma Residue class ring of integers modulo 12345678900 """ return 'Integers({})'.format(self.order()) diff --git a/src/sage/rings/finite_rings/maps_finite_field.py b/src/sage/rings/finite_rings/maps_finite_field.py index 07d351c165a..0ae08a3d25d 100644 --- a/src/sage/rings/finite_rings/maps_finite_field.py +++ b/src/sage/rings/finite_rings/maps_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Structure maps for finite fields diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index 5c1941894e0..b466ee5e2c1 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -3,40 +3,42 @@ Finite residue fields We can take the residue field of maximal ideals in the ring of integers of number fields. We can also take the residue field of irreducible -polynomials over `GF(p)`. +polynomials over `\GF{p}`. EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P); k Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) - sage: k.order() # optional - sage.rings.number_field + sage: k.order() 841 We reduce mod a prime for which the ring of integers is not monogenic (i.e., 2 is an essential discriminant divisor):: - sage: K. = NumberField(x^3 + x^2 - 2*x + 8) # optional - sage.rings.number_field - sage: F = K.factor(2); F # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^3 + x^2 - 2*x + 8) + sage: F = K.factor(2); F (Fractional ideal (-1/2*a^2 + 1/2*a - 1)) * (Fractional ideal (-a^2 + 2*a - 3)) * (Fractional ideal (3/2*a^2 - 5/2*a + 4)) - sage: F[0][0].residue_field() # optional - sage.rings.number_field + sage: F[0][0].residue_field() Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) - sage: F[1][0].residue_field() # optional - sage.rings.number_field + sage: F[1][0].residue_field() Residue field of Fractional ideal (-a^2 + 2*a - 3) - sage: F[2][0].residue_field() # optional - sage.rings.number_field + sage: F[2][0].residue_field() Residue field of Fractional ideal (3/2*a^2 - 5/2*a + 4) We can also form residue fields from `\ZZ`:: - sage: ZZ.residue_field(17) # optional - sage.rings.number_field + sage: ZZ.residue_field(17) Residue field of Integers modulo 17 And for polynomial rings over finite fields:: + sage: # needs sage.rings.finite_rings sage: R. = GF(5)[] sage: I = R.ideal(t^2 + 2) sage: k = ResidueField(I); k @@ -54,21 +56,23 @@ AUTHORS: TESTS:: - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: P = K.factor(17)[0][0] # optional - sage.rings.number_field - sage: ff = K.residue_field(P) # optional - sage.rings.number_field - sage: loads(dumps(ff)) is ff # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: P = K.factor(17)[0][0] + sage: ff = K.residue_field(P) + sage: loads(dumps(ff)) is ff True - sage: a = ff(z) # optional - sage.rings.number_field - sage: parent(a*a) # optional - sage.rings.number_field + sage: a = ff(z) + sage: parent(a*a) Residue field in zbar of Fractional ideal (17) sage: TestSuite(ff).run() Verify that :trac:`15192` has been resolved:: - sage: a.is_unit() # optional - sage.rings.number_field + sage: a.is_unit() # needs sage.rings.number_field True + sage: # needs sage.rings.finite_rings sage: R. = GF(11)[]; P = R.ideal(t^3 + t + 4) sage: ff. = ResidueField(P) sage: a == ff(t) @@ -85,20 +89,22 @@ Verify that :trac:`7475` is fixed:: Reducing a curve modulo a prime:: - sage: K. = NumberField(x^2 + 23) # optional - sage.rings.number_field - sage: OK = K.ring_of_integers() # optional - sage.rings.number_field - sage: E = EllipticCurve([0,0,0,K(1),K(5)]) # optional - sage.rings.number_field - sage: pp = K.factor(13)[0][0] # optional - sage.rings.number_field - sage: Fpp = OK.residue_field(pp) # optional - sage.rings.number_field - sage: E.base_extend(Fpp) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^2 + 23) + sage: OK = K.ring_of_integers() + sage: E = EllipticCurve([0,0,0,K(1),K(5)]) + sage: pp = K.factor(13)[0][0] + sage: Fpp = OK.residue_field(pp) + sage: E.base_extend(Fpp) Elliptic Curve defined by y^2 = x^3 + x + 5 over Residue field of Fractional ideal (13, 1/2*s + 9/2) + sage: # needs sage.rings.finite_rings sage: R. = GF(11)[] sage: P = R.ideal(t^3 + t + 4) sage: ff. = R.residue_field(P) - sage: E = EllipticCurve([0,0,0,R(1),R(t)]) - sage: E.base_extend(ff) + sage: E = EllipticCurve([0,0,0,R(1),R(t)]) # needs sage.schemes + sage: E.base_extend(ff) # needs sage.schemes Elliptic Curve defined by y^2 = x^3 + x + a over Residue field in a of Principal ideal (t^3 + t + 4) of Univariate Polynomial Ring in t over Finite Field of size 11 @@ -106,41 +112,43 @@ Reducing a curve modulo a prime:: Calculating Groebner bases over various residue fields. First over a small non-prime field:: - sage: F1. = NumberField(x^6 + 6*x^5 + 124*x^4 # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: F1. = NumberField(x^6 + 6*x^5 + 124*x^4 ....: + 452*x^3 + 4336*x^2 + 8200*x + 42316) - sage: reduct_id = F1.factor(47)[0][0] # optional - sage.rings.number_field - sage: Rf = F1.residue_field(reduct_id) # optional - sage.rings.number_field - sage: type(Rf) # optional - sage.rings.number_field + sage: reduct_id = F1.factor(47)[0][0] + sage: Rf = F1.residue_field(reduct_id) + sage: type(Rf) - sage: Rf.cardinality().factor() # optional - sage.rings.number_field + sage: Rf.cardinality().factor() 47^3 - sage: R. = PolynomialRing(Rf) # optional - sage.rings.number_field - sage: ubar = Rf(u) # optional - sage.rings.number_field - sage: I = ideal([ubar*X + Y]); I # optional - sage.rings.number_field + sage: R. = PolynomialRing(Rf) + sage: ubar = Rf(u) + sage: I = ideal([ubar*X + Y]); I Ideal (ubar*X + Y) of Multivariate Polynomial Ring in X, Y over Residue field in ubar of Fractional ideal (47, 517/55860*u^5 + 235/3724*u^4 + 9829/13965*u^3 + 54106/13965*u^2 + 64517/27930*u + 755696/13965) - sage: I.groebner_basis() # optional - sage.rings.number_field + sage: I.groebner_basis() [X + (-19*ubar^2 - 5*ubar - 17)*Y] And now over a large prime field:: + sage: # needs sage.rings.number_field sage: x = ZZ['x'].0 - sage: F1. = NumberField(x^2 + 6*x + 324) # optional - sage.rings.number_field - sage: reduct_id = F1.prime_above(next_prime(2^42)) # optional - sage.rings.number_field - sage: Rf = F1.residue_field(reduct_id) # optional - sage.rings.number_field - sage: type(Rf) # optional - sage.rings.number_field + sage: F1. = NumberField(x^2 + 6*x + 324) + sage: reduct_id = F1.prime_above(next_prime(2^42)) + sage: Rf = F1.residue_field(reduct_id) + sage: type(Rf) - sage: Rf.cardinality().factor() # optional - sage.rings.number_field + sage: Rf.cardinality().factor() 4398046511119 - sage: S. = PolynomialRing(Rf, order='lex') # optional - sage.rings.number_field - sage: I = ideal([2*X - Y^2, Y + Z]) # optional - sage.rings.number_field - sage: I.groebner_basis() # optional - sage.rings.number_field + sage: S. = PolynomialRing(Rf, order='lex') + sage: I = ideal([2*X - Y^2, Y + Z]) + sage: I.groebner_basis() [X + 2199023255559*Z^2, Y + Z] - sage: S. = PolynomialRing(Rf, order='deglex') # optional - sage.rings.number_field - sage: I = ideal([2*X - Y^2, Y + Z]) # optional - sage.rings.number_field - sage: I.groebner_basis() # optional - sage.rings.number_field + sage: S. = PolynomialRing(Rf, order='deglex') + sage: I = ideal([2*X - Y^2, Y + Z]) + sage: I.groebner_basis() [Z^2 + 4398046511117*X, Y + Z] """ @@ -176,19 +184,16 @@ from sage.rings.finite_rings.finite_field_constructor import zech_log_bound, Fin from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn from sage.rings.ideal import is_Ideal from sage.rings.number_field.number_field_element_base import NumberFieldElement_base -from sage.structure.element cimport Element - from sage.rings.number_field.number_field_ideal import is_NumberFieldIdeal -from sage.modules.free_module_element import FreeModuleElement from sage.rings.fraction_field import is_FractionField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.polynomial_element import Polynomial +from sage.structure.element cimport Element, parent, Vector from sage.structure.factory import UniqueFactory -from sage.structure.element cimport parent from sage.structure.richcmp cimport richcmp, richcmp_not_equal @@ -200,71 +205,74 @@ class ResidueFieldFactory(UniqueFactory): INPUT: - - ``p`` -- a prime ideal of an order in a number field. + - ``p`` -- a prime ideal of an order in a number field. - - ``names`` -- the variable name for the finite field created. - Defaults to the name of the number field variable but with - bar placed after it. + - ``names`` -- the variable name for the finite field created. + Defaults to the name of the number field variable but with + bar placed after it. - - ``check`` -- whether or not to check if `p` is prime. + - ``check`` -- whether or not to check if `p` is prime. OUTPUT: - - The residue field at the prime `p`. + The residue field at the prime `p`. EXAMPLES:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: ResidueField(P) # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: P = K.ideal(29).factor()[0][0] # needs sage.rings.number_field + sage: ResidueField(P) # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) The result is cached:: - sage: ResidueField(P) is ResidueField(P) # optional - sage.rings.number_field + sage: ResidueField(P) is ResidueField(P) # needs sage.rings.number_field True - sage: k = K.residue_field(P); k # optional - sage.rings.number_field + sage: k = K.residue_field(P); k # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) - sage: k.order() # optional - sage.rings.number_field + sage: k.order() # needs sage.rings.number_field 841 It also works for polynomial rings:: sage: R. = GF(31)[] sage: P = R.ideal(t^5 + 2*t + 11) - sage: ResidueField(P) + sage: ResidueField(P) # needs sage.rings.finite_rings Residue field in tbar of Principal ideal (t^5 + 2*t + 11) of Univariate Polynomial Ring in t over Finite Field of size 31 - sage: ResidueField(P) is ResidueField(P) + sage: ResidueField(P) is ResidueField(P) # needs sage.rings.finite_rings True - sage: k = ResidueField(P); k.order() + sage: k = ResidueField(P); k.order() # needs sage.rings.finite_rings 28629151 An example where the generator of the number field doesn't generate the residue class field:: - sage: K. = NumberField(x^3 - 875) # optional - sage.rings.number_field - sage: P = K.ideal(5).factor()[0][0]; k = K.residue_field(P); k # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^3 - 875) + sage: P = K.ideal(5).factor()[0][0]; k = K.residue_field(P); k Residue field in abar of Fractional ideal (5, 1/25*a^2 - 2/5*a - 1) - sage: k.polynomial() # optional - sage.rings.number_field + sage: k.polynomial() abar^2 + 3*abar + 4 - sage: k.0^3 - 875 # optional - sage.rings.number_field + sage: k.0^3 - 875 2 An example where the residue class field is large but of degree 1:: - sage: K. = NumberField(x^3 - 875) # optional - sage.rings.number_field - sage: P = K.ideal(2007).factor()[2][0]; k = K.residue_field(P); k # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^3 - 875) + sage: P = K.ideal(2007).factor()[2][0]; k = K.residue_field(P); k Residue field of Fractional ideal (223, 1/5*a + 11) - sage: k(a) # optional - sage.rings.number_field + sage: k(a) 168 - sage: k(a)^3 - 875 # optional - sage.rings.number_field + sage: k(a)^3 - 875 0 And for polynomial rings:: + sage: # needs sage.rings.finite_rings sage: R. = GF(next_prime(2^18))[] sage: P = R.ideal(t - 5) sage: k = ResidueField(P); k @@ -276,28 +284,29 @@ class ResidueFieldFactory(UniqueFactory): In this example, 2 is an inessential discriminant divisor, so divides the index of ``ZZ[a]`` in the maximal order for all ``a``:: - sage: K. = NumberField(x^3 + x^2 - 2*x + 8) # optional - sage.rings.number_field - sage: P = K.ideal(2).factor()[0][0]; P # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^3 + x^2 - 2*x + 8) + sage: P = K.ideal(2).factor()[0][0]; P Fractional ideal (-1/2*a^2 + 1/2*a - 1) - sage: F = K.residue_field(P); F # optional - sage.rings.number_field + sage: F = K.residue_field(P); F Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) - sage: F(a) # optional - sage.rings.number_field + sage: F(a) 0 - sage: B = K.maximal_order().basis(); B # optional - sage.rings.number_field + sage: B = K.maximal_order().basis(); B [1, 1/2*a^2 + 1/2*a, a^2] - sage: F(B[1]) # optional - sage.rings.number_field + sage: F(B[1]) 1 - sage: F(B[2]) # optional - sage.rings.number_field + sage: F(B[2]) 0 - sage: F # optional - sage.rings.number_field + sage: F Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) - sage: F.degree() # optional - sage.rings.number_field + sage: F.degree() 1 TESTS:: - sage: K. = NumberField(polygen(QQ)) # optional - sage.rings.number_field - sage: K.residue_field(K.ideal(3)) # optional - sage.rings.number_field + sage: K. = NumberField(polygen(QQ)) # needs sage.rings.number_field + sage: K.residue_field(K.ideal(3)) # needs sage.rings.number_field Residue field of Fractional ideal (3) """ def create_key_and_extra_args(self, p, names = None, check=True, impl=None, **kwds): @@ -308,8 +317,8 @@ class ResidueFieldFactory(UniqueFactory): EXAMPLES:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: ResidueField(K.ideal(29).factor()[0][0]) # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: ResidueField(K.ideal(29).factor()[0][0]) # indirect doctest # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) """ if check: @@ -356,9 +365,9 @@ class ResidueFieldFactory(UniqueFactory): EXAMPLES:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: ResidueField(P) is ResidueField(P) # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: P = K.ideal(29).factor()[0][0] # needs sage.rings.number_field + sage: ResidueField(P) is ResidueField(P) # indirect doctest # needs sage.rings.number_field True """ p, names, impl = key @@ -376,16 +385,30 @@ class ResidueFieldFactory(UniqueFactory): else: q = characteristic**(f.degree()) if q < zech_log_bound and (impl is None or impl == 'givaro'): - from .residue_field_givaro import ResidueFiniteField_givaro - return ResidueFiniteField_givaro(p, q, names, f, None, None, None) - elif (q % 2 == 0) and (impl is None or impl == 'ntl'): - from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e - return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, None, None, None) - elif impl is None or impl == 'pari': - from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt - return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, None, None, None) - else: - raise ValueError("unrecognized finite field type") + try: + from .residue_field_givaro import ResidueFiniteField_givaro + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_givaro(p, q, names, f, None, None, None) + if q % 2 == 0 and (impl is None or impl == 'ntl'): + try: + from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, None, None, None) + if impl is None or impl == 'pari': + try: + from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, None, None, None) + raise ValueError("unrecognized finite field type") # Should generalize to allowing residue fields of relative extensions to be extensions of finite fields. if is_NumberFieldIdeal(p): @@ -438,36 +461,54 @@ class ResidueFieldFactory(UniqueFactory): else: q = characteristic**(f.degree()) if q < zech_log_bound and (impl is None or impl == 'givaro'): - from .residue_field_givaro import ResidueFiniteField_givaro - return ResidueFiniteField_givaro(p, q, names, f, to_vs, to_order, PB) - elif (q % 2 == 0) and (impl is None or impl == 'ntl'): - from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e - return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, to_vs, to_order, PB) - elif impl is None or impl == 'pari': - from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt - return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, to_vs, to_order, PB) - else: - raise ValueError("unrecognized finite field type") + try: + from .residue_field_givaro import ResidueFiniteField_givaro + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_givaro(p, q, names, f, to_vs, to_order, PB) + elif q % 2 == 0 and (impl is None or impl == 'ntl'): + try: + from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, to_vs, to_order, PB) + if impl is None or impl == 'pari': + try: + from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, to_vs, to_order, PB) + raise ValueError("unrecognized finite field type") + ResidueField = ResidueFieldFactory("ResidueField") + class ResidueField_generic(Field): """ The class representing a generic residue field. EXAMPLES:: - sage: I = QQ[i].factor(2)[0][0]; I # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: I = QQ[i].factor(2)[0][0]; I Fractional ideal (I + 1) - sage: k = I.residue_field(); k # optional - sage.rings.number_field + sage: k = I.residue_field(); k Residue field of Fractional ideal (I + 1) - sage: type(k) # optional - sage.rings.number_field + sage: type(k) + sage: # needs sage.rings.finite_rings sage: R. = GF(29)[]; P = R.ideal(t^2 + 2); k. = ResidueField(P); k Residue field in a of Principal ideal (t^2 + 2) of Univariate Polynomial Ring in t over Finite Field of size 29 - sage: type(k) + sage: type(k) # needs sage.libs.linbox """ def __init__(self, p): @@ -487,26 +528,30 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 17) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # indirect doctest # optional - sage.rings.number_field - sage: F = ZZ.residue_field(17) # indirect doctest - - sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) - sage: k. = P.residue_field() # indirect doctest + sage: K. = NumberField(x^3 - 17) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) # indirect doctest - sage: k.category() - Category of finite enumerated fields + sage: F = ZZ.residue_field(17) # indirect doctest sage: F.category() Join of Category of finite enumerated fields and Category of subquotients of monoids and Category of quotients of semigroups + sage: # needs sage.rings.finite_rings + sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) + sage: k. = P.residue_field() # indirect doctest + sage: k.category() + Category of finite enumerated fields + TESTS:: - sage: TestSuite(k).run() sage: TestSuite(F).run() + + sage: # needs sage.modules sage.rings.finite_rings + sage: TestSuite(k).run() """ self.p = p # Note: we don't call Parent.__init__ since many residue fields use multiple inheritance and will be calling __init__ via their other superclass. @@ -527,21 +572,21 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: P = K.factor(17)[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: P = K.factor(17)[0][0] + sage: k = K.residue_field(P); k Residue field in zbar of Fractional ideal (17) - sage: F, R = k.construction() # optional - sage.rings.number_field - sage: F # optional - sage.rings.number_field + sage: F, R = k.construction() + sage: F AlgebraicExtensionFunctor - sage: R # optional - sage.rings.number_field + sage: R Cyclotomic Field of order 7 and degree 6 - sage: F(R) is k # optional - sage.rings.number_field + sage: F(R) is k True - sage: F(ZZ) # optional - sage.rings.number_field + sage: F(ZZ) Residue field of Integers modulo 17 - sage: F(CyclotomicField(49)) # optional - sage.rings.number_field + sage: F(CyclotomicField(49)) Residue field in zbar of Fractional ideal (17) """ @@ -553,18 +598,20 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + x + 1) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # indirect doctest # optional - sage.rings.number_field - sage: k.ideal() is P # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + x + 1) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) # indirect doctest + sage: k.ideal() is P True - sage: p = next_prime(2^40); p # optional - sage.rings.number_field + sage: p = next_prime(2^40); p 1099511627791 - sage: k = K.residue_field(K.prime_above(p)) # optional - sage.rings.number_field - sage: k.ideal().norm() == p # optional - sage.rings.number_field + sage: k = K.residue_field(K.prime_above(p)) + sage: k.ideal().norm() == p True + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = R.residue_field(P) sage: k.ideal() @@ -591,23 +638,25 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.rings.finite_rings.residue_field import ResidueField_generic sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: P = K.ideal(-3*i - 2) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: F = OK.residue_field(P) # optional - sage.rings.number_field - sage: ResidueField_generic._element_constructor_(F, i) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: P = K.ideal(-3*i - 2) + sage: OK = K.maximal_order() + sage: F = OK.residue_field(P) + sage: ResidueField_generic._element_constructor_(F, i) 8 With :trac:`8800`, we also have:: - sage: ResidueField_generic._element_constructor_(F, GF(13)(8)) # optional - sage.rings.number_field + sage: ResidueField_generic._element_constructor_(F, GF(13)(8)) # needs sage.rings.number_field 8 Here is a test that was temporarily removed, but newly introduced in :trac:`8800`:: + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() sage: k(t) @@ -638,24 +687,26 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: P = K.ideal(-3*i - 2) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: F = OK.residue_field(P) # optional - sage.rings.number_field - sage: F.has_coerce_map_from(GF(13)) # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: P = K.ideal(-3*i - 2) + sage: OK = K.maximal_order() + sage: F = OK.residue_field(P) + sage: F.has_coerce_map_from(GF(13)) # indirect doctest True TESTS: Check that :trac:`11319` is fixed:: - sage: GF(13).has_coerce_map_from(F) + sage: GF(13).has_coerce_map_from(F) # needs sage.rings.number_field True + sage: # needs sage.rings.number_field sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() - sage: k.has_coerce_map_from(Qp(17)) # indirect doctest + sage: k.has_coerce_map_from(Qp(17)) # indirect doctest # needs sage.rings.padics False """ OK = self.p.ring() @@ -669,15 +720,17 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P); k # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P); k Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) sage: F = ZZ.residue_field(17); F Residue field of Integers modulo 17 + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field(); k # indirect doctest Residue field in a of Principal ideal (t^3 + t^2 + 7) of @@ -694,18 +747,20 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(a) # optional - sage.rings.number_field - sage: k.lift(13*b + 5) # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(a) + sage: k.lift(13*b + 5) 13*a + 5 - sage: k.lift(12821*b + 918) # optional - sage.rings.number_field + sage: k.lift(12821*b + 918) 3*a + 19 + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() sage: k.lift(a^2 + 5) @@ -726,30 +781,33 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: I = QQ[2^(1/3)].factor(2)[0][0]; I # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: I = QQ[2^(1/3)].factor(2)[0][0]; I Fractional ideal (a) - sage: k = I.residue_field(); k # optional - sage.rings.number_field sage.symbolic + sage: k = I.residue_field(); k Residue field of Fractional ideal (a) - sage: pi = k.reduction_map(); pi # optional - sage.rings.number_field sage.symbolic + sage: pi = k.reduction_map(); pi Partially defined reduction map: From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? To: Residue field of Fractional ideal (a) - sage: pi.domain() # optional - sage.rings.number_field sage.symbolic + sage: pi.domain() Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? - sage: pi.codomain() # optional - sage.rings.number_field sage.symbolic + sage: pi.codomain() Residue field of Fractional ideal (a) + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + x^2 - 2*x + 32) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.reduction_map().domain() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + x^2 - 2*x + 32) + sage: F = K.factor(2)[0][0].residue_field() + sage: F.reduction_map().domain() Number Field in a with defining polynomial x^3 + x^2 - 2*x + 32 - sage: K. = NumberField(x^3 + 128) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.reduction_map().codomain() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + 128) + sage: F = K.factor(2)[0][0].residue_field() + sage: F.reduction_map().codomain() Residue field of Fractional ideal (1/4*a) + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field(); f = k.reduction_map(); f Partially defined reduction map: @@ -769,23 +827,25 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: I = QQ[3^(1/3)].factor(5)[1][0]; I # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: I = QQ[3^(1/3)].factor(5)[1][0]; I Fractional ideal (a - 2) - sage: k = I.residue_field(); k # optional - sage.rings.number_field sage.symbolic + sage: k = I.residue_field(); k Residue field of Fractional ideal (a - 2) - sage: f = k.lift_map(); f # optional - sage.rings.number_field sage.symbolic + sage: f = k.lift_map(); f Lifting map: From: Residue field of Fractional ideal (a - 2) To: Maximal Order in Number Field in a with defining polynomial x^3 - 3 with a = 1.442249570307409? - sage: f.domain() # optional - sage.rings.number_field sage.symbolic + sage: f.domain() Residue field of Fractional ideal (a - 2) - sage: f.codomain() # optional - sage.rings.number_field sage.symbolic + sage: f.codomain() Maximal Order in Number Field in a with defining polynomial x^3 - 3 with a = 1.442249570307409? - sage: f(k.0) # optional - sage.rings.number_field sage.symbolic + sage: f(k.0) 1 + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() sage: f = k.lift_map(); f @@ -809,15 +869,17 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 11) # optional - sage.rings.number_field - sage: F = K.ideal(37).factor(); F # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 11) + sage: F = K.ideal(37).factor(); F (Fractional ideal (37, a + 9)) * (Fractional ideal (37, a + 12)) * (Fractional ideal (-2*a + 5)) - sage: k = K.residue_field(F[0][0]) # optional - sage.rings.number_field - sage: l = K.residue_field(F[1][0]) # optional - sage.rings.number_field - sage: k == l # optional - sage.rings.number_field + sage: k = K.residue_field(F[0][0]) + sage: l = K.residue_field(F[1][0]) + sage: k == l False + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 11) @@ -842,12 +904,15 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + x + 1) # optional - sage.rings.number_field - sage: hash(K.residue_field(K.prime_above(17))) # random # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + x + 1) + sage: hash(K.residue_field(K.prime_above(17))) # random -6463132282686559142 - sage: hash(K.residue_field(K.prime_above(2^60))) # random # optional - sage.rings.number_field + sage: hash(K.residue_field(K.prime_above(2^60))) # random -6939519969600666586 + + sage: # needs sage.rings.finite_rings sage: R. = GF(13)[] sage: hash(R.residue_field(t + 2)) # random 3521289879659800254 @@ -864,16 +929,18 @@ cdef class ReductionMap(Map): EXAMPLES:: - sage: I = QQ[sqrt(17)].factor(5)[0][0]; I # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: I = QQ[sqrt(17)].factor(5)[0][0]; I Fractional ideal (5) - sage: k = I.residue_field(); k # optional - sage.rings.number_field sage.symbolic + sage: k = I.residue_field(); k Residue field in sqrt17bar of Fractional ideal (5) - sage: R = k.reduction_map(); R # optional - sage.rings.number_field sage.symbolic + sage: R = k.reduction_map(); R Partially defined reduction map: From: Number Field in sqrt17 with defining polynomial x^2 - 17 with sqrt17 = 4.123105625617660? To: Residue field in sqrt17bar of Fractional ideal (5) + sage: # needs sage.rings.finite_rings sage: R. = GF(next_prime(2^20))[]; P = R.ideal(t^2 + t + 1) sage: k = P.residue_field() sage: k.reduction_map() @@ -889,30 +956,33 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + x^2 - 2*x + 8) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.reduction_map() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + x^2 - 2*x + 8) + sage: F = K.factor(2)[0][0].residue_field() + sage: F.reduction_map() Partially defined reduction map: From: Number Field in a with defining polynomial x^3 + x^2 - 2*x + 8 To: Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) - sage: K. = CyclotomicField(5) # optional - sage.rings.number_field - sage: F = K.factor(7)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.reduction_map() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(5) + sage: F = K.factor(7)[0][0].residue_field() + sage: F.reduction_map() Partially defined reduction map: From: Cyclotomic Field of order 5 and degree 4 To: Residue field in theta_5bar of Fractional ideal (7) + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; P = R.ideal(t^7 + t^6 + t^5 + t^4 + 1) sage: k = P.residue_field() - sage: k.reduction_map() + sage: k.reduction_map() # needs sage.libs.ntl Partially defined reduction map: From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) To: Residue field in tbar of Principal ideal (t^7 + t^6 + t^5 + t^4 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) - sage: type(k) + sage: type(k) # needs sage.libs.linbox """ self._K = K @@ -931,18 +1001,19 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: r = F.reduction_map() # optional - sage.rings.number_field - sage: cr = copy(r) # indirect doctest # optional - sage.rings.number_field - sage: cr # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: F = K.factor(2)[0][0].residue_field() + sage: r = F.reduction_map() + sage: cr = copy(r) # indirect doctest + sage: cr Partially defined reduction map: From: Number Field in a with defining polynomial x^2 + 1 To: Residue field of Fractional ideal (a + 1) - sage: cr == r # todo: comparison not implemented # optional - sage.rings.number_field + sage: cr == r # not implemented True - sage: r(2 + a) == cr(2 + a) # optional - sage.rings.number_field + sage: r(2 + a) == cr(2 + a) True """ slots = Map._extra_slots(self) @@ -961,18 +1032,19 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: r = F.reduction_map() # optional - sage.rings.number_field - sage: cr = copy(r) # indirect doctest # optional - sage.rings.number_field - sage: cr # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: F = K.factor(2)[0][0].residue_field() + sage: r = F.reduction_map() + sage: cr = copy(r) # indirect doctest + sage: cr Partially defined reduction map: From: Number Field in a with defining polynomial x^2 + 1 To: Residue field of Fractional ideal (a + 1) - sage: cr == r # todo: comparison not implemented # optional - sage.rings.number_field + sage: cr == r # not implemented True - sage: r(2 + a) == cr(2 + a) # optional - sage.rings.number_field + sage: r(2 + a) == cr(2 + a) True """ Map._update_slots(self, _slots) @@ -994,25 +1066,28 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: F = K.factor(2)[0][0].residue_field() # optional - sage.rings.number_field - sage: r = F.reduction_map(); r # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: F = K.factor(2)[0][0].residue_field() + sage: r = F.reduction_map(); r Partially defined reduction map: From: Number Field in a with defining polynomial x^2 + 1 To: Residue field of Fractional ideal (a + 1) We test that calling the function also works after copying:: - sage: r = copy(r) # optional - sage.rings.number_field - sage: r(2 + a) # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: r = copy(r) + sage: r(2 + a) # indirect doctest 1 - sage: r(a/2) # optional - sage.rings.number_field + sage: r(a/2) Traceback (most recent call last): ... ZeroDivisionError: Cannot reduce field element 1/2*a modulo Fractional ideal (a + 1): it has negative valuation + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; h = t^5 + t^2 + 1 sage: k. = R.residue_field(h) sage: K = R.fraction_field() @@ -1024,27 +1099,28 @@ cdef class ReductionMap(Map): sage: f(1/h) Traceback (most recent call last): ... - ZeroDivisionError: division by zero in finite field + ZeroDivisionError... An example to show that the issue raised in :trac:`1951` has been fixed:: - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: P1, P2 = [g[0] for g in K.factor(5)]; P1, P2 # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: P1, P2 = [g[0] for g in K.factor(5)]; P1, P2 (Fractional ideal (-i - 2), Fractional ideal (2*i + 1)) - sage: a = 1/(1+2*i) # optional - sage.rings.number_field - sage: F1, F2 = [g.residue_field() for g in [P1,P2]]; F1, F2 # optional - sage.rings.number_field + sage: a = 1/(1+2*i) + sage: F1, F2 = [g.residue_field() for g in [P1,P2]]; F1, F2 (Residue field of Fractional ideal (-i - 2), Residue field of Fractional ideal (2*i + 1)) - sage: a.valuation(P1) # optional - sage.rings.number_field + sage: a.valuation(P1) 0 - sage: F1(i/7) # optional - sage.rings.number_field + sage: F1(i/7) 4 - sage: F1(a) # optional - sage.rings.number_field + sage: F1(a) 3 - sage: a.valuation(P2) # optional - sage.rings.number_field + sage: a.valuation(P2) -1 - sage: F2(a) # optional - sage.rings.number_field + sage: F2(a) Traceback (most recent call last): ... ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5 @@ -1106,34 +1182,36 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^5 - 5*x + 2) # optional - sage.rings.number_field - sage: P = K.ideal(47).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: f = k.convert_map_from(K) # optional - sage.rings.number_field - sage: s = f.section(); s # optional - sage.rings.number_field + sage: K. = NumberField(x^5 - 5*x + 2) + sage: P = K.ideal(47).factor()[0][0] + sage: k = K.residue_field(P) + sage: f = k.convert_map_from(K) + sage: s = f.section(); s Lifting map: From: Residue field in abar of Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) To: Number Field in a with defining polynomial x^5 - 5*x + 2 - sage: s(k.gen()) # optional - sage.rings.number_field + sage: s(k.gen()) a - sage: L. = NumberField(x^5 + 17*x + 1) # optional - sage.rings.number_field - sage: P = L.factor(53)[0][0] # optional - sage.rings.number_field - sage: l = L.residue_field(P) # optional - sage.rings.number_field - sage: g = l.convert_map_from(L) # optional - sage.rings.number_field - sage: s = g.section(); s # optional - sage.rings.number_field + sage: L. = NumberField(x^5 + 17*x + 1) + sage: P = L.factor(53)[0][0] + sage: l = L.residue_field(P) + sage: g = l.convert_map_from(L) + sage: s = g.section(); s Lifting map: From: Residue field in bbar of Fractional ideal (53, b^2 + 23*b + 8) To: Number Field in b with defining polynomial x^5 + 17*x + 1 - sage: s(l.gen()).parent() # optional - sage.rings.number_field + sage: s(l.gen()).parent() Number Field in b with defining polynomial x^5 + 17*x + 1 + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; h = t^5 + t^2 + 1 sage: k. = R.residue_field(h) sage: K = R.fraction_field() sage: f = k.convert_map_from(K) - sage: f.section() + sage: f.section() # needs sage.libs.ntl Lifting map: From: Residue field in a of Principal ideal (t^5 + t^2 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) @@ -1152,25 +1230,28 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: abar = k(OK.1); abar # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: abar = k(OK.1); abar abar - sage: (1+abar)^179 # optional - sage.rings.number_field + sage: (1+abar)^179 24*abar + 12 - sage: phi = k.coerce_map_from(OK); phi # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: phi = k.coerce_map_from(OK); phi Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - 7 To: Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) - sage: phi in Hom(OK,k) # optional - sage.rings.number_field + sage: phi in Hom(OK,k) True - sage: phi(OK.1) # optional - sage.rings.number_field + sage: phi(OK.1) abar + sage: # needs sage.rings.finite_rings sage: R. = GF(19)[]; P = R.ideal(t^2 + 5) sage: k. = R.residue_field(P) sage: f = k.coerce_map_from(R); f @@ -1195,19 +1276,21 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): We create a residue field homomorphism:: - sage: K. = CyclotomicField(5) # optional - sage.rings.number_field - sage: P = K.factor(7)[0][0] # optional - sage.rings.number_field - sage: P.residue_class_degree() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(5) + sage: P = K.factor(7)[0][0] + sage: P.residue_class_degree() 4 - sage: kk. = P.residue_field(); kk # optional - sage.rings.number_field + sage: kk. = P.residue_field(); kk Residue field in a of Fractional ideal (7) - sage: phi = kk.coerce_map_from(K.maximal_order()); phi # optional - sage.rings.number_field + sage: phi = kk.coerce_map_from(K.maximal_order()); phi Ring morphism: From: Maximal Order in Cyclotomic Field of order 5 and degree 4 To: Residue field in a of Fractional ideal (7) - sage: type(phi) # optional - sage.rings.number_field + sage: type(phi) + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; P = R.ideal(t^7 + t^6 + t^5 + t^4 + 1) sage: k = P.residue_field(); f = k.coerce_map_from(R) sage: f(t^10) @@ -1228,19 +1311,20 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - x + 8) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: phi = k.coerce_map_from(OK) # optional - sage.rings.number_field - sage: psi = copy(phi); psi # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - x + 8) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: phi = k.coerce_map_from(OK) + sage: psi = copy(phi); psi # indirect doctest Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - x + 8 To: Residue field in abar of Fractional ideal (29) - sage: psi == phi # todo: comparison not implemented # optional - sage.rings.number_field + sage: psi == phi # not implemented True - sage: psi(OK.an_element()) == phi(OK.an_element()) # optional - sage.rings.number_field + sage: psi(OK.an_element()) == phi(OK.an_element()) True """ slots = RingHomomorphism._extra_slots(self) @@ -1259,19 +1343,20 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - x + 8) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: phi = k.coerce_map_from(OK) # optional - sage.rings.number_field - sage: psi = copy(phi); psi # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - x + 8) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: phi = k.coerce_map_from(OK) + sage: psi = copy(phi); psi # indirect doctest Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - x + 8 To: Residue field in abar of Fractional ideal (29) - sage: psi == phi # todo: comparison not implemented # optional - sage.rings.number_field + sage: psi == phi # not implemented True - sage: psi(OK.an_element()) == phi(OK.an_element()) # optional - sage.rings.number_field + sage: psi(OK.an_element()) == phi(OK.an_element()) True """ RingHomomorphism._update_slots(self, _slots) @@ -1289,14 +1374,16 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - x + 8) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: k.coerce_map_from(OK)(OK(a)^7) # indirect doctest # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - x + 8) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: k.coerce_map_from(OK)(OK(a)^7) # indirect doctest 13*abar^2 + 7*abar + 21 + sage: # needs sage.rings.finite_rings sage: R. = GF(next_prime(2^18))[]; P = R.ideal(t - 71) sage: k = ResidueField(P); f = k.coerce_map_from(R); f Ring morphism: @@ -1329,30 +1416,32 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^5 - 5*x + 2) # optional - sage.rings.number_field - sage: P = K.ideal(47).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: f = k.coerce_map_from(K.ring_of_integers()) # optional - sage.rings.number_field - sage: s = f.section(); s # optional - sage.rings.number_field + sage: K. = NumberField(x^5 - 5*x + 2) + sage: P = K.ideal(47).factor()[0][0] + sage: k = K.residue_field(P) + sage: f = k.coerce_map_from(K.ring_of_integers()) + sage: s = f.section(); s Lifting map: From: Residue field in abar of Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) To: Maximal Order in Number Field in a with defining polynomial x^5 - 5*x + 2 sage: s(k.gen()) a - sage: L. = NumberField(x^5 + 17*x + 1) # optional - sage.rings.number_field - sage: P = L.factor(53)[0][0] # optional - sage.rings.number_field - sage: l = L.residue_field(P) # optional - sage.rings.number_field - sage: g = l.coerce_map_from(L.ring_of_integers()) # optional - sage.rings.number_field - sage: s = g.section(); s # optional - sage.rings.number_field + sage: L. = NumberField(x^5 + 17*x + 1) + sage: P = L.factor(53)[0][0] + sage: l = L.residue_field(P) + sage: g = l.coerce_map_from(L.ring_of_integers()) + sage: s = g.section(); s Lifting map: From: Residue field in bbar of Fractional ideal (53, b^2 + 23*b + 8) To: Maximal Order in Number Field in b with defining polynomial x^5 + 17*x + 1 - sage: s(l.gen()).parent() # optional - sage.rings.number_field + sage: s(l.gen()).parent() Maximal Order in Number Field in b with defining polynomial x^5 + 17*x + 1 + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field() sage: f = k.coerce_map_from(R) @@ -1374,19 +1463,21 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: f = k.coerce_map_from(OK) # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(a) # optional - sage.rings.number_field - sage: f.lift(13*b + 5) # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: OK = K.maximal_order() + sage: f = k.coerce_map_from(OK) + sage: c = OK(a) + sage: b = k(a) + sage: f.lift(13*b + 5) 13*a + 5 - sage: f.lift(12821*b + 918) # optional - sage.rings.number_field + sage: f.lift(12821*b + 918) 3*a + 19 + sage: # needs sage.rings.finite_rings sage: R. = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k. = P.residue_field(); f = k.coerce_map_from(R) sage: f.lift(a^2 + 5*a + 1) @@ -1405,20 +1496,22 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + 2) # optional - sage.rings.number_field - sage: F = K.factor(5)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.degree() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + 2) + sage: F = K.factor(5)[0][0].residue_field() + sage: F.degree() 2 - sage: L = F.lift_map(); L # optional - sage.rings.number_field + sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (a^2 + 2*a - 1) To: Maximal Order in Number Field in a with defining polynomial x^3 + 2 - sage: L(F.0^2) # optional - sage.rings.number_field + sage: L(F.0^2) 3*a + 1 - sage: L(3*a + 1) == F.0^2 # optional - sage.rings.number_field + sage: L(3*a + 1) == F.0^2 True + sage: # needs sage.rings.finite_rings sage: R. = GF(13)[] sage: P = R.ideal(8*t^12 + 9*t^11 + 11*t^10 + 2*t^9 + 11*t^8 ....: + 3*t^7 + 12*t^6 + t^4 + 7*t^3 + 5*t^2 + 12*t + 1) @@ -1436,38 +1529,42 @@ cdef class LiftingMap(Section): EXAMPLES:: - sage: K. = CyclotomicField(5) # optional - sage.rings.number_field - sage: F = K.factor(7)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.lift_map() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(5) + sage: F = K.factor(7)[0][0].residue_field() + sage: F.lift_map() Lifting map: From: Residue field in theta_5bar of Fractional ideal (7) To: Maximal Order in Cyclotomic Field of order 5 and degree 4 + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^5 + 2) # optional - sage.rings.number_field - sage: F = K.factor(7)[0][0].residue_field() # optional - sage.rings.number_field - sage: L = F.lift_map(); L # optional - sage.rings.number_field + sage: K. = NumberField(x^5 + 2) + sage: F = K.factor(7)[0][0].residue_field() + sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (2*a^4 - a^3 + 4*a^2 - 2*a + 1) To: Maximal Order in Number Field in a with defining polynomial x^5 + 2 - sage: L.domain() # optional - sage.rings.number_field + sage: L.domain() Residue field in abar of Fractional ideal (2*a^4 - a^3 + 4*a^2 - 2*a + 1) - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: F = K.factor(5)[0][0].residue_field() # optional - sage.rings.number_field - sage: L = F.lift_map(); L # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: F = K.factor(5)[0][0].residue_field() + sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: L.codomain() # optional - sage.rings.number_field + sage: L.codomain() Maximal Order in Cyclotomic Field of order 7 and degree 6 + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; h = t^5 + t^2 + 1 sage: k. = R.residue_field(h) sage: K = R.fraction_field() sage: L = k.lift_map(); L.codomain() - Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + Univariate Polynomial Ring in t over Finite Field of size 2... """ self._K = reduction._K self._F = reduction._F # finite field @@ -1481,16 +1578,17 @@ cdef class LiftingMap(Section): EXAMPLES:: - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: F = K.factor(5)[0][0].residue_field() # optional - sage.rings.number_field - sage: phi = F.lift_map() # optional - sage.rings.number_field - sage: psi = copy(phi); psi # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: F = K.factor(5)[0][0].residue_field() + sage: phi = F.lift_map() + sage: psi = copy(phi); psi # indirect doctest Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: psi == phi # todo: comparison not implemented # optional - sage.rings.number_field + sage: psi == phi # not implemented False - sage: phi(F.0) == psi(F.0) # optional - sage.rings.number_field + sage: phi(F.0) == psi(F.0) True """ slots = Section._extra_slots(self) @@ -1506,16 +1604,17 @@ cdef class LiftingMap(Section): EXAMPLES:: - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: F = K.factor(5)[0][0].residue_field() # optional - sage.rings.number_field - sage: phi = F.lift_map() # optional - sage.rings.number_field - sage: psi = copy(phi); psi # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: F = K.factor(5)[0][0].residue_field() + sage: phi = F.lift_map() + sage: psi = copy(phi); psi # indirect doctest Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: psi == phi # todo: comparison not implemented # optional - sage.rings.number_field + sage: psi == phi # not implemented False - sage: phi(F.0) == psi(F.0) # optional - sage.rings.number_field + sage: phi(F.0) == psi(F.0) True """ Section._update_slots(self, _slots) @@ -1530,17 +1629,19 @@ cdef class LiftingMap(Section): EXAMPLES:: - sage: K. = CyclotomicField(7) # optional - sage.rings.number_field - sage: F = K.factor(5)[0][0].residue_field() # optional - sage.rings.number_field - sage: L = F.lift_map(); L # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(7) + sage: F = K.factor(5)[0][0].residue_field() + sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: L(F.0) # indirect doctest # optional - sage.rings.number_field + sage: L(F.0) # indirect doctest a - sage: F(a) # optional - sage.rings.number_field + sage: F(a) abar + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; h = t^5 + t^2 + 1 sage: k. = R.residue_field(h) sage: K = R.fraction_field() @@ -1572,9 +1673,10 @@ cdef class LiftingMap(Section): """ EXAMPLES:: - sage: K. = CyclotomicField(12) # optional - sage.rings.number_field - sage: F. = K.factor(7)[0][0].residue_field() # optional - sage.rings.number_field - sage: F.lift_map() #indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(12) + sage: F. = K.factor(7)[0][0].residue_field() + sage: F.lift_map() #indirect doctest Lifting map: From: Residue field in tmod of Fractional ideal (theta_12^2 + 2) To: Maximal Order in Cyclotomic Field of order 12 and degree 4 @@ -1588,26 +1690,27 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[1][0] # optional - sage.rings.number_field - sage: k = ResidueField(P) # optional - sage.rings.number_field - sage: k # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[1][0] + sage: k = ResidueField(P); k Residue field of Fractional ideal (-a^2 - 2*a - 2) - sage: k.order() # optional - sage.rings.number_field + sage: k.order() 29 - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(a) # optional - sage.rings.number_field - sage: k.coerce_map_from(OK)(c) # optional - sage.rings.number_field + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(a) + sage: k.coerce_map_from(OK)(c) 16 - sage: k(4) # optional - sage.rings.number_field + sage: k(4) 4 - sage: k(c + 5) # optional - sage.rings.number_field + sage: k(c + 5) 21 - sage: b + c # optional - sage.rings.number_field + sage: b + c 3 + sage: # needs sage.rings.finite_rings sage: R. = GF(7)[]; P = R.ideal(2*t + 3) sage: k = P.residue_field(); k Residue field of Principal ideal (t + 5) of @@ -1631,11 +1734,13 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: - sage: K. = QuadraticField(-1) # optional - sage.rings.number_field - sage: kk = ResidueField(K.factor(5)[0][0]) # optional - sage.rings.number_field - sage: type(kk) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-1) + sage: kk = ResidueField(K.factor(5)[0][0]) + sage: type(kk) + sage: # needs sage.rings.finite_rings sage: R. = GF(7)[]; P = R.ideal(2*t + 3) sage: k = P.residue_field(); type(k) @@ -1675,30 +1780,32 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[1][0] # optional - sage.rings.number_field - sage: k = ResidueField(P) # optional - sage.rings.number_field - sage: k # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[1][0] + sage: k = ResidueField(P) + sage: k Residue field of Fractional ideal (-a^2 - 2*a - 2) - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(a); b # optional - sage.rings.number_field + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(a); b 16 - sage: k(2r) # optional - sage.rings.number_field + sage: k(2r) 2 - sage: V = k.vector_space(map=False); v = V([3]) # optional - sage.rings.number_field - sage: type(k.convert_map_from(V)) # optional - sage.rings.number_field + sage: V = k.vector_space(map=False); v = V([3]) + sage: type(k.convert_map_from(V)) - sage: k(v) # indirect doctest # optional - sage.rings.number_field + sage: k(v) # indirect doctest 3 + sage: # needs sage.rings.finite_rings sage: R. = GF(2)[]; P = R.ideal(t + 1); k. = P.residue_field() sage: V = k.vector_space(map=False); v = V([1]) sage: k(v) 1 """ - if isinstance(x, FreeModuleElement) and len(x) == 1: + if isinstance(x, Vector) and len(x) == 1: x = x[0] try: return FiniteField_prime_modn._element_constructor_(self, x) diff --git a/src/sage/rings/finite_rings/residue_field_givaro.pyx b/src/sage/rings/finite_rings/residue_field_givaro.pyx index 32a133a9f0b..07fd740c044 100644 --- a/src/sage/rings/finite_rings/residue_field_givaro.pyx +++ b/src/sage/rings/finite_rings/residue_field_givaro.pyx @@ -33,18 +33,19 @@ class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k.degree() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() 2 - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(c) # optional - sage.rings.number_field - sage: b*c^2 # optional - sage.rings.number_field + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b*c^2 7 - sage: b*c # optional - sage.rings.number_field + sage: b*c 13*abar + 5 sage: R. = GF(7)[]; P = R.ideal(t^2 + 4) @@ -75,9 +76,9 @@ class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): EXAMPLES:: sage: R. = QQ[] - sage: K. = NumberField(x^4 + 3*x^2 - 17) # optional - sage.rings.number_field - sage: P = K.ideal(61).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field + sage: K. = NumberField(x^4 + 3*x^2 - 17) # needs sage.rings.number_field + sage: P = K.ideal(61).factor()[0][0] # needs sage.rings.number_field + sage: k = K.residue_field(P) # needs sage.rings.number_field sage: R. = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k. = P.residue_field(); type(k) @@ -107,16 +108,17 @@ class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^4 + 3*x^2 - 17) # optional - sage.rings.number_field - sage: P = K.ideal(61).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k(77*a^7 + 4) # optional - sage.rings.number_field + sage: K. = NumberField(x^4 + 3*x^2 - 17) + sage: P = K.ideal(61).factor()[0][0] + sage: k = K.residue_field(P) + sage: k(77*a^7 + 4) 2*abar + 4 - sage: V = k.vector_space(map=False); v = V([3,-2]) # optional - sage.rings.number_field + sage: V = k.vector_space(map=False); v = V([3,-2]) sage: type(k.convert_map_from(V)) - sage: k(v) # indirect doctest + sage: k(v) # indirect doctest 59*abar + 3 sage: R. = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k. = P.residue_field() diff --git a/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx b/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx index c9fcfa50f07..ed6af655258 100644 --- a/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx @@ -34,18 +34,19 @@ class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(29).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k.degree() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() 2 - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(c) # optional - sage.rings.number_field - sage: b*c^2 # optional - sage.rings.number_field + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b*c^2 7 - sage: b*c # optional - sage.rings.number_field + sage: b*c 13*abar + 5 sage: R. = GF(2)[]; P = R.ideal(t^19 + t^5 + t^2 + t + 1) @@ -80,9 +81,9 @@ class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): EXAMPLES:: sage: R. = QQ[] - sage: K. = NumberField(x^4 + 3*x^2 - 17) # optional - sage.rings.number_field - sage: P = K.ideal(61).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field + sage: K. = NumberField(x^4 + 3*x^2 - 17) # needs sage.rings.number_field + sage: P = K.ideal(61).factor()[0][0] # needs sage.rings.number_field + sage: k = K.residue_field(P) # needs sage.rings.number_field sage: R. = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k. = P.residue_field(); type(k) @@ -112,16 +113,17 @@ class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^4 + 3*x^2 - 17) # optional - sage.rings.number_field - sage: P = K.ideal(61).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k(77*a^7 + 4) # optional - sage.rings.number_field + sage: K. = NumberField(x^4 + 3*x^2 - 17) + sage: P = K.ideal(61).factor()[0][0] + sage: k = K.residue_field(P) + sage: k(77*a^7 + 4) 2*abar + 4 - sage: V = k.vector_space(map=False); v = V([3,-2]) # optional - sage.rings.number_field - sage: type(k.convert_map_from(V)) # optional - sage.rings.number_field + sage: V = k.vector_space(map=False); v = V([3,-2]) + sage: type(k.convert_map_from(V)) - sage: k(v) # indirect doctest # optional - sage.rings.number_field + sage: k(v) # indirect doctest 59*abar + 3 sage: R. = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k. = P.residue_field() diff --git a/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx b/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx index f4e6ee10b1c..375b3b4cdfc 100644 --- a/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx @@ -33,20 +33,21 @@ class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 7) # optional - sage.rings.number_field - sage: P = K.ideal(923478923).factor()[0][0] # optional - sage.rings.number_field - sage: k = K.residue_field(P) # optional - sage.rings.number_field - sage: k.degree() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 7) + sage: P = K.ideal(923478923).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() 2 - sage: OK = K.maximal_order() # optional - sage.rings.number_field - sage: c = OK(a) # optional - sage.rings.number_field - sage: b = k(c) # optional - sage.rings.number_field - sage: b + c # optional - sage.rings.number_field + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b + c 2*abar - sage: b*c # optional - sage.rings.number_field + sage: b*c 664346875*abar + 535606347 - sage: k.base_ring() # optional - sage.rings.number_field + sage: k.base_ring() Finite Field of size 923478923 sage: R. = GF(5)[] @@ -67,6 +68,7 @@ class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt We create a residue field with implementation ``pari_ffelt``:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^3 - 7) sage: P = K.ideal(923478923).factor()[0][0] @@ -94,23 +96,24 @@ class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: P = K.factor(10007)[0][0] # optional - sage.rings.number_field - sage: P.residue_class_degree() # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: P = K.factor(10007)[0][0] + sage: P.residue_class_degree() 2 - sage: ff. = P.residue_field(); ff # optional - sage.rings.number_field + sage: ff. = P.residue_field(); ff Residue field in alpha of Fractional ideal (-12*aa^2 + 189*aa - 475) - sage: type(ff) # optional - sage.rings.number_field + sage: type(ff) - sage: ff(alpha^2 + 1) # optional - sage.rings.number_field + sage: ff(alpha^2 + 1) 7521*alpha + 4131 - sage: ff(17/3) # optional - sage.rings.number_field + sage: ff(17/3) 6677 - sage: V = ff.vector_space(map=False); v = V([3,-2]) # optional - sage.rings.number_field - sage: type(ff.convert_map_from(V)) # optional - sage.rings.number_field + sage: V = ff.vector_space(map=False); v = V([3,-2]) + sage: type(ff.convert_map_from(V)) - sage: ff(v) # indirect doctest # optional - sage.rings.number_field + sage: ff(v) # indirect doctest 10005*alpha + 3 sage: R. = GF(5)[]; P = R.ideal(4*t^12 + 3*t^11 + 4*t^10 + t^9 + t^8 + 3*t^7 + 2*t^6 + 3*t^4 + t^3 + 3*t^2 + 2) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 91c326b13aa..1aff655bed8 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -1175,7 +1175,7 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1307,7 +1307,7 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index c90a532d6c5..ead3310d054 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -154,7 +154,7 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented from sage.structure.richcmp import richcmp diff --git a/src/sage/rings/function_field/valuation.py b/src/sage/rings/function_field/valuation.py index 5eecbb38095..5567c4db1ce 100644 --- a/src/sage/rings/function_field/valuation.py +++ b/src/sage/rings/function_field/valuation.py @@ -570,7 +570,7 @@ def extensions(self, L): H_extensions = self.extensions(M) from sage.rings.morphism import RingHomomorphism_im_gens - if type(y_to_u) == RingHomomorphism_im_gens and type(u_to_y) == RingHomomorphism_im_gens: + if isinstance(y_to_u, RingHomomorphism_im_gens) and isinstance(u_to_y, RingHomomorphism_im_gens): return [L.valuation((w, L.hom([M(y_to_u(y_to_u.domain().gen()))]), M.hom([L(u_to_y(u_to_y.domain().gen()))]))) for w in H_extensions] raise NotImplementedError return [L.valuation(w) for w in self.mac_lane_approximants(L.polynomial(), require_incomparability=True)] diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 2cd080ddafa..d5e87626d31 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2852,12 +2852,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): except (ValueError, TypeError): pass - if type(m) == Integer and type(self) == Integer: + if isinstance(m, Integer): elog = self.exact_log(m) if elog == -sage.rings.infinity.infinity or m**elog == self: return elog - if (type(m) == Rational and type(self) == Integer + if (isinstance(m, Rational) and m.numer() == 1): elog = -self.exact_log(m.denom()) if m**elog == self: diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 564af30855d..f9b7f6a561b 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -635,7 +635,7 @@ def __richcmp__(self, other, op): sage: quartic == quartic True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.coeffs(), other.coeffs(), op) @@ -3159,7 +3159,7 @@ def __richcmp__(self, other, op): sage: two_inv == two_inv True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self._forms, other._forms, op) diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index eb54c8df3dc..a986e3c513c 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -982,11 +982,12 @@ def minimal_vector(A, y, prec=106): ALLLinv = ALLL.inverse() ybrace = [ abs(R(a-a.round())) for a in y * ALLLinv if (a-a.round()) != 0] + v = ALLL.rows()[0] if len(ybrace) == 0: - return (ALLL.rows()[0].norm())**2 / c1 + return v.dot_product(v) / c1 else: sigma = ybrace[len(ybrace)-1] - return ((ALLL.rows()[0].norm())**2 * sigma) / c1 + return v.dot_product(v) * sigma / c1 def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index f89a2141d8d..748122fe924 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -45,9 +45,11 @@ class GaloisGroup_v1(SageObject): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 sage: K = QQ[2^(1/3)] - sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G + sage: pK = K.absolute_polynomial() + sage: G = GaloisGroup_v1(pK.galois_group(pari_group=True), K); G ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. Galois group PARI group [6, -1, 2, "S3"] of degree 3 of the @@ -96,6 +98,8 @@ def __eq__(self, other): sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. + + sage: # needs sage.symbolic sage: L = QQ[sqrt(2)] sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L) sage: H == G @@ -125,6 +129,8 @@ def __ne__(self, other): sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. + + sage: # needs sage.symbolic sage: L = QQ[sqrt(2)] sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L) sage: H != G diff --git a/src/sage/rings/number_field/homset.py b/src/sage/rings/number_field/homset.py index 8624a7aaccf..a28660ca5d0 100644 --- a/src/sage/rings/number_field/homset.py +++ b/src/sage/rings/number_field/homset.py @@ -342,10 +342,10 @@ def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): are only approximate:: sage: K. = QuadraticField(-7) - sage: f = K.hom([CC(sqrt(-7))], check=False) + sage: f = K.hom([CC(sqrt(-7))], check=False) # needs sage.symbolic sage: x = polygen(K) sage: L. = K.extension(x^2 - a - 5) - sage: L.Hom(CC)(f(a + 5).sqrt(), f, check=False) + sage: L.Hom(CC)(f(a + 5).sqrt(), f, check=False) # needs sage.symbolic Relative number field morphism: From: Number Field in b with defining polynomial x^2 - a - 5 over its base field To: Complex Field with 53 bits of precision diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index 1d84c0777dd..182bfea18d2 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -79,7 +79,7 @@ def _repr_type(self): def is_injective(self): r""" - EXAMPLES:: + EXAMPLES:: sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^4 + 3*x + 1) @@ -91,7 +91,7 @@ def is_injective(self): def is_surjective(self): r""" - EXAMPLES:: + EXAMPLES:: sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^4 + 3*x + 1) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 29f16213880..bc35e0ec0ed 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -540,7 +540,9 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, Another problem that was found while working on :trac:`11670`, ``maximize_at_primes`` and ``assume_disc_small`` were lost when pickling:: - sage: K. = NumberField(x^3 - 2, assume_disc_small=True, maximize_at_primes=[2], + sage: # needs sage.symbolic + sage: K. = NumberField(x^3 - 2, assume_disc_small=True, + ....: maximize_at_primes=[2], ....: latex_name='\\alpha', embedding=2^(1/3)) sage: L = loads(dumps(K)) sage: L._assume_disc_small @@ -550,7 +552,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, It is an error not to specify the generator:: - sage: K = NumberField(x^2-2) + sage: K = NumberField(x^2 - 2) Traceback (most recent call last): ... TypeError: You must specify the name of the generator. @@ -619,7 +621,8 @@ class NumberFieldFactory(UniqueFactory): sage: from sage.rings.number_field.number_field import NumberFieldFactory sage: nff = NumberFieldFactory("number_field_factory") sage: R. = QQ[] - sage: nff(x^2 + 1, name='a', check=False, embedding=None, latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) + sage: nff(x^2 + 1, name='a', check=False, embedding=None, latex_name=None, + ....: assume_disc_small=False, maximize_at_primes=None, structure=None) Number Field in a with defining polynomial x^2 + 1 Pickling preserves the ``structure()`` of a number field:: @@ -645,7 +648,8 @@ def create_key_and_extra_args(self, polynomial, name, check, embedding, latex_na sage: from sage.rings.number_field.number_field import NumberFieldFactory sage: nff = NumberFieldFactory("number_field_factory") sage: R. = QQ[] - sage: nff.create_key_and_extra_args(x^2+1, name='a', check=False, embedding=None, latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) + sage: nff.create_key_and_extra_args(x^2+1, name='a', check=False, embedding=None, + ....: latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) ((Rational Field, x^2 + 1, ('a',), None, 'a', None, False, None), {'check': False}) @@ -801,16 +805,14 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name We mix polynomial parent rings:: sage: k. = QQ[] - sage: m = NumberField([y^3 - 3, x^2 + x + 1, y^3 + 2], 'beta') - sage: m + sage: m = NumberField([y^3 - 3, x^2 + x + 1, y^3 + 2], 'beta'); m Number Field in beta0 with defining polynomial y^3 - 3 over its base field sage: m.base_field () Number Field in beta1 with defining polynomial x^2 + x + 1 over its base field A tower of quadratic fields:: - sage: K. = NumberField([x^2 + 3, x^2 + 2, x^2 + 1]) - sage: K + sage: K. = NumberField([x^2 + 3, x^2 + 2, x^2 + 1]); K Number Field in a0 with defining polynomial x^2 + 3 over its base field sage: K.base_field() Number Field in a1 with defining polynomial x^2 + 2 over its base field @@ -893,7 +895,7 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * - ``D`` -- a rational number - - ``name`` -- variable name (default: 'a') + - ``name`` -- variable name (default: ``'a'``) - ``check`` -- bool (default: ``True``) @@ -953,9 +955,9 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * We can provide our own name as well:: sage: K. = QuadraticField(next_prime(10^10), latex_name=r'\sqrt{D}') - sage: 1+a + sage: 1 + a a + 1 - sage: latex(1+a) + sage: latex(1 + a) \sqrt{D} + 1 sage: latex(QuadraticField(-1, 'a', latex_name=None).gen()) a @@ -1040,7 +1042,7 @@ def is_AbsoluteNumberField(x): sage: x = polygen(ZZ, 'x') sage: is_AbsoluteNumberField(NumberField(x^2 + 1, 'a')) True - sage: is_AbsoluteNumberField(NumberField([x^3 + 17, x^2+1],'a')) + sage: is_AbsoluteNumberField(NumberField([x^3 + 17, x^2 + 1], 'a')) False The rationals are a number field, but they're not of the absolute @@ -1112,7 +1114,7 @@ class CyclotomicFieldFactory(UniqueFactory): If called without a parameter, we get the :class:`universal cyclotomic field`:: - sage: CyclotomicField() + sage: CyclotomicField() # needs sage.libs.gap Universal Cyclotomic Field We create the `7`\th cyclotomic field @@ -1452,7 +1454,7 @@ def __init__(self, polynomial, name, latex_name, Number Field in a with defining polynomial x^4 + 23 sage: NumberField(QQ['x'].0^4 + 23, 'a') Number Field in a with defining polynomial x^4 + 23 - sage: NumberField(GF(7)['x'].0^4 + 23, 'a') # optional - sage.rings.finite_rings + sage: NumberField(GF(7)['x'].0^4 + 23, 'a') # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: polynomial must be defined over rational field @@ -1547,16 +1549,17 @@ def _magma_polynomial_(self, magma): EXAMPLES:: - sage: R. = QQ[] # optional - magma - sage: K. = NumberField(x^3 + 2) # optional - magma - sage: K._magma_polynomial_(magma) # optional - magma + sage: # optional - magma + sage: R. = QQ[] + sage: K. = NumberField(x^3 + 2) + sage: K._magma_polynomial_(magma) x^3 + 2 - sage: magma2=Magma() # optional - magma - sage: K._magma_polynomial_(magma2) # optional - magma + sage: magma2 = Magma() + sage: K._magma_polynomial_(magma2) x^3 + 2 - sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma) # optional - magma + sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma) True - sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma2) # optional - magma + sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma2) False """ # NB f must not be garbage-collected, otherwise the @@ -1569,34 +1572,36 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: R. = QQ[] # optional - magma - sage: K. = NumberField(t^2 + 1) # optional - magma - sage: K._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: R. = QQ[] + sage: K. = NumberField(t^2 + 1) + sage: K._magma_init_(magma) 'SageCreateWithNames(NumberField(_sage_[...]),["a"])' - sage: L = magma(K) # optional - magma - sage: L # optional - magma + sage: L = magma(K) + sage: L Number Field with defining polynomial t^2 + 1 over the Rational Field - sage: L.sage() # optional - magma + sage: L.sage() Number Field in a with defining polynomial t^2 + 1 - sage: L.sage() is K # optional - magma + sage: L.sage() is K True - sage: L.1 # optional - magma + sage: L.1 a - sage: L.1^2 # optional - magma + sage: L.1^2 -1 - sage: m = magma(a+1/2); m # optional - magma + sage: m = magma(a+1/2); m 1/2*(2*a + 1) - sage: m.sage() # optional - magma + sage: m.sage() a + 1/2 A relative number field:: - sage: S. = K[] # optional - magma - sage: M. = NumberField(u^3+u+a) # optional - magma - sage: L = magma(M) # optional - magma - sage: L # optional - magma + sage: # optional - magma + sage: S. = K[] + sage: M. = NumberField(u^3+u+a) + sage: L = magma(M) + sage: L Number Field with defining polynomial u^3 + u + a over its ground field - sage: L.sage() is M # optional - magma + sage: L.sage() is M True """ # Get magma version of defining polynomial of this number field @@ -1606,7 +1611,7 @@ def _magma_init_(self, magma): def construction(self): r""" - Construction of self. + Construction of ``self``. EXAMPLES:: @@ -1691,7 +1696,7 @@ def _element_constructor_(self, x, check=True): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^3 + 17) - sage: K(a) is a # indirect doctest + sage: K(a) is a # indirect doctest True sage: K('a^2 + 2/3*a + 5') a^2 + 2/3*a + 5 @@ -1707,78 +1712,80 @@ def _element_constructor_(self, x, check=True): We can create number field elements from PARI:: sage: K. = NumberField(x^3 - 17) - sage: K(pari(42)) + sage: K(pari(42)) # needs sage.libs.pari 42 - sage: K(pari("5/3")) + sage: K(pari("5/3")) # needs sage.libs.pari 5/3 - sage: K(pari("[3/2, -5, 0]~")) # Uses Z-basis + sage: K(pari("[3/2, -5, 0]~")) # Uses Z-basis # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 From a PARI polynomial or ``POLMOD``, note that the variable name does not matter:: - sage: K(pari("-5/3*q^2 + 5/3*q - 1/6")) + sage: K(pari("-5/3*q^2 + 5/3*q - 1/6")) # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 - sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 17)")) + sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 17)")) # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 - sage: K(pari("x^5/17")) + sage: K(pari("x^5/17")) # needs sage.libs.pari a^2 An error is raised when a PARI element with an incorrect modulus is given:: - sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999)")) + sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999)")) # needs sage.libs.pari Traceback (most recent call last): ... - TypeError: cannot convert PARI element Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999) into Number Field in a with defining polynomial x^3 - 17 + TypeError: cannot convert PARI element Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999) + into Number Field in a with defining polynomial x^3 - 17 Test round-trip conversion to PARI and back:: sage: x = polygen(QQ) sage: K. = NumberField(x^3 - 1/2*x + 1/3) sage: b = K.random_element() - sage: K(pari(b)) == b + sage: K(pari(b)) == b # needs sage.libs.pari True sage: F. = NumberField(2*x^3 + x + 1) sage: d = F.random_element() - sage: F(F.pari_nf().nfalgtobasis(d)) == d + sage: F(F.pari_nf().nfalgtobasis(d)) == d # needs sage.libs.pari True If the PARI polynomial is different from the Sage polynomial, a warning is printed unless ``check=False`` is specified:: - sage: b = pari(a); b + sage: b = pari(a); b # needs sage.libs.pari Mod(-1/12*y^2 - 1/12*y + 1/6, y^3 - 3*y - 22) - sage: K(b.lift()) - doctest:...: UserWarning: interpreting PARI polynomial -1/12*y^2 - 1/12*y + 1/6 relative to the defining polynomial x^3 - 3*x - 22 of the PARI number field + sage: K(b.lift()) # needs sage.libs.pari + doctest:...: UserWarning: interpreting PARI polynomial -1/12*y^2 - 1/12*y + 1/6 + relative to the defining polynomial x^3 - 3*x - 22 of the PARI number field a - sage: K(b.lift(), check=False) + sage: K(b.lift(), check=False) # needs sage.libs.pari a Using a GAP element may be tricky, as it may contain an exclamation mark:: - sage: L. = NumberField(x^3-2) - sage: gap(tau^3) + sage: L. = NumberField(x^3 - 2) + sage: gap(tau^3) # needs sage.libs.gap 2 - sage: gap(tau)^3 + sage: gap(tau)^3 # needs sage.libs.gap !2 - sage: L(gap(tau)^3) # indirect doctest + sage: L(gap(tau)^3) # indirect doctest # needs sage.libs.gap 2 Check that :trac:`22202` and :trac:`27765` are fixed:: sage: y = QQ['y'].gen() - sage: R = QQ.extension(y^2-1/2,'a')['x'] + sage: R = QQ.extension(y^2 - 1/2, 'a')['x'] sage: R("a*x").factor() (a) * x Check that :trac:`30961` is fixed:: sage: QQi = i.parent() - sage: x = SR.var('x') # optional - sage.symbolic - sage: QQi((x, x)) # optional - sage.symbolic + sage: x = SR.var('x') # needs sage.symbolic + sage: QQi((x, x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert x to a rational @@ -1880,17 +1887,17 @@ def _convert_non_number_field_element(self, x): will convert to the number field, e.g., this one in characteristic 7:: - sage: f = GF(7)['y']([1,2,3]); f # optional - sage.rings.finite_rings + sage: f = GF(7)['y']([1,2,3]); f 3*y^2 + 2*y + 1 - sage: K._convert_non_number_field_element(f) # optional - sage.rings.finite_rings + sage: K._convert_non_number_field_element(f) 3*a^2 + 2*a + 1 But not this one over a field of order 27:: - sage: F27. = GF(27) # optional - sage.rings.finite_rings - sage: f = F27['z']([g^2, 2*g, 1]); f # optional - sage.rings.finite_rings + sage: F27. = GF(27) # needs sage.rings.finite_rings + sage: f = F27['z']([g^2, 2*g, 1]); f # needs sage.rings.finite_rings z^2 + 2*g*z + g^2 - sage: K._convert_non_number_field_element(f) # optional - sage.rings.finite_rings + sage: K._convert_non_number_field_element(f) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert g^2 to a rational @@ -1905,16 +1912,17 @@ def _convert_non_number_field_element(self, x): We can convert symbolic expressions:: - sage: I = sqrt(-1); parent(I) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: I = sqrt(-1); parent(I) Symbolic Ring - sage: GaussianIntegers()(2 + I) # optional - sage.symbolic + sage: GaussianIntegers()(2 + I) I + 2 - sage: K1 = QuadraticField(3) # optional - sage.symbolic - sage: K2 = QuadraticField(5) # optional - sage.symbolic - sage: (K,) = K1.composite_fields(K2, preserve_embedding=True) # optional - sage.symbolic - sage: K(sqrt(3) + sqrt(5)) # optional - sage.symbolic + sage: K1 = QuadraticField(3) + sage: K2 = QuadraticField(5) + sage: (K,) = K1.composite_fields(K2, preserve_embedding=True) + sage: K(sqrt(3) + sqrt(5)) -1/2*a0^3 + 8*a0 - sage: K(sqrt(-3)*I) # optional - sage.symbolic + sage: K(sqrt(-3)*I) 1/4*a0^3 - 7/2*a0 """ if isinstance(x, (int, Rational, Integer, pari_gen, list)): @@ -1974,7 +1982,8 @@ def _convert_from_qqbar(self, x): sage: CyclotomicField(12)(QQbar.zeta(5)) Traceback (most recent call last): ... - TypeError: unable to convert 0.3090169943749474? + 0.9510565162951536?*I to Cyclotomic Field of order 12 and degree 4 + TypeError: unable to convert 0.3090169943749474? + 0.9510565162951536?*I + to Cyclotomic Field of order 12 and degree 4 """ # We use the diagram # @@ -2004,7 +2013,7 @@ def _convert_from_str(self, x): INPUT: - - x -- string + - ``x`` -- string EXAMPLES:: @@ -2027,7 +2036,7 @@ def _convert_from_str(self, x): def _Hom_(self, codomain, category=None): """ - Return homset of homomorphisms from self to the number field codomain. + Return homset of homomorphisms from ``self`` to the number field codomain. EXAMPLES: @@ -2037,7 +2046,7 @@ def _Hom_(self, codomain, category=None): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2 + 1); K Number Field in i with defining polynomial x^2 + 1 - sage: K.Hom(K) # indirect doctest + sage: K.Hom(K) # indirect doctest Automorphism group of Number Field in i with defining polynomial x^2 + 1 sage: Hom(K, QuadraticField(-1, 'b')) Set of field embeddings @@ -2079,7 +2088,7 @@ def _Hom_(self, codomain, category=None): @cached_method def structure(self): """ - Return fixed isomorphism or embedding structure on self. + Return fixed isomorphism or embedding structure on ``self``. This is used to record various isomorphisms or embeddings that arise naturally in other constructions. @@ -2113,7 +2122,7 @@ def structure(self): def completion(self, p, prec, extras={}): """ - Return the completion of self at `p` to the specified precision. + Return the completion of ``self`` at `p` to the specified precision. Only implemented at archimedean places, and then only if an embedding has been fixed. @@ -2151,7 +2160,7 @@ def primitive_element(self): sage: K. = NumberField(x^3 + 2) sage: K.primitive_element() a - sage: K. = NumberField([x^2-2,x^2-3,x^2-5]) + sage: K. = NumberField([x^2 - 2, x^2 - 3, x^2 - 5]) sage: K.primitive_element() a - b + c sage: alpha = K.primitive_element(); alpha @@ -2316,8 +2325,8 @@ def subfield(self, alpha, name=None, names=None): sage: CLF_from_K(K_from_L(L.gen())) 2.23606797749979? + 0.?e-14*I - If `self` has no specified embedding, then `K` comes with an - embedding in `self`:: + If ``self`` has no specified embedding, then `K` comes with an + embedding in ``self``:: sage: K. = NumberField(x^6 - 6*x^4 + 8*x^2 - 1) sage: L., from_L = K.subfield(a^2) @@ -2328,7 +2337,7 @@ def subfield(self, alpha, name=None, names=None): You can also view a number field as having a different generator by just choosing the input to generate the whole field; for that it is - better to use ``self.change_generator``, which gives + better to use :meth:`change_generator`, which gives isomorphisms in both directions. """ if names is not None: @@ -2433,10 +2442,10 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): - ``name`` -- a name for the generator of the new number field - - ``polred`` (boolean, default ``True``) - whether to optimize the generator of + - ``polred`` -- (boolean, default ``True``); whether to optimize the generator of the newly created field - - ``threshold`` (positive number, default ``None``) - threshold to be passed to + - ``threshold`` -- (positive number, default ``None``) threshold to be passed to the ``do_polred`` function OUTPUT: a triple ``(field, beta, hom)`` where @@ -2463,8 +2472,10 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): [a0, -1/3*a0 + 1] sage: phi Ring morphism: - From: Number Field in a0 with defining polynomial x^2 - 2 with a0 = 1.414213562373095? - To: Number Field in a with defining polynomial x^4 - 4*x^2 + 1 with a = 0.5176380902050415? + From: Number Field in a0 with defining polynomial x^2 - 2 + with a0 = 1.414213562373095? + To: Number Field in a with defining polynomial x^4 - 4*x^2 + 1 + with a = 0.5176380902050415? Defn: a0 |--> -a^3 + 3*a sage: assert phi(elts[0]) == sqrt2 sage: assert phi(elts[1]) == 1 - sqrt2/3 @@ -2476,7 +2487,8 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): sage: L, elts, phi = K.subfield_from_elements([sqrt2, sqrt3]) sage: phi - Identity endomorphism of Number Field in a with defining polynomial x^4 - 4*x^2 + 1 with a = 0.5176380902050415? + Identity endomorphism of Number Field in a with defining polynomial + x^4 - 4*x^2 + 1 with a = 0.5176380902050415? TESTS:: @@ -2588,7 +2600,7 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): def is_absolute(self): """ - Return ``True`` if self is an absolute field. + Return ``True`` if ``self`` is an absolute field. This function will be implemented in the derived classes. @@ -2795,7 +2807,7 @@ def is_totally_real(self): def is_totally_imaginary(self): """ - Return ``True`` if self is totally imaginary, and ``False`` otherwise. + Return ``True`` if ``self`` is totally imaginary, and ``False`` otherwise. Totally imaginary means that no isomorphic embedding of ``self`` into the complex numbers has image contained in the real numbers. @@ -2814,7 +2826,7 @@ def is_totally_imaginary(self): def is_CM(self): r""" - Return ``True`` if self is a CM field (i.e. a totally imaginary + Return ``True`` if ``self`` is a CM field (i.e., a totally imaginary quadratic extension of a totally real field). EXAMPLES:: @@ -2851,9 +2863,8 @@ def is_CM(self): True sage: F.is_CM() False - sage: F2. = NumberField(x^12 - 5*x^11 + 8*x^10 - 5*x^9 - \ - x^8 + 9*x^7 + 7*x^6 - 3*x^5 + 5*x^4 + \ - 7*x^3 - 4*x^2 - 7*x + 7) + sage: F2. = NumberField(x^12 - 5*x^11 + 8*x^10 - 5*x^9 - x^8 + 9*x^7 + ....: + 7*x^6 - 3*x^5 + 5*x^4 + 7*x^3 - 4*x^2 - 7*x + 7) sage: F2.is_totally_imaginary() True sage: F2.is_CM() @@ -2948,7 +2959,8 @@ def complex_conjugation(self): EXAMPLES:: sage: QuadraticField(-1, 'I').complex_conjugation() - Ring endomorphism of Number Field in I with defining polynomial x^2 + 1 with I = 1*I + Ring endomorphism of + Number Field in I with defining polynomial x^2 + 1 with I = 1*I Defn: I |--> -I sage: CyclotomicField(8).complex_conjugation() Ring endomorphism of Cyclotomic Field of order 8 and degree 4 @@ -2961,10 +2973,12 @@ def complex_conjugation(self): sage: F.is_totally_real() True sage: F.complex_conjugation() - Identity endomorphism of Number Field in a with defining polynomial x^4 + x^3 - 3*x^2 - x + 1 + Identity endomorphism of Number Field in a with defining + polynomial x^4 + x^3 - 3*x^2 - x + 1 sage: F. = NumberField(x^2 - 2) sage: F.extension(x^2 + 1, 'a').complex_conjugation() - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 1 over its base field + Relative number field endomorphism of Number Field in a + with defining polynomial x^2 + 1 over its base field Defn: a |--> -a b |--> b sage: F2. = NumberField(x^2 + 2) @@ -3169,14 +3183,14 @@ def complex_embeddings(self, prec=53): sage: x = polygen(QQ, 'x') sage: k. = NumberField(x^5 + x + 17) sage: v = k.complex_embeddings() - sage: ls = [phi(k.0^2) for phi in v] ; ls # random order + sage: ls = [phi(k.0^2) for phi in v]; ls # random order [2.97572074038..., -2.40889943716 + 1.90254105304*I, -2.40889943716 - 1.90254105304*I, 0.921039066973 + 3.07553311885*I, 0.921039066973 - 3.07553311885*I] sage: K. = NumberField(x^3 + 2) - sage: ls = K.complex_embeddings() ; ls # random order + sage: ls = K.complex_embeddings(); ls # random order [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 @@ -3240,7 +3254,7 @@ def real_embeddings(self, prec=53): As this is a numerical function, the number of embeddings may be incorrect if the precision is too low:: - sage: K = NumberField(x^2 + 2*10^1000*x + 10^2000+1, 'a') + sage: K = NumberField(x^2 + 2*10^1000*x + 10^2000 + 1, 'a') sage: len(K.real_embeddings()) 2 sage: len(K.real_embeddings(100)) @@ -3312,13 +3326,14 @@ def specified_complex_embedding(self): This function only returns complex embeddings:: - sage: K. = NumberField(x^2 - 2, embedding=Qp(7)(2).sqrt()) # optional - sage.rings.padics - sage: K.specified_complex_embedding() is None # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K. = NumberField(x^2 - 2, embedding=Qp(7)(2).sqrt()) + sage: K.specified_complex_embedding() is None True - sage: K.gen_embedding() # optional - sage.rings.padics + sage: K.gen_embedding() 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + 4*7^18 + 6*7^19 + O(7^20) - sage: K.coerce_embedding() # optional - sage.rings.padics + sage: K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^2 - 2 with a = 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 @@ -3398,7 +3413,7 @@ def conductor(self, check_abelian=True): sage: K. = NumberField(x^3 + x^2 - 2*x - 1) sage: K.conductor() 7 - sage: K. = NumberField(x^3+x^2-36*x-4) + sage: K. = NumberField(x^3 + x^2 - 36*x - 4) sage: K.conductor() 109 sage: K = CyclotomicField(48) @@ -3407,11 +3422,11 @@ def conductor(self, check_abelian=True): 48 sage: NumberField(x,'a').conductor() 1 - sage: NumberField(x^8 - 8*x^6 + 19*x^4 - 12*x^2 + 1,'a').conductor() + sage: NumberField(x^8 - 8*x^6 + 19*x^4 - 12*x^2 + 1, 'a').conductor() 40 - sage: NumberField(x^8 + 7*x^4 + 1,'a').conductor() + sage: NumberField(x^8 + 7*x^4 + 1, 'a').conductor() 40 - sage: NumberField(x^8 - 40*x^6 + 500*x^4 - 2000*x^2 + 50,'a').conductor() + sage: NumberField(x^8 - 40*x^6 + 500*x^4 - 2000*x^2 + 50, 'a').conductor() 160 ALGORITHM: @@ -3660,22 +3675,24 @@ def idealchinese(self, ideals, residues): This is the example from the pari page on ``idealchinese``:: - sage: K. = NumberField(sqrt(2).minpoly()) # optional - sage.symbolic - sage: ideals = [K.ideal(4), K.ideal(3)] # optional - sage.symbolic - sage: residues = [sqrt2, 1] # optional - sage.symbolic - sage: r = K.idealchinese(ideals, residues); r # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = NumberField(sqrt(2).minpoly()) + sage: ideals = [K.ideal(4), K.ideal(3)] + sage: residues = [sqrt2, 1] + sage: r = K.idealchinese(ideals, residues); r -3*sqrt2 + 4 - sage: all((r - a) in I for I, a in zip(ideals, residues)) # optional - sage.symbolic + sage: all((r - a) in I for I, a in zip(ideals, residues)) True The result may be non-integral if the results are non-integral:: - sage: K. = NumberField(sqrt(2).minpoly()) # optional - sage.symbolic - sage: ideals = [K.ideal(4), K.ideal(21)] # optional - sage.symbolic - sage: residues = [1/sqrt2, 1] # optional - sage.symbolic - sage: r = K.idealchinese(ideals, residues); r # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = NumberField(sqrt(2).minpoly()) + sage: ideals = [K.ideal(4), K.ideal(21)] + sage: residues = [1/sqrt2, 1] + sage: r = K.idealchinese(ideals, residues); r -63/2*sqrt2 - 20 - sage: all( # optional - sage.symbolic + sage: all( ....: (r - a).valuation(P) >= k ....: for I, a in zip(ideals, residues) ....: for P, k in I.factor() @@ -3810,10 +3827,10 @@ def primes_above(self, x, degree=None): INPUT: - - ``x``: usually an element or ideal of ``self``. It + - ``x`` -- usually an element or ideal of ``self``. It should be such that ``self.ideal(x)`` is sensible. This excludes `x=0`. - - ``degree`` (default: ``None``): ``None`` or an integer. + - ``degree`` -- (default: ``None``) ``None`` or an integer. If ``None``, find all primes above `x` of any degree. If an integer, find all primes above `x` such that the resulting residue field has exactly this degree. @@ -3831,7 +3848,7 @@ def primes_above(self, x, degree=None): :: sage: P2s = F.primes_above(2) - sage: P2s # random + sage: P2s # random [Fractional ideal (-t)] sage: all(2 in P2 for P2 in P2s) True @@ -3913,10 +3930,10 @@ def prime_above(self, x, degree=None): INPUT: - - ``x``: usually an element or ideal of ``self``. It + - ``x`` -- usually an element or ideal of ``self``. It should be such that ``self.ideal(x)`` is sensible. This excludes `x=0`. - - ``degree`` (default: ``None``): ``None`` or an integer. + - ``degree`` -- (default: ``None``) ``None`` or an integer. If one, find a prime above `x` of any degree. If an integer, find a prime above `x` such that the resulting residue field has exactly this degree. @@ -4136,13 +4153,13 @@ def primes_of_degree_one_iter(self, num_integer_primes=10000, max_iterations=100 INPUT: - - ``num_integer_primes (default: 10000)`` - an + - ``num_integer_primes`` -- (default: 10000) an integer. We try to find primes of absolute norm no greater than the ``num_integer_primes``-th prime number. For example, if ``num_integer_primes`` is 2, the largest norm found will be 3, since the second prime is 3. - - ``max_iterations (default: 100)`` - an integer. We + - ``max_iterations`` -- (default: 100) an integer. We test ``max_iterations`` integers to find small primes before raising :class:`StopIteration`. @@ -4597,13 +4614,14 @@ def _gap_init_(self): EXAMPLES:: + sage: # needs sage.libs.gap sage: z = QQ['z'].0 sage: K. = NumberField(z^2 - 2) - sage: K._gap_init_() # the following variable name $sage1 represents the F.base_ring() in gap and is somehow random # optional - sage.libs.gap + sage: K._gap_init_() # the following variable name $sage1 represents the F.base_ring() in gap and is somehow random 'CallFuncList(function() local z,E; z:=Indeterminate($sage1,"z"); E:=AlgebraicExtension($sage1,z^2 - 2,"zeta"); return E; end,[])' - sage: k = gap(K); k # optional - sage.libs.gap + sage: k = gap(K); k - sage: k.GeneratorsOfDivisionRing() # optional - sage.libs.gap + sage: k.GeneratorsOfDivisionRing() [ zeta ] The following tests that it is possible to use a defining @@ -4611,13 +4629,14 @@ def _gap_init_(self): ``E`` is used as a local variable in the above GAP ``CallFuncList``:: + sage: # needs sage.libs.gap sage: P. = QQ[] sage: L. = NumberField(E^3 - 2) - sage: l = gap(L); l # optional - sage.libs.gap + sage: l = gap(L); l - sage: l.GeneratorsOfField() # optional - sage.libs.gap + sage: l.GeneratorsOfField() [ tau ] - sage: gap(tau)^3 # optional - sage.libs.gap + sage: gap(tau)^3 !2 """ if not self.is_absolute(): @@ -4773,8 +4792,9 @@ def S_class_group(self, S, proof=None, names='c'): When we include the prime `(2, a+1)`, the S-class group becomes trivial:: - sage: K.S_class_group([K.ideal(2,a+1)]) - S-class group of order 1 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + sage: K.S_class_group([K.ideal(2, a + 1)]) + S-class group of order 1 of Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I TESTS:: @@ -5042,8 +5062,8 @@ def selmer_generators(self, S, m, proof=True, orders=False): When `m` is prime all the orders are equal to `m`, but in general they are only divisors of `m`:: sage: K. = QuadraticField(-5) - sage: P2 = K.ideal(2, -a+1) - sage: P3 = K.ideal(3, a+1) + sage: P2 = K.ideal(2, -a + 1) + sage: P3 = K.ideal(3, a + 1) sage: K.selmer_generators((), 2, orders=True) ([-1, 2], [2, 2]) sage: K.selmer_generators((), 4, orders=True) @@ -5168,7 +5188,7 @@ def selmer_group_iterator(self, S, m, proof=True): - ``m`` -- a positive integer - - ``proof`` -- if False, assume the GRH in computing the class group + - ``proof`` -- if ``False``, assume the GRH in computing the class group OUTPUT: @@ -5249,8 +5269,8 @@ def selmer_space(self, S, p, proof=None): sage: K. = QuadraticField(-5) sage: K.class_number() 2 - sage: P2 = K.ideal(2, -a+1) - sage: P3 = K.ideal(3, a+1) + sage: P2 = K.ideal(2, -a + 1) + sage: P3 = K.ideal(3, a + 1) sage: P5 = K.ideal(a) sage: KS2, gens, fromKS2, toKS2 = K.selmer_space([P2, P3, P5], 2) sage: KS2 @@ -5262,9 +5282,9 @@ def selmer_space(self, S, p, proof=None): sage: [K.ideal(g).factor() for g in gens] [(Fractional ideal (2, a + 1)) * (Fractional ideal (3, a + 1)), - Fractional ideal (a), - (Fractional ideal (2, a + 1))^2, - 1] + Fractional ideal (a), + (Fractional ideal (2, a + 1))^2, + 1] sage: toKS2(10) (0, 0, 1, 1) @@ -5366,6 +5386,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin into the compositum, if the fields are endowed with a real or complex embedding:: + sage: # needs sage.symbolic sage: K1 = NumberField(x^4 - 2, 'a', embedding=RR(2^(1/4))) sage: K2 = NumberField(x^4 - 2, 'a', embedding=RR(-2^(1/4))) sage: K1.composite_fields(K2) @@ -5378,16 +5399,17 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin With ``preserve_embedding`` set to ``False``, the embeddings are ignored:: - sage: K1.composite_fields(K2, preserve_embedding=False) + sage: K1.composite_fields(K2, preserve_embedding=False) # needs sage.symbolic [Number Field in a with defining polynomial x^4 - 2 with a = 1.189207115002722?, Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500] Changing the embedding selects a different compositum:: - sage: K3 = NumberField(x^4 - 2, 'a', embedding=CC(2^(1/4)*I)) - sage: [F, f, g, k], = K1.composite_fields(K3, both_maps=True); F - Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500 with a0 = -2.378414230005443? + 1.189207115002722?*I - sage: f(K1.0), g(K3.0) + sage: K3 = NumberField(x^4 - 2, 'a', embedding=CC(2^(1/4)*I)) # needs sage.symbolic + sage: [F, f, g, k], = K1.composite_fields(K3, both_maps=True); F # needs sage.symbolic + Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500 + with a0 = -2.378414230005443? + 1.189207115002722?*I + sage: f(K1.0), g(K3.0) # needs sage.symbolic (1/240*a0^5 - 41/120*a0, 1/120*a0^5 + 19/60*a0) If no embeddings are specified, the maps into the compositum @@ -5396,12 +5418,15 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: Q1. = NumberField(x^4 + 10*x^2 + 1) sage: Q2. = NumberField(x^4 + 16*x^2 + 4) sage: Q1.composite_fields(Q2, 'c') - [Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600] - sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, 'c', both_maps=True)[0] + [Number Field in c with defining polynomial + x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600] + sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, 'c', + ....: both_maps=True)[0] sage: Q1_into_F Ring morphism: From: Number Field in a with defining polynomial x^4 + 10*x^2 + 1 - To: Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600 + To: Number Field in c with defining polynomial + x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600 Defn: a |--> 19/14400*c^7 + 137/1800*c^5 + 2599/3600*c^3 + 8/15*c This is just one of four embeddings of ``Q1`` into ``F``:: @@ -5415,7 +5440,8 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: x = polygen(ZZ) sage: A. = NumberField(x^3 - 7, embedding=CC(-0.95+1.65*I)) - sage: B. = NumberField(x^9 - 7, embedding=QQbar.polynomial_root(x^9 - 7, RIF(1.2, 1.3))) + sage: r = QQbar.polynomial_root(x^9 - 7, RIF(1.2, 1.3)) + sage: B. = NumberField(x^9 - 7, embedding=r) sage: len(A.composite_fields(B, preserve_embedding=True)) 2 @@ -5458,7 +5484,8 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin From: Cyclotomic Field of order 3 and degree 2 To: Number Field in a with defining polynomial x^3 - 5 over its base field Defn: w |--> -1/2*b - 1/2, - Relative number field endomorphism of Number Field in a with defining polynomial x^3 - 5 over its base field + Relative number field endomorphism of Number Field in a + with defining polynomial x^3 - 5 over its base field Defn: a |--> a b |--> b, None)] @@ -5511,7 +5538,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin Check that the bugs reported at :trac:`24357` are fixed:: sage: A. = NumberField(x^9 - 7) - sage: B. = NumberField(x^3-7, embedding=a^3) + sage: B. = NumberField(x^3 - 7, embedding=a^3) sage: C. = QuadraticField(-1) sage: B.composite_fields(C) [Number Field in bc with defining polynomial x^6 + 3*x^4 + 14*x^3 + 3*x^2 - 42*x + 50] @@ -5689,7 +5716,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin def absolute_degree(self): r""" - Return the degree of self over `\QQ`. + Return the degree of ``self`` over `\QQ`. EXAMPLES:: @@ -6017,7 +6044,7 @@ def factor(self, n): def prime_factors(self, x): """ - Return a list of the prime ideals of self which divide + Return a list of the prime ideals of ``self`` which divide the ideal generated by `x`. OUTPUT: list of prime ideals (a new list is returned each time this @@ -6352,7 +6379,7 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non sage: G[2](b1) 1/12*b1^4 + 1/2*b1 - many examples for higher degrees may be found in the online databases + Many examples for higher degrees may be found in the online databases http://galoisdb.math.upb.de/ by Jürgen Klüners and Gunter Malle and https://www.lmfdb.org/NumberField/ by the LMFDB collaboration, although these might need a lot of computing time. @@ -6364,7 +6391,7 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non sage: x = polygen(QQ) sage: K. = NumberField(x^2 + 1) sage: R. = PolynomialRing(K) - sage: L = K.extension(t^5-t+a, 'b') + sage: L = K.extension(t^5 - t + a, 'b') sage: L.galois_group() ...DeprecationWarning: Use .absolute_field().galois_group() if you want the Galois group of the absolute field @@ -6375,7 +6402,7 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non We check that the changes in :trac:`28782` won't break code that used v1 Galois groups:: - sage: G = NumberField(x^3-2, 'a').galois_group(type="pari") + sage: G = NumberField(x^3 - 2, 'a').galois_group(type="pari") ...DeprecationWarning: the different Galois types have been merged into one class See https://github.com/sagemath/sage/issues/28782 for details. sage: G.group() @@ -6733,12 +6760,12 @@ def reduced_gram_matrix(self, prec=None): def _positive_integral_elements_with_trace(self, C): r""" - Find all totally positive integral elements in self whose + Find all totally positive integral elements in ``self`` whose trace is between C[0] and C[1], inclusive. .. note:: - This is currently only implemented in the case that self is + This is currently only implemented in the case that ``self`` is totally real, since it requires exact computation of :meth:`.reduced_gram_matrix`. @@ -7050,7 +7077,7 @@ def signature(self): sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 1, 'a').signature() (0, 1) - sage: NumberField(x^3-2, 'a').signature() + sage: NumberField(x^3 - 2, 'a').signature() (1, 1) """ r1, r2 = self.pari_nf().nf_get_sign() @@ -7343,7 +7370,7 @@ def S_unit_group(self, proof=None, S=None): INPUT: - - ``proof`` (bool, default True) flag passed to ``pari``. + - ``proof`` -- bool (default: ``True``); flag passed to PARI - ``S`` -- list or tuple of prime ideals, or an ideal, or a single ideal or element from which an ideal can be constructed, in @@ -7391,16 +7418,25 @@ def S_unit_group(self, proof=None, S=None): sage: K. = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=K.ideal(6).prime_factors()); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 - with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: K. = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=K.ideal(6)); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 - with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: K. = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=6); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 - with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: U.primes() (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), @@ -8209,8 +8245,8 @@ def _coerce_from_other_number_field(self, x): Two number fields both containing `i`:: - sage: K. = NumberField(x^4 + 6*x^2 + 1, embedding = CC(-2.4*I)) - sage: L. = NumberField(x^4 + 8*x^2 + 4, embedding = CC(2.7*I)) + sage: K. = NumberField(x^4 + 6*x^2 + 1, embedding=CC(-2.4*I)) + sage: L. = NumberField(x^4 + 8*x^2 + 4, embedding=CC(2.7*I)) sage: Ki = 1/2*a^3 + 5/2*a; Ki.minpoly() x^2 + 1 sage: L(Ki) @@ -8222,7 +8258,7 @@ def _coerce_from_other_number_field(self, x): i sage: Q(L(Ki)) i - sage: L( (Ki+2)^1000 ) + sage: L((Ki+2)^1000) 737533628...075020804*b^3 + 442520177...450124824*b + 793311113...453515313 This fails if we don't specify the embeddings:: @@ -8238,17 +8274,20 @@ def _coerce_from_other_number_field(self, x): Embeddings can also be `p`-adic:: + sage: # needs sage.rings.padics sage: F = Qp(73) - sage: K. = NumberField(x^4 + 6*x^2 + 1, embedding = F(1290990671961076190983179596556712119)) - sage: L. = NumberField(x^4 + 8*x^2 + 4, embedding = F(1773398470280167815153042237103591466)) + sage: K. = NumberField(x^4 + 6*x^2 + 1, + ....: embedding=F(1290990671961076190983179596556712119)) + sage: L. = NumberField(x^4 + 8*x^2 + 4, + ....: embedding=F(1773398470280167815153042237103591466)) sage: L(2*a^3 + 10*a + 3) b^3 + 6*b + 3 If we take the same non-Galois number field with two different embeddings, conversion fails:: - sage: K. = NumberField(x^3 - 4*x + 1, embedding = 0.254) - sage: L. = NumberField(x^3 - 4*x + 1, embedding = 1.86) + sage: K. = NumberField(x^3 - 4*x + 1, embedding=0.254) + sage: L. = NumberField(x^3 - 4*x + 1, embedding=1.86) sage: L(a) Traceback (most recent call last): ... @@ -8270,11 +8309,11 @@ def _coerce_from_other_number_field(self, x): Since `L2` and `L3` both embed in `K`, conversion works:: sage: K. = NumberField(x^8 - x^4 + 1) - sage: i = (x^2+1).roots(ring=K)[0][0] - sage: r2 = (x^2-2).roots(ring=K)[0][0] - sage: r3 = (x^2-3).roots(ring=K)[0][0] - sage: L2., phi2 = K.subfield(r2+i) - sage: L3., phi3 = K.subfield(r3+i) + sage: i = (x^2 + 1).roots(ring=K)[0][0] + sage: r2 = (x^2 - 2).roots(ring=K)[0][0] + sage: r3 = (x^2 - 3).roots(ring=K)[0][0] + sage: L2., phi2 = K.subfield(r2 + i) + sage: L3., phi3 = K.subfield(r3 + i) sage: i_in_L2 = L2(i); i_in_L2 1/6*a2^3 + 1/6*a2 sage: i_in_L3 = L3(i); i_in_L3 @@ -8289,8 +8328,8 @@ def _coerce_from_other_number_field(self, x): The following was fixed in :trac:`8800`:: sage: P. = QQ[] - sage: K. = NumberField(x^3-5,embedding=0) - sage: L. = K.extension(x^2+a) + sage: K. = NumberField(x^3 - 5,embedding=0) + sage: L. = K.extension(x^2 + a) sage: F,R = L.construction() sage: F(R) == L #indirect doctest True @@ -8407,7 +8446,7 @@ def _coerce_from_other_number_field(self, x): def _coerce_map_from_(self, R): r""" - Canonical coercion of a ring R into self. + Canonical coercion of a ring `R` into ``self``. Currently any ring coercing into the base ring canonically coerces into this field, as well as orders in any number field coercing into @@ -8421,7 +8460,7 @@ def _coerce_map_from_(self, R): sage: x = polygen(QQ, 'x') sage: S. = NumberField(x^3 + x + 1) - sage: S.coerce(int(4)) # indirect doctest + sage: S.coerce(int(4)) # indirect doctest 4 sage: S.coerce(-Integer(2)) -2 @@ -8446,14 +8485,14 @@ def _coerce_map_from_(self, R): Two embedded number fields with mutual coercions (testing against a bug that was fixed in :trac:`8800`):: - sage: K. = NumberField(x^4-2) - sage: L1. = NumberField(x^2-2, embedding = r4**2) - sage: L2. = NumberField(x^2-2, embedding = -r4**2) - sage: r2_1+r2_2 # indirect doctest + sage: K. = NumberField(x^4 - 2) + sage: L1. = NumberField(x^2 - 2, embedding=r4**2) + sage: L2. = NumberField(x^2 - 2, embedding=-r4**2) + sage: r2_1 + r2_2 # indirect doctest 0 - sage: (r2_1+r2_2).parent() is L1 + sage: (r2_1 + r2_2).parent() is L1 True - sage: (r2_2+r2_1).parent() is L2 + sage: (r2_2 + r2_1).parent() is L2 True Coercion of an order (testing against a bug that was fixed in @@ -8473,7 +8512,7 @@ def _coerce_map_from_(self, R): there will be no coercion from the Symbolic Ring to a Number Field:: sage: K. = QuadraticField(2) - sage: K.coerce(sqrt(2)) + sage: K.coerce(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: no canonical coercion from Symbolic Ring to Number Field in a @@ -8882,13 +8921,13 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) sage: K, CDF(a) (Number Field in a with defining polynomial x^4 - 23 with a = 2.189938703094843?, 2.1899387030948425) - sage: Ss = K.subfields(); len(Ss) # indirect doctest + sage: Ss = K.subfields(); len(Ss) # indirect doctest 3 sage: diffs = [ S.coerce_embedding()(S.gen()) - CDF(S_into_K(S.gen())) for S, S_into_K, _ in Ss ] sage: all(abs(diff) < 1e-5 for diff in diffs) True - sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest + sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest (Number Field in a0 with defining polynomial x^2 - 23 with a0 = -4.795831523312720?, -4.795831523312719) @@ -8896,7 +8935,7 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) different embedding of the degree 2 subfield:: sage: K. = NumberField(x^4 - 23, embedding=-50) - sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest + sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest (Number Field in a0 with defining polynomial x^2 - 23 with a0 = -4.795831523312720?, -4.795831523312719) @@ -9073,7 +9112,7 @@ def _order(self, gens, **kwds): Even if the order lives in a different field, caching works (currently, however, ``allow_subfield`` is incorrect :trac:`16046`):: - sage: K. = NumberField(x**4+3) + sage: K. = NumberField(x**4 + 3) sage: o = K.order([a**2], allow_subfield=True) sage: o is K.order([a**2], allow_subfield=True) True @@ -9105,7 +9144,7 @@ def free_module(self, base=None, basis=None, map=True): OUTPUT: - - `V` - a vector space over the rational numbers + - `V` -- a vector space over the rational numbers - ``from_V`` -- an isomorphism from `V` to ``self`` (if requested) @@ -9436,7 +9475,7 @@ def embeddings(self, K): def minkowski_embedding(self, B=None, prec=None): r""" - Return an nxn matrix over RDF whose columns are the images of the + Return an `n \times n` matrix over ``RDF`` whose columns are the images of the basis `\{1, \alpha, \dots, \alpha^{n-1}\}` of ``self`` over `\QQ` (as vector spaces), where here `\alpha` is the generator of ``self`` over @@ -9704,20 +9743,20 @@ def places(self, all_complex=False, prec=None): def real_places(self, prec=None): """ - Return all real places of self as homomorphisms into RIF. + Return all real places of ``self`` as homomorphisms into ``RIF``. EXAMPLES:: sage: x = polygen(QQ, 'x') sage: F. = NumberField(x^4 - 7) ; F.real_places() [Ring morphism: - From: Number Field in alpha with defining polynomial x^4 - 7 - To: Real Field with 106 bits of precision - Defn: alpha |--> -1.626576561697785743211232345494, - Ring morphism: - From: Number Field in alpha with defining polynomial x^4 - 7 - To: Real Field with 106 bits of precision - Defn: alpha |--> 1.626576561697785743211232345494] + From: Number Field in alpha with defining polynomial x^4 - 7 + To: Real Field with 106 bits of precision + Defn: alpha |--> -1.626576561697785743211232345494, + Ring morphism: + From: Number Field in alpha with defining polynomial x^4 - 7 + To: Real Field with 106 bits of precision + Defn: alpha |--> 1.626576561697785743211232345494] """ return self.places(prec=prec)[0:self.signature()[0]] @@ -11037,9 +11076,9 @@ def _libgap_(self): TESTS:: sage: K = CyclotomicField(8) - sage: K._libgap_() + sage: K._libgap_() # needs sage.libs.gap CF(8) - sage: libgap(K) # indirect doctest + sage: libgap(K) # indirect doctest # needs sage.libs.gap CF(8) """ from sage.libs.gap.libgap import libgap @@ -11086,7 +11125,7 @@ def _latex_(self): sage: Z = CyclotomicField(4) sage: Z.gen() zeta4 - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}(\zeta_{4}) Latex printing respects the generator name:: @@ -11134,7 +11173,7 @@ def _coerce_map_from_(self, K): sage: K. = CyclotomicField(12) sage: L. = CyclotomicField(132) - sage: L.coerce_map_from(K) # indirect doctest + sage: L.coerce_map_from(K) # indirect doctest Generic morphism: From: Cyclotomic Field of order 12 and degree 4 To: Cyclotomic Field of order 132 and degree 40 @@ -11184,32 +11223,33 @@ def _coerce_map_from_(self, K): Check that custom embeddings are respected (:trac:`13765`):: - sage: z105 = CDF(exp(2*pi*I/105)) # optional - sage.symbolic - sage: Ka. = CyclotomicField(105, embedding=z105^11) # optional - sage.symbolic - sage: Kb. = CyclotomicField(35, embedding=z105^6) # optional - sage.symbolic - sage: Ka.coerce_map_from(Kb) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: z105 = CDF(exp(2*pi*I/105)) + sage: Ka. = CyclotomicField(105, embedding=z105^11) + sage: Kb. = CyclotomicField(35, embedding=z105^6) + sage: Ka.coerce_map_from(Kb) Generic morphism: From: Cyclotomic Field of order 35 and degree 24 To: Cyclotomic Field of order 105 and degree 48 Defn: b -> -a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 - a^8 - a^6 + a^5 + a^3 + a - sage: CC(b) # optional - sage.symbolic + sage: CC(b) 0.936234870639737 + 0.351374824081343*I - sage: CC(-a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 # optional - sage.symbolic + sage: CC(-a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 ....: - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 ....: - a^8 - a^6 + a^5 + a^3 + a) 0.936234870639731 + 0.351374824081341*I - sage: z15 = CDF(exp(2*pi*I/15)) # optional - sage.symbolic - sage: K6 = CyclotomicField(6, embedding=-z15^5) # optional - sage.symbolic - sage: CyclotomicField(15).coerce_map_from(K6) # optional - sage.symbolic + sage: z15 = CDF(exp(2*pi*I/15)) # needs sage.symbolic + sage: K6 = CyclotomicField(6, embedding=-z15^5) # needs sage.symbolic + sage: CyclotomicField(15).coerce_map_from(K6) # needs sage.symbolic Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 15 and degree 8 Defn: zeta6 -> -zeta15^5 - sage: CyclotomicField(15, embedding=z15^4).coerce_map_from(K6) # optional - sage.symbolic + sage: CyclotomicField(15, embedding=z15^4).coerce_map_from(K6) # needs sage.symbolic Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 15 and degree 8 @@ -11273,21 +11313,22 @@ def _log_gen(self, x): sage: K._log_gen(CDF(a^4)) 4 - sage: zeta105 = CC(exp(2*pi*i/105)) # optional - sage.symbolic - sage: K. = CyclotomicField(105, embedding=zeta105^13) # optional - sage.symbolic - sage: zeta105^13, CC(a) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: zeta105 = CC(exp(2*pi*i/105)) + sage: K. = CyclotomicField(105, embedding=zeta105^13) + sage: zeta105^13, CC(a) (0.712376096951345 + 0.701797902883992*I, 0.712376096951345 + 0.701797902883991*I) - sage: K._log_gen(zeta105^26) # optional - sage.symbolic + sage: K._log_gen(zeta105^26) 2 - sage: K._log_gen(zeta105) # optional - sage.symbolic + sage: K._log_gen(zeta105) 97 - sage: zeta105, CC(a^97) # optional - sage.symbolic + sage: zeta105, CC(a^97) (0.998210129767735 + 0.0598041539450342*I, 0.998210129767736 + 0.0598041539450313*I) - sage: K._log_gen(zeta105^3) # optional - sage.symbolic + sage: K._log_gen(zeta105^3) 81 - sage: zeta105^3, CC(a)^81 # optional - sage.symbolic + sage: zeta105^3, CC(a)^81 (0.983929588598630 + 0.178556894798637*I, 0.983929588598631 + 0.178556894798635*I) @@ -11295,11 +11336,12 @@ def _log_gen(self, x): sage: K._log_gen(CDF(.5, -.8)) is None True - sage: zeta5 = cyclotomic_polynomial(5).change_ring(Qp(11)).roots()[0][0] # optional - sage.rings.padics - sage: zeta5 ^ 5 # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: zeta5 = cyclotomic_polynomial(5).change_ring(Qp(11)).roots()[0][0] + sage: zeta5 ^ 5 1 + O(11^20) - sage: K. = CyclotomicField(5, embedding=zeta5^2) # optional - sage.rings.padics - sage: K._log_gen(zeta5) # optional - sage.rings.padics + sage: K. = CyclotomicField(5, embedding=zeta5^2) + sage: K._log_gen(zeta5) 3 sage: K60. = CyclotomicField(60) @@ -11361,7 +11403,7 @@ def _element_constructor_(self, x, check=True): sage: a = k42.gen(0) sage: b = a^7; b zeta42^7 - sage: k6(b) # indirect doctest + sage: k6(b) # indirect doctest zeta6 sage: b^2 zeta42^7 - 1 @@ -11371,17 +11413,17 @@ def _element_constructor_(self, x, check=True): Conversion of elements of the :class:`~sage.rings.universal_cyclotomic_field.UniversalCyclotomicField`:: sage: CF = CyclotomicField(5) - sage: UCF. = UniversalCyclotomicField() - sage: CF(E(5)) + sage: UCF. = UniversalCyclotomicField() # needs sage.libs.gap + sage: CF(E(5)) # needs sage.libs.gap zeta5 sage: CF = CyclotomicField(10) - sage: CF(E(5)) + sage: CF(E(5)) # needs sage.libs.gap zeta10^2 Coercion of GAP cyclotomic elements is also supported:: - sage: CyclotomicField(18)(gap('E(3)')) # indirect doctest # optional - sage.libs.gap + sage: CyclotomicField(18)(gap('E(3)')) # indirect doctest # needs sage.libs.gap zeta18^3 - 1 Converting from rings of integers:: @@ -11475,11 +11517,11 @@ def _coerce_from_gap(self, x): EXAMPLES:: sage: k5. = CyclotomicField(5) - sage: w = libgap.eval('E(5)^7 + 3'); w # optional - sage.libs.gap + sage: w = libgap.eval('E(5)^7 + 3'); w # needs sage.libs.gap -3*E(5)-2*E(5)^2-3*E(5)^3-3*E(5)^4 - sage: z^7 + 3 # optional - sage.libs.gap + sage: z^7 + 3 # needs sage.libs.gap z^2 + 3 - sage: k5(w) # indirect doctest # optional - sage.libs.gap + sage: k5(w) # indirect doctest # needs sage.libs.gap z^2 + 3 It may be that GAP uses a name for the generator of the cyclotomic field. @@ -11487,28 +11529,29 @@ def _coerce_from_gap(self, x): sage: F = CyclotomicField(8) sage: z = F.gen() - sage: a = libgap(z + 1/z); a # optional - sage.libs.gap + sage: a = libgap(z + 1/z); a # needs sage.libs.gap E(8)-E(8)^3 - sage: F(a) # optional - sage.libs.gap + sage: F(a) # needs sage.libs.gap -zeta8^3 + zeta8 Matrices over cyclotomic fields are correctly dealt with it as well:: - sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') # optional - sage.libs.gap - sage: matrix(F, b) # optional - sage.libs.gap + sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') # needs sage.libs.gap + sage: matrix(F, b) # needs sage.libs.gap [ zeta8^2 1] [ 0 -zeta8^3 + zeta8 + 1] It also works with the old pexpect interface to GAP:: - sage: a = gap(z + 1/z) # optional - sage.libs.gap - sage: b = gap(Matrix(F,[[z^2,1],[0,a+1]])); b # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: a = gap(z + 1/z) + sage: b = gap(Matrix(F,[[z^2,1],[0,a+1]])); b [ [ E(4), 1 ], [ 0, 1+E(8)-E(8)^3 ] ] - sage: b[1,2] # optional - sage.libs.gap + sage: b[1,2] 1 - sage: F(b[1,2]) # optional - sage.libs.gap + sage: F(b[1,2]) 1 - sage: matrix(F, b) # optional - sage.libs.gap + sage: matrix(F, b) [ zeta8^2 1] [ 0 -zeta8^3 + zeta8 + 1] """ @@ -11535,7 +11578,7 @@ def _Hom_(self, codomain, cat=None): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2 + 3); K Number Field in a with defining polynomial x^2 + 3 - sage: CyclotomicField(3).Hom(K) # indirect doctest + sage: CyclotomicField(3).Hom(K) # indirect doctest Set of field embeddings from Cyclotomic Field of order 3 and degree 2 to Number Field in a with defining polynomial x^2 + 3 @@ -11654,7 +11697,7 @@ def embeddings(self, K): From: Cyclotomic Field of order 5 and degree 4 To: Complex Field with 53 bits of precision Defn: zeta5 |--> -0.809016994374947 + 0.587785252292473*I - sage: CyclotomicField(5).embeddings(Qp(11, 4, print_mode='digits'))[1] # optional - sage.rings.padics + sage: CyclotomicField(5).embeddings(Qp(11, 4, print_mode='digits'))[1] # needs sage.rings.padics Ring morphism: From: Cyclotomic Field of order 5 and degree 4 To: 11-adic Field with capped relative precision 4 @@ -11934,7 +11977,7 @@ def zeta(self, n=None, all=False): - ``n`` -- integer (default: ``None``, returns element of maximal order) - - ``all`` -- bool (default: ``False``) - whether to return + - ``all`` -- bool (default: ``False``); whether to return a list of all primitive `n`-th roots of unity. OUTPUT: root of unity or list @@ -12095,8 +12138,8 @@ def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding Check that :trac:`23008` is fixed:: sage: z = polygen(ZZ, 'z') - sage: K. = NumberField(z^2 - z - 1, embedding=QQbar(golden_ratio)) - sage: floor(phi) + sage: K. = NumberField(z^2 - z - 1, embedding=QQbar(golden_ratio)) # needs sage.symbolic + sage: floor(phi) # needs sage.symbolic 1 """ NumberField_absolute.__init__(self, polynomial, name=name, check=check, @@ -12146,7 +12189,7 @@ def _coerce_map_from_(self, K): EXAMPLES:: sage: K. = QuadraticField(-3) - sage: f = K.coerce_map_from(QQ); f # indirect doctest + sage: f = K.coerce_map_from(QQ); f # indirect doctest Natural morphism: From: Rational Field To: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I @@ -12155,7 +12198,7 @@ def _coerce_map_from_(self, K): sage: parent(f(3/5)) is K True - sage: g = K.coerce_map_from(ZZ); g # indirect doctest + sage: g = K.coerce_map_from(ZZ); g # indirect doctest Natural morphism: From: Integer Ring To: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I @@ -12179,11 +12222,11 @@ def _latex_(self): EXAMPLES:: sage: Z = QuadraticField(7) - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}(\sqrt{7}) sage: Z = QuadraticField(7, latex_name='x') - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}[x]/(x^{2} - 7) """ v = self.latex_variable_names()[0] @@ -12202,7 +12245,7 @@ def _polymake_init_(self): EXAMPLES:: sage: Z = QuadraticField(7) - sage: polymake(Z) # optional - jupymake # indirect doctest + sage: polymake(Z) # optional - jupymake # indirect doctest QuadraticExtension """ @@ -12363,8 +12406,8 @@ def hilbert_class_field(self, names): .. note:: For the polynomial that defines this field as a relative - extension, see the ``hilbert_class_field_defining_polynomial`` - command, which is vastly faster than this command, since it doesn't + extension, see the method :meth:`hilbert_class_field_defining_polynomial`, + which is vastly faster than this method, since it doesn't construct a relative extension. EXAMPLES:: @@ -12532,7 +12575,9 @@ def put_natural_embedding_first(v): """ Helper function for embeddings() functions for number fields. - INPUT: a list of embeddings of a number field + INPUT: + + - ``v`` -- a list of embeddings of a number field OUTPUT: ``None``. The list is altered in-place, so that, if possible, the first embedding @@ -12785,7 +12830,8 @@ def _splitting_classes_gens_(K, m, d): sage: K.degree() 20 sage: L - Number Field in zeta44_0 with defining polynomial x^5 - 2*x^4 - 16*x^3 + 24*x^2 + 48*x - 32 with zeta44_0 = 3.837971894457990? + Number Field in zeta44_0 with defining polynomial x^5 - 2*x^4 - 16*x^3 + 24*x^2 + 48*x - 32 + with zeta44_0 = 3.837971894457990? sage: L.conductor() 11 sage: _splitting_classes_gens_(L,11,5) diff --git a/src/sage/rings/number_field/number_field_base.pyx b/src/sage/rings/number_field/number_field_base.pyx index 0a4e0beb664..1d09825477a 100644 --- a/src/sage/rings/number_field/number_field_base.pyx +++ b/src/sage/rings/number_field/number_field_base.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.number_field +# sage.doctest: needs sage.rings.number_field """ Base class for all number fields @@ -135,13 +135,15 @@ cdef class NumberField(Field): else: codomain_other = other - from sage.rings.qqbar import AA - if codomain_self is AA and codomain_other is AA: - return AA - - from sage.rings.qqbar import QQbar - if codomain_self in (AA, QQbar) and codomain_other in (AA, QQbar): - return QQbar + try: + from sage.rings.qqbar import AA, QQbar + except ImportError: + pass + else: + if codomain_self is AA and codomain_other is AA: + return AA + if codomain_self in (AA, QQbar) and codomain_other in (AA, QQbar): + return QQbar def ring_of_integers(self, *args, **kwds): r""" diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 1ffd5cf07c9..27e33ad5be0 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -582,19 +582,19 @@ cdef class NumberFieldElement(NumberFieldElement_base): EXAMPLES:: sage: F = CyclotomicField(8) - sage: F.gen()._libgap_() # optional - sage.libs.gap + sage: F.gen()._libgap_() # needs sage.libs.gap E(8) - sage: libgap(F.gen()) # syntactic sugar # optional - sage.libs.gap + sage: libgap(F.gen()) # syntactic sugar # needs sage.libs.gap E(8) - sage: E8 = F.gen() # optional - sage.libs.gap - sage: libgap(E8 + 3/2*E8^2 + 100*E8^7) # optional - sage.libs.gap + sage: E8 = F.gen() # needs sage.libs.gap + sage: libgap(E8 + 3/2*E8^2 + 100*E8^7) # needs sage.libs.gap E(8)+3/2*E(8)^2-100*E(8)^3 - sage: type(_) # optional - sage.libs.gap + sage: type(_) # needs sage.libs.gap Check that :trac:`15276` is fixed:: - sage: for n in range(2,20): # optional - sage.libs.gap + sage: for n in range(2,20): # needs sage.libs.gap ....: K = CyclotomicField(n) ....: assert K(libgap(K.gen())) == K.gen(), "n = {}".format(n) ....: assert K(libgap(K.one())) == K.one(), "n = {}".format(n) @@ -622,13 +622,13 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^3 + 2) - sage: K.zero()._pari_polynomial('x') # optional - sage.libs.pari + sage: K.zero()._pari_polynomial('x') # needs sage.libs.pari 0 - sage: K.one()._pari_polynomial() # optional - sage.libs.pari + sage: K.one()._pari_polynomial() # needs sage.libs.pari 1 - sage: (a + 1)._pari_polynomial() # optional - sage.libs.pari + sage: (a + 1)._pari_polynomial() # needs sage.libs.pari y + 1 - sage: a._pari_polynomial('c') # optional - sage.libs.pari + sage: a._pari_polynomial('c') # needs sage.libs.pari c """ f = pari(self._coefficients()).Polrev() @@ -653,20 +653,20 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^3 + 2) - sage: K(1).__pari__() # optional - sage.libs.pari + sage: K(1).__pari__() # needs sage.libs.pari Mod(1, y^3 + 2) - sage: (a + 2).__pari__() # optional - sage.libs.pari + sage: (a + 2).__pari__() # needs sage.libs.pari Mod(y + 2, y^3 + 2) sage: L. = K.extension(x^2 + 2) - sage: (b + a).__pari__() # optional - sage.libs.pari + sage: (b + a).__pari__() # needs sage.libs.pari Mod(24/101*y^5 - 9/101*y^4 + 160/101*y^3 - 156/101*y^2 + 397/101*y + 364/101, y^6 + 6*y^4 - 4*y^3 + 12*y^2 + 24*y + 12) :: sage: k. = QuadraticField(-1) - sage: j.__pari__('j') # optional - sage.libs.pari + sage: j.__pari__('j') # needs sage.libs.pari Mod(j, j^2 + 1) - sage: pari(j) # optional - sage.libs.pari + sage: pari(j) # needs sage.libs.pari Mod(y, y^2 + 1) By default the variable name is 'y'. This allows 'x' to be used @@ -675,7 +675,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: P. = PolynomialRing(QQ) sage: K. = NumberField(a^2 + 1) sage: R. = PolynomialRing(K) - sage: pari(b*x) # optional - sage.libs.pari + sage: pari(b*x) # needs sage.libs.pari Mod(y, y^2 + 1)*x In PARI many variable names are reserved, for example ``theta`` @@ -683,25 +683,25 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: R. = PolynomialRing(QQ) sage: K. = NumberField(theta^2 + 1) - sage: theta.__pari__('theta') # optional - sage.libs.pari + sage: theta.__pari__('theta') # needs sage.libs.pari Traceback (most recent call last): ... PariError: theta already exists with incompatible valence - sage: theta.__pari__() # optional - sage.libs.pari + sage: theta.__pari__() # needs sage.libs.pari Mod(y, y^2 + 1) sage: k. = QuadraticField(-1) - sage: I.__pari__('I') # optional - sage.libs.pari + sage: I.__pari__('I') # needs sage.libs.pari Traceback (most recent call last): ... PariError: I already exists with incompatible valence Instead, request the variable be named different for the coercion:: - sage: pari(I) # optional - sage.libs.pari + sage: pari(I) # needs sage.libs.pari Mod(y, y^2 + 1) - sage: I.__pari__('i') # optional - sage.libs.pari + sage: I.__pari__('i') # needs sage.libs.pari Mod(i, i^2 + 1) - sage: I.__pari__('II') # optional - sage.libs.pari + sage: I.__pari__('II') # needs sage.libs.pari Mod(II, II^2 + 1) Examples with relative number fields, which always yield an @@ -709,13 +709,13 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: y = QQ['y'].gen() sage: k. = NumberField([y^2 - 7, y^3 - 2]) - sage: pari(j) # optional - sage.libs.pari + sage: pari(j) # needs sage.libs.pari Mod(42/5515*y^5 - 9/11030*y^4 - 196/1103*y^3 + 273/5515*y^2 + 10281/5515*y + 4459/11030, y^6 - 21*y^4 + 4*y^3 + 147*y^2 + 84*y - 339) sage: j^2 7 - sage: pari(j)^2 # optional - sage.libs.pari + sage: pari(j)^2 # needs sage.libs.pari Mod(7, y^6 - 21*y^4 + 4*y^3 + 147*y^2 + 84*y - 339) - sage: (j^2).__pari__('x') # optional - sage.libs.pari + sage: (j^2).__pari__('x') # needs sage.libs.pari Mod(7, x^6 - 21*x^4 + 4*x^3 + 147*x^2 + 84*x - 339) A tower of three number fields:: @@ -724,11 +724,11 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: K. = NumberField(x^2 + 2) sage: L. = NumberField(polygen(K)^2 + a) sage: M. = NumberField(polygen(L)^3 + b) - sage: L(b).__pari__() # optional - sage.libs.pari + sage: L(b).__pari__() # needs sage.libs.pari Mod(y, y^4 + 2) - sage: M(b).__pari__('c') # optional - sage.libs.pari + sage: M(b).__pari__('c') # needs sage.libs.pari Mod(-c^3, c^12 + 2) - sage: c.__pari__('c') # optional - sage.libs.pari + sage: c.__pari__('c') # needs sage.libs.pari Mod(c, c^12 + 2) """ f = self._pari_polynomial(name) @@ -751,9 +751,9 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^5 - x - 1) - sage: ((1 + 1/3*a)^4)._pari_init_() # optional - sage.libs.pari + sage: ((1 + 1/3*a)^4)._pari_init_() # needs sage.libs.pari 'Mod(1/81*y^4 + 4/27*y^3 + 2/3*y^2 + 4/3*y + 1, y^5 - y - 1)' - sage: ((1 + 1/3*a)^4)._pari_init_('a') # optional - sage.libs.pari + sage: ((1 + 1/3*a)^4)._pari_init_('a') # needs sage.libs.pari 'Mod(1/81*a^4 + 4/27*a^3 + 2/3*a^2 + 4/3*a + 1, a^5 - a - 1)' Note that _pari_init_ can fail because of reserved words in @@ -763,7 +763,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: K. = NumberField(x^5 - x - 1) sage: b = (1/2 - 2/3*theta)^3; b -8/27*theta^3 + 2/3*theta^2 - 1/2*theta + 1/8 - sage: b._pari_init_('theta') # optional - sage.libs.pari + sage: b._pari_init_('theta') # needs sage.libs.pari Traceback (most recent call last): ... PariError: theta already exists with incompatible valence @@ -771,7 +771,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): Fortunately pari_init returns everything in terms of y by default:: - sage: pari(b) # optional - sage.libs.pari + sage: pari(b) # needs sage.libs.pari Mod(-8/27*y^3 + 2/3*y^2 - 1/2*y + 1/8, y^5 - y - 1) """ return repr(self.__pari__(name=name)) @@ -933,7 +933,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: K. = NumberField(x^3 - 2) sage: a._random_element().parent() is K True - sage: K. = NumberField(x^2-5) + sage: K. = NumberField(x^2 - 5) sage: a._random_element().parent() is K True """ @@ -2010,7 +2010,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): In the following example, the class number is 2. If a factorization in prime elements exists, we will find it:: - sage: K. = NumberField(x^2-10) + sage: K. = NumberField(x^2 - 10) sage: factor(169*a + 531) (-6*a - 19) * (-3*a - 1) * (-2*a + 9) sage: factor(K(3)) @@ -2317,7 +2317,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): Using the ``extend`` keyword:: sage: K = QuadraticField(-5) - sage: z = K(-7).sqrt(extend=True); z # optional - sage.symbolic + sage: z = K(-7).sqrt(extend=True); z # needs sage.symbolic sqrt(-7) sage: CyclotomicField(4)(4).sqrt(extend=False) 2 @@ -2420,9 +2420,9 @@ cdef class NumberFieldElement(NumberFieldElement_base): If the exponent is not integral, perform this operation in the symbolic ring:: - sage: sqrt2^(1/5) # optional - sage.symbolic + sage: sqrt2^(1/5) # needs sage.symbolic 2^(1/10) - sage: sqrt2^sqrt2 # optional - sage.symbolic + sage: sqrt2^sqrt2 # needs sage.symbolic 2^(1/2*sqrt(2)) Sage follows Python's convention `0^0 = 1`:: @@ -2434,17 +2434,17 @@ cdef class NumberFieldElement(NumberFieldElement_base): TESTS:: - sage: 2^I + sage: 2^I # needs sage.symbolic 2^I Test :trac:`14895`:: sage: K. = QuadraticField(2) - sage: 2^sqrt2 # optional - sage.symbolic + sage: 2^sqrt2 # needs sage.symbolic 2^sqrt(2) sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2+1) - sage: 2^a # optional - sage.symbolic + sage: 2^a # needs sage.symbolic Traceback (most recent call last): ... TypeError: no canonical coercion from Number Field in a with defining polynomial x^2 + 1 to Symbolic Ring @@ -2942,16 +2942,16 @@ cdef class NumberFieldElement(NumberFieldElement_base): EXAMPLES:: sage: K. = QuadraticField(2) - sage: SR(a) # indirect doctest # optional - sage.symbolic + sage: SR(a) # indirect doctest # needs sage.symbolic sqrt(2) - sage: SR(3*a-5) # indirect doctest # optional - sage.symbolic + sage: SR(3*a-5) # indirect doctest # needs sage.symbolic 3*sqrt(2) - 5 sage: K. = QuadraticField(2, embedding=-1.4) - sage: SR(a) # indirect doctest # optional - sage.symbolic + sage: SR(a) # indirect doctest # needs sage.symbolic -sqrt(2) sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2 - 2) - sage: SR(a) # indirect doctest # optional - sage.symbolic + sage: SR(a) # indirect doctest # needs sage.symbolic Traceback (most recent call last): ... TypeError: an embedding into RR or CC must be specified @@ -2959,29 +2959,29 @@ cdef class NumberFieldElement(NumberFieldElement_base): Now a more complicated example:: sage: K. = NumberField(x^3 + x - 1, embedding=0.68) - sage: b = SR(a); b # indirect doctest # optional - sage.symbolic + sage: b = SR(a); b # indirect doctest # needs sage.symbolic (1/18*sqrt(31)*sqrt(3) + 1/2)^(1/3) - 1/3/(1/18*sqrt(31)*sqrt(3) + 1/2)^(1/3) - sage: (b^3 + b - 1).canonicalize_radical() # optional - sage.symbolic + sage: (b^3 + b - 1).canonicalize_radical() # needs sage.symbolic 0 Make sure we got the right one:: sage: CC(a) 0.682327803828019 - sage: CC(b) # optional - sage.symbolic + sage: CC(b) # needs sage.symbolic 0.682327803828019 Special case for cyclotomic fields:: sage: K. = CyclotomicField(19) - sage: SR(zeta) # indirect doctest # optional - sage.symbolic + sage: SR(zeta) # indirect doctest # needs sage.symbolic e^(2/19*I*pi) sage: CC(zeta) 0.945817241700635 + 0.324699469204683*I - sage: CC(SR(zeta)) # optional - sage.symbolic + sage: CC(SR(zeta)) # needs sage.symbolic 0.945817241700635 + 0.324699469204683*I - sage: SR(zeta^5 + 2) # optional - sage.symbolic + sage: SR(zeta^5 + 2) # needs sage.symbolic e^(10/19*I*pi) + 2 For degree greater than 5, sometimes Galois theory prevents a @@ -2990,22 +2990,22 @@ cdef class NumberFieldElement(NumberFieldElement_base): printed as a numerical approximation:: sage: K. = NumberField(x^5-x+1, embedding=-1) - sage: SR(a) # optional - sage.symbolic + sage: SR(a) # needs sage.symbolic -1.167303978261419? :: sage: K. = NumberField(x^6-x^3-1, embedding=1) - sage: SR(a) # optional - sage.symbolic + sage: SR(a) # needs sage.symbolic (1/2*sqrt(5) + 1/2)^(1/3) In this field, general elements cannot be written in terms of radicals, but particular elements might be:: sage: K. = NumberField(x^10 + 6*x^6 + 9*x^2 + 1, embedding=CC(0.332*I)) - sage: SR(a) # optional - sage.symbolic + sage: SR(a) # needs sage.symbolic 0.3319890295845093?*I - sage: SR(a^5+3*a) # optional - sage.symbolic + sage: SR(a^5+3*a) # needs sage.symbolic I Conversely, some elements are too complicated to be written in @@ -3017,9 +3017,9 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: K. = NumberField(QQ['x']([6, -65, 163, -185, 81, -15, 1]), embedding=4.9) sage: b = a + a^3 - sage: SR(b.minpoly()).solve(SR('x'), explicit_solutions=True) # optional - sage.symbolic + sage: SR(b.minpoly()).solve(SR('x'), explicit_solutions=True) # needs sage.symbolic [] - sage: SR(b) # optional - sage.symbolic + sage: SR(b) # needs sage.symbolic 1/8*(sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5)^3 + 1/2*sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5/2 @@ -3031,7 +3031,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): sage: p = x^8 + x^7 - 9*x^6 - 3*x^5 - 6*x^4 + x^3 - 14*x^2 + 2*x + 2 sage: rt = sorted(p.roots(AA, multiplicities=False))[1] sage: K. = NumberField(p, embedding=rt) - sage: SR(a) # optional - sage.symbolic + sage: SR(a) # needs sage.symbolic -0.3056815681115094? """ @@ -4200,7 +4200,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): EXAMPLES:: sage: R. = QQ[] - sage: K. = NumberField(x^4+3*x^2-17) + sage: K. = NumberField(x^4 + 3*x^2 - 17) sage: b = a/2 sage: b.global_height() 0.789780699008... @@ -4717,27 +4717,29 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): EXAMPLES:: + sage: # optional - magma sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 + 2) # optional - magma - sage: a._magma_init_(magma) # optional - magma + sage: K. = NumberField(x^3 + 2) + sage: a._magma_init_(magma) '(_sage_[...]![0, 1, 0])' - sage: m = magma((2/3)*a^2 - 17/3); m # optional - magma + sage: m = magma((2/3)*a^2 - 17/3); m 1/3*(2*a^2 - 17) - sage: m.sage() # optional - magma + sage: m.sage() 2/3*a^2 - 17/3 An element of a cyclotomic field. :: - sage: K = CyclotomicField(9) # optional - magma - sage: K.gen() # optional - magma + sage: # optional - magma + sage: K = CyclotomicField(9) + sage: K.gen() zeta9 - sage: K.gen()._magma_init_(magma) # optional - magma + sage: K.gen()._magma_init_(magma) '(_sage_[...]![0, 1, 0, 0, 0, 0])' - sage: magma(K.gen()) # optional - magma + sage: magma(K.gen()) zeta9 - sage: _.sage() # optional - magma + sage: _.sage() zeta9 """ K = magma(self.parent()) @@ -4795,7 +4797,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): sage: b.absolute_minpoly() x^5 + 5*x^4 - 40*x^2 - 19*x + 135 - sage: b.absolute_minpoly(algorithm='pari') == b.absolute_minpoly(algorithm='sage') # optional - sage.libs.pari + sage: b.absolute_minpoly(algorithm='pari') == b.absolute_minpoly(algorithm='sage') # needs sage.libs.pari True """ return self.minpoly(var, algorithm) @@ -4840,7 +4842,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): sage: R(a).charpoly().parent() Univariate Polynomial Ring in x over Integer Ring - sage: R(a).charpoly(algorithm='pari') == R(a).charpoly(algorithm='sage') # optional - sage.libs.pari + sage: R(a).charpoly(algorithm='pari') == R(a).charpoly(algorithm='sage') # needs sage.libs.pari True """ if algorithm is None: @@ -5058,7 +5060,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): sage: K. = NumberField([x^3 + 2, x^2 + 1]) sage: a.list() [0, 1, 0] - sage: v = (K.base_field().0 + a)^2 ; v + sage: v = (K.base_field().0 + a)^2; v a^2 + 2*b*a - 1 sage: v.list() [-1, 2*b, 1] @@ -5196,7 +5198,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): sage: a.absolute_charpoly('y') y^9 + 51*y^6 + 867*y^3 + 4913 - sage: a.absolute_charpoly(algorithm='pari') == a.absolute_charpoly(algorithm='sage') # optional - sage.libs.pari + sage: a.absolute_charpoly(algorithm='pari') == a.absolute_charpoly(algorithm='sage') # needs sage.libs.pari True """ if algorithm is None: diff --git a/src/sage/rings/number_field/number_field_element_base.pyx b/src/sage/rings/number_field/number_field_element_base.pyx index ab85fb461fa..5fee5817cbc 100644 --- a/src/sage/rings/number_field/number_field_element_base.pyx +++ b/src/sage/rings/number_field/number_field_element_base.pyx @@ -21,8 +21,8 @@ cdef class NumberFieldElement_base(FieldElement): EXAMPLES:: sage: x = polygen(ZZ, 'x') - sage: k. = NumberField(x^3 + x + 1) # optional - sage.rings.number_field - sage: isinstance(a, sage.rings.number_field.number_field_element_base.NumberFieldElement_base) # optional - sage.rings.number_field + sage: k. = NumberField(x^3 + x + 1) # needs sage.rings.number_field + sage: isinstance(a, sage.rings.number_field.number_field_element_base.NumberFieldElement_base) # needs sage.rings.number_field True By design, there is a unique direct subclass:: diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 4982fc0cd7d..7d24d56c980 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -295,9 +295,9 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: sage: K. = QuadraticField(-1) - sage: (1/3 + a/2)._sympy_() # optional - sympy + sage: (1/3 + a/2)._sympy_() # needs sympy 1/3 + I/2 - sage: type(_) # optional - sympy + sage: type(_) # needs sympy """ a = self.parent().gen() @@ -506,10 +506,10 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): Verify embeddings are respected:: - sage: cf6c = CyclotomicField(6, embedding=CDF(exp(-pi*I/3))) ; z6c = cf6c.0 - sage: cf3(z6c) + sage: cf6c = CyclotomicField(6, embedding=CDF(exp(-pi*I/3))); z6c = cf6c.0 # needs sage.symbolic + sage: cf3(z6c) # needs sage.symbolic -zeta3 - sage: cf6c(z3) + sage: cf6c(z3) # needs sage.symbolic -zeta6 AUTHOR: @@ -986,9 +986,10 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: (-a-2).sign() -1 + sage: # needs sage.symbolic sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 2*x + 7, 'b', embedding=CC(-1,-sqrt(6))) # optional - sage.symbolic - sage: b.sign() # optional - sage.symbolic + sage: K. = NumberField(x^2 + 2*x + 7, 'b', embedding=CC(-1,-sqrt(6))) + sage: b.sign() Traceback (most recent call last): ... ValueError: a complex number has no sign! @@ -1822,6 +1823,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): 0 sage: (a + 1/2).real() 1/2 + sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2 + x + 1) sage: a.real() -1/2 @@ -1865,7 +1867,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): 1/2*sqrt3 sage: a.real() -1/2 - sage: SR(a) # optional - sage.symbolic + sage: SR(a) # needs sage.symbolic 1/2*I*sqrt(3) - 1/2 sage: bool(QQbar(I)*QQbar(a.imag()) + QQbar(a.real()) == QQbar(a)) True @@ -2214,7 +2216,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^2 + 1, embedding=CDF.gen()) - sage: abs(a+1) + sage: abs(a+1) # needs sage.symbolic sqrt(2) """ if mpz_sgn(self.D.value) == 1: @@ -2506,11 +2508,11 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic_sqrt): r""" EXAMPLES:: - sage: SR(1 + 2*i) # optional - sage.symbolic + sage: SR(1 + 2*i) # needs sage.symbolic 2*I + 1 sage: K. = QuadraticField(-1, embedding=CC(0,-1)) - sage: SR(1 + mi) # optional - sage.symbolic + sage: SR(1 + mi) # needs sage.symbolic -I + 1 """ from sage.symbolic.constants import I @@ -2616,7 +2618,7 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic_sqrt): EXAMPLES:: - sage: I.log() # optional - sage.symbolic + sage: I.log() # needs sage.symbolic 1/2*I*pi """ from sage.symbolic.ring import SR diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 7a4b3b2debc..b5e724a0ab4 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.pari +# sage.doctest: needs sage.libs.pari sage.rings.number_field """ Number Field Ideals @@ -2757,7 +2757,7 @@ def ideallog(self, x, gens=None, check=True): G = self.idealstar(2) invs = G.invariants() - from sage.matrix.constructor import Matrix as matrix + from sage.matrix.constructor import matrix from sage.matrix.special import identity_matrix from sage.matrix.special import zero_matrix from sage.matrix.special import diagonal_matrix 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 c53b80c2bc2..e19d0df9c1c 100644 --- a/src/sage/rings/number_field/number_field_ideal_rel.py +++ b/src/sage/rings/number_field/number_field_ideal_rel.py @@ -738,7 +738,8 @@ def ramification_index(self): sage: K.ideal(2).ramification_index() Traceback (most recent call last): ... - NotImplementedError: For an ideal in a relative number field you must use relative_ramification_index or absolute_ramification_index as appropriate + NotImplementedError: For an ideal in a relative number field you must use + relative_ramification_index or absolute_ramification_index as appropriate """ raise NotImplementedError("For an ideal in a relative number field you must use relative_ramification_index or absolute_ramification_index as appropriate") diff --git a/src/sage/rings/number_field/number_field_morphisms.pyx b/src/sage/rings/number_field/number_field_morphisms.pyx index 93ffdb6cd74..862b32ffc02 100644 --- a/src/sage/rings/number_field/number_field_morphisms.pyx +++ b/src/sage/rings/number_field/number_field_morphisms.pyx @@ -480,9 +480,9 @@ def root_from_approx(f, a): sage: root_from_approx(x^2 + 1, CC(0)) -1*I - sage: root_from_approx(x^2 - 2, sqrt(2)) + sage: root_from_approx(x^2 - 2, sqrt(2)) # needs sage.symbolic sqrt(2) - sage: root_from_approx(x^2 - 2, sqrt(3)) + sage: root_from_approx(x^2 - 2, sqrt(3)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: sqrt(3) is not a root of x^2 - 2 diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index c81d5ec67f4..143191e05f1 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -884,6 +884,7 @@ def _convert_non_number_field_element(self, x): Examples from :trac:`4727`:: + sage: # needs sage.symbolic sage: K. = QQ[sqrt(-1), sqrt(2)] sage: j I @@ -912,7 +913,8 @@ def _convert_non_number_field_element(self, x): sage: L(L) Traceback (most recent call last): ... - TypeError: unable to convert Number Field in a0 with defining polynomial x^2 + 1 over its base field to Number Field in a0 with defining polynomial x^2 + 1 over its base field + TypeError: unable to convert Number Field in a0 with defining polynomial x^2 + 1 over its base field + to Number Field in a0 with defining polynomial x^2 + 1 over its base field sage: L in L False @@ -1672,7 +1674,7 @@ def _gen_relative(self): sage: k. = NumberField(x^2 + 1); k Number Field in a with defining polynomial x^2 + 1 sage: y = polygen(k) - sage: m. = k.extension(y^2+3); m + sage: m. = k.extension(y^2 + 3); m Number Field in b with defining polynomial x^2 + 3 over its base field sage: c = m.gen(); c # indirect doctest b @@ -2455,20 +2457,20 @@ def order(self, *gens, **kwds): EXAMPLES:: - sage: P. = QQ[2^(1/2), 2^(1/3), 3^(1/2)] - sage: R = P.order([a,b,c]); R + sage: P. = QQ[2^(1/2), 2^(1/3), 3^(1/2)] # needs sage.symbolic + sage: R = P.order([a,b,c]); R # needs sage.symbolic Relative Order in Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field The base ring of an order in a relative extension is still `\ZZ`.:: - sage: R.base_ring() + sage: R.base_ring() # needs sage.symbolic Integer Ring One must give enough generators to generate a ring of finite index in the maximal order:: - sage: P.order([a, b]) + sage: P.order([a, b]) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the rank of the span of gens is wrong diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index c97a1e4a89c..e789a97bc75 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -1064,20 +1064,20 @@ def class_number(self, proof=None): EXAMPLES:: - sage: ZZ[2^(1/3)].class_number() + sage: ZZ[2^(1/3)].class_number() # needs sage.symbolic 1 - sage: QQ[sqrt(-23)].maximal_order().class_number() + sage: QQ[sqrt(-23)].maximal_order().class_number() # needs sage.symbolic 3 - sage: ZZ[120*sqrt(-23)].class_number() + sage: ZZ[120*sqrt(-23)].class_number() # needs sage.symbolic 288 Note that non-maximal orders are only supported in quadratic fields:: - sage: ZZ[120*sqrt(-23)].class_number() + sage: ZZ[120*sqrt(-23)].class_number() # needs sage.symbolic 288 - sage: ZZ[100*sqrt(3)].class_number() + sage: ZZ[100*sqrt(3)].class_number() # needs sage.symbolic 4 - sage: ZZ[11*2^(1/3)].class_number() + sage: ZZ[11*2^(1/3)].class_number() # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: computation of class numbers of non-maximal orders @@ -1554,7 +1554,7 @@ def _element_constructor_(self, x): (see :trac:`10017`):: sage: x = polygen(QQ) - sage: K. = NumberField(x^3-10) + sage: K. = NumberField(x^3 - 10) sage: ZK = K.ring_of_integers() sage: ZK.basis() [1/3*a^2 + 1/3*a + 1/3, a, a^2] @@ -1665,7 +1665,7 @@ def _magma_init_(self, magma): OUTPUT: - a MagmaElement, the magma version of this absolute order + a :class:`MagmaElement`, the magma version of this absolute order EXAMPLES:: diff --git a/src/sage/rings/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 190ea239092..448adc6b529 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -164,7 +164,8 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: R. = PolynomialRing(QQ) sage: K. = (x^3 + 2).splitting_field(); K - Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 + Number Field in a with defining polynomial + x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 sage: K. = (x^3 - 3*x + 1).splitting_field(); K Number Field in a with defining polynomial x^3 - 3*x + 1 @@ -175,11 +176,25 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No :: sage: (x^4 - x + 1).splitting_field('a', simplify=False) - Number Field in a with defining polynomial x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + 18065914012013502602456565991 + Number Field in a with defining polynomial + x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 + - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 + - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 + - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + + 18065914012013502602456565991 sage: (x^4 - x + 1).splitting_field('a', simplify=True) - Number Field in a with defining polynomial x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 + Number Field in a with defining polynomial + x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 + - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True) - Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 + Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Reducible polynomials also work:: @@ -208,7 +223,10 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: (x^4 - x + 1).splitting_field('a', simplify_all=True, map=True)[1] Ring morphism: From: Rational Field - To: Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 + To: Number Field in a with defining polynomial + x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 + - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Defn: 1 |--> 1 We can enable verbose messages:: @@ -242,13 +260,22 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Number Field in x with defining polynomial x^8 + 24*x^6 + 608*x^4 + 9792*x^2 + 53824 sage: C4pol = x^4 + x^3 + x^2 + x + 1 sage: C4pol.splitting_field('x') - Number Field in x with defining polynomial x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 + Number Field in x with defining polynomial + x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 sage: D8pol = x^4 - 2 sage: D8pol.splitting_field('x') - Number Field in x with defining polynomial x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 - 60048*x^3 - 16628*x^2 + 12008*x + 34961 + Number Field in x with defining polynomial + x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 + - 60048*x^3 - 16628*x^2 + 12008*x + 34961 sage: A4pol = x^4 - 4*x^3 + 14*x^2 - 28*x + 21 sage: A4pol.splitting_field('x') - Number Field in x with defining polynomial x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 + Number Field in x with defining polynomial + x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 + - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 sage: S4pol = x^4 + x + 1 sage: S4pol.splitting_field('x') Number Field in x with defining polynomial x^48 ... @@ -256,9 +283,11 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Some bigger examples:: sage: R. = PolynomialRing(QQ) - sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 - sage: pol15.splitting_field('a') - Number Field in a with defining polynomial x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 + sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 # needs sage.symbolic + sage: pol15.splitting_field('a') # needs sage.symbolic + Number Field in a with defining polynomial + x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: pol48.splitting_field('a') Number Field in a with defining polynomial x^48 ... @@ -268,8 +297,10 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No computation, in particular for polynomials of degree >= 12 or for relative extensions:: - sage: pol15.splitting_field('a', degree_multiple=15) - Number Field in a with defining polynomial x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 + sage: pol15.splitting_field('a', degree_multiple=15) # needs sage.symbolic + Number Field in a with defining polynomial + x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 A value for ``degree_multiple`` which isn't actually a multiple of the absolute degree of the splitting field can @@ -297,10 +328,14 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Number Field in x with defining polynomial x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: D10pol = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1 sage: D10pol.splitting_field('x') - Number Field in x with defining polynomial x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 + Number Field in x with defining polynomial + x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 sage: AGL_1_5pol = x^5 - 2 sage: AGL_1_5pol.splitting_field('x') - Number Field in x with defining polynomial x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 + Number Field in x with defining polynomial + x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 sage: A5pol = x^5 - x^4 + 2*x^2 - 2*x + 2 sage: A5pol.splitting_field('x') Number Field in x with defining polynomial x^60 ... @@ -309,11 +344,11 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No fields of too large degree (this can be used to check whether the splitting field has small degree):: - sage: (x^5+x+3).splitting_field('b', abort_degree=119) + sage: (x^5 + x + 3).splitting_field('b', abort_degree=119) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field equals 120 - sage: (x^10+x+3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) + sage: (x^10 + x + 3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field is a multiple of 180 @@ -324,7 +359,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: from sage.rings.number_field.splitting_field import SplittingFieldAbort sage: try: # long time (4s on sage.math, 2014) - ....: (x^8+x+1).splitting_field('b', abort_degree=60, simplify=False) + ....: (x^8 + x + 1).splitting_field('b', abort_degree=60, simplify=False) ....: except SplittingFieldAbort as e: ....: print(e.degree_divisor) ....: print(e.degree_multiple) diff --git a/src/sage/rings/number_field/structure.py b/src/sage/rings/number_field/structure.py index 04f316da60f..ee699716638 100644 --- a/src/sage/rings/number_field/structure.py +++ b/src/sage/rings/number_field/structure.py @@ -84,8 +84,8 @@ class NumberFieldStructure(UniqueRepresentation): sage: NumberFieldStructure(K) is NumberFieldStructure(L) False sage: from sage.rings.number_field.structure import NameChange - sage: KK. = NumberField(x^2+1, structure=NameChange(K)) - sage: LL. = NumberField(x^2+1, structure=NameChange(L)) + sage: KK. = NumberField(x^2 + 1, structure=NameChange(K)) + sage: LL. = NumberField(x^2 + 1, structure=NameChange(L)) sage: KK is LL False diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index 5e2abb154e4..87ae68a4d59 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -292,7 +292,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False f_out[n_int] = 1 if keep_fields: - if type(keep_fields) == bool: + if isinstance(keep_fields, bool): keepB = pari(int(math.floor(B*math.log(B)))) else: keepB = pari(keep_fields) @@ -337,7 +337,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False if verbose: verb_int = 1 saveout = sys.stdout - if type(verbose) == str: + if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen @@ -458,7 +458,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False print("Polynomials with nfdisc <= B:", counts[3]) for i from 0 <= i < lenS: print(S[i]) - if type(verbose) == str: + if isinstance(verbose, str): fsock.close() sys.stdout = saveout diff --git a/src/sage/rings/number_field/totallyreal_phc.py b/src/sage/rings/number_field/totallyreal_phc.py index f53358ad7dd..890a0a2f469 100644 --- a/src/sage/rings/number_field/totallyreal_phc.py +++ b/src/sage/rings/number_field/totallyreal_phc.py @@ -86,15 +86,16 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): EXAMPLES:: + sage: # optional - phc sage: from sage.rings.number_field.totallyreal_phc import __lagrange_bounds_phc - sage: __lagrange_bounds_phc(3,5,[8,1,2,0,1]) # optional - phc + sage: __lagrange_bounds_phc(3,5,[8,1,2,0,1]) [] - sage: x, y = __lagrange_bounds_phc(3,2,[8,1,2,0,1]) # optional - phc - sage: x # optional - phc + sage: x, y = __lagrange_bounds_phc(3,2,[8,1,2,0,1]) + sage: x -1.3333333333333299 - sage: y < 0.00000001 # optional - phc + sage: y < 0.00000001 True - sage: __lagrange_bounds_phc(3,1,[8,1,2,0,1]) # optional - phc + sage: __lagrange_bounds_phc(3,1,[8,1,2,0,1]) [] """ diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index 19f9224841c..65026b38885 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -12,7 +12,7 @@ :: - sage: ZZx = ZZ['x'] + sage: ZZx. = ZZ[] sage: F. = NumberField(x^2 - 2) sage: enumerate_totallyreal_fields_rel(F, 2, 2000) [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]] @@ -699,7 +699,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, EXAMPLES:: - sage: ZZx = ZZ['x'] + sage: ZZx. = ZZ[] sage: F. = NumberField(x^2 - 2) sage: enumerate_totallyreal_fields_rel(F, 1, 2000) [[1, [-2, 0, 1], xF - 1]] diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index d3a701decfe..2004f295d20 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -975,10 +975,10 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, 2. The modulus can also be given as a **symbolic expression**. :: - sage: x = var('x') - sage: X. = Qq(27, modulus = x^3 + 2*x + 1); X.modulus() + sage: x = var('x') # needs sage.symbolic + sage: X. = Qq(27, modulus = x^3 + 2*x + 1); X.modulus() # needs sage.symbolic (1 + O(3^20))*x^3 + O(3^20)*x^2 + (2 + O(3^20))*x + 1 + O(3^20) - sage: X == R + sage: X == R # needs sage.symbolic True By default, the polynomial chosen is the standard lift of the @@ -2225,10 +2225,10 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, 2. The modulus can also be given as a **symbolic expression**. :: - sage: x = var('x') - sage: X. = Zq(27, modulus = x^3 + 2*x + 1); X.modulus() + sage: x = var('x') # needs sage.symbolic + sage: X. = Zq(27, modulus = x^3 + 2*x + 1); X.modulus() # needs sage.symbolic (1 + O(3^20))*x^3 + O(3^20)*x^2 + (2 + O(3^20))*x + 1 + O(3^20) - sage: X == R + sage: X == R # needs sage.symbolic True By default, the polynomial chosen is the standard lift of the diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 21f3e458255..6dbebfb5347 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.padics +# sage.doctest: needs sage.rings.padics r""" Local Generic diff --git a/src/sage/rings/padics/local_generic_element.pyx b/src/sage/rings/padics/local_generic_element.pyx index 5a757de50bb..6c78114f395 100644 --- a/src/sage/rings/padics/local_generic_element.pyx +++ b/src/sage/rings/padics/local_generic_element.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.padics +# sage.doctest: needs sage.rings.padics """ Local Generic Element diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index d3c3a72083d..46b261c95dc 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -91,25 +91,25 @@ def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None): In this example, we verify that `g_3(0) = -1`:: sage: from sage.rings.padics.misc import gauss_sum - sage: -gauss_sum(0, 3, 1) # optional - sage.rings.padics + sage: -gauss_sum(0, 3, 1) # needs sage.rings.padics 1 + O(pi^40) Next, we verify that `g_5(a) g_5(-a) = 5 (-1)^a`:: sage: from sage.rings.padics.misc import gauss_sum - sage: gauss_sum(2,5,1)^2 - 5 # optional - sage.rings.padics + sage: gauss_sum(2,5,1)^2 - 5 # needs sage.rings.padics O(pi^84) - sage: gauss_sum(1,5,1)*gauss_sum(3,5,1) + 5 # optional - sage.rings.padics + sage: gauss_sum(1,5,1)*gauss_sum(3,5,1) + 5 # needs sage.rings.padics O(pi^84) Finally, we compute a non-trivial value:: sage: from sage.rings.padics.misc import gauss_sum - sage: gauss_sum(2,13,2) # optional - sage.rings.padics + sage: gauss_sum(2,13,2) # needs sage.rings.padics 6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 + pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 + pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242) - sage: gauss_sum(2,13,2, prec=5, factored=True) # optional - sage.rings.padics + sage: gauss_sum(2,13,2, prec=5, factored=True) # needs sage.rings.padics (2, 6 + 6*13 + 10*13^2 + O(13^5)) .. SEEALSO:: diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index 6be6bceec0a..56f241fd777 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -433,11 +433,11 @@ def plot(self, max_points=2500, **args): EXAMPLES:: - sage: Zp(3).plot() + sage: Zp(3).plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: Zp(5).plot(max_points=625) + sage: Zp(5).plot(max_points=625) # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: Zp(23).plot(rgbcolor=(1,0,0)) + sage: Zp(23).plot(rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive """ if 'pointsize' not in args: diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index a4596240d57..769b8500c7d 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.padics +# sage.doctest: needs sage.rings.padics r""" `p`-adic Generic @@ -36,7 +36,6 @@ from sage.rings.ring import PrincipalIdealDomain from sage.rings.integer import Integer from sage.rings.infinity import Infinity -from sage.rings.padics.padic_printing import pAdicPrinter from sage.rings.padics.precision_error import PrecisionError from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_not_equal @@ -59,6 +58,8 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non sage: R = Zp(17) # indirect doctest """ + from sage.rings.padics.padic_printing import pAdicPrinter + if category is None: if self.is_field(): category = Fields() @@ -1741,7 +1742,7 @@ def _richcmp_(self, other, op): sage: f == g True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1874,7 +1875,7 @@ def _richcmp_(self, other, op): sage: f == g True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1896,6 +1897,8 @@ def local_print_mode(obj, print_options, pos=None, ram_name=None): For more documentation see :class:`sage.structure.parent_gens.localvars`. """ + from sage.rings.padics.padic_printing import pAdicPrinter + if isinstance(print_options, str): print_options = {'mode': print_options} elif not isinstance(print_options, dict): diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 141af863ef5..a8d9e507b90 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -17,10 +17,11 @@ sage: R3 = QpLC(2) sage: R4 = QpLF(2) - sage: TestSuite(R1).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R2).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R3).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R4).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time + sage: # long time + sage: TestSuite(R1).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R2).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R3).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R4).run(skip=['_test_teichmuller', '_test_matrix_smith']) """ # **************************************************************************** diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 4de2b197ad1..a18ffb1cb03 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -811,7 +811,7 @@ cdef class RelaxedElement(pAdicGenericElement): def __bool__(self): r""" - Return ``True`` if this element is indistinguishable from zero. + Return ``True`` if this element is distinguishable from zero. TESTS:: diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index 3657b929c8f..3a891ec1ae8 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -30,32 +30,34 @@ import sys from cysignals.memory cimport sig_malloc, check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.structure.element cimport parent - from sage.arith.misc import factor -from sage.rings.integer_ring import ZZ -from sage.misc.misc_c import prod from sage.combinat.subset import subsets -from sage.libs.pari.all import pari +from sage.misc.misc_c import prod +from sage.rings.integer_ring import ZZ +from sage.structure.element cimport parent +try: + from sage.libs.pari.all import pari +except ImportError: + pass def cyclotomic_coeffs(nn, sparse=None): """ - Return the coefficients of the n-th cyclotomic polynomial + Return the coefficients of the `n`-th cyclotomic polynomial by using the formula .. MATH:: \\Phi_n(x) = \\prod_{d|n} (1-x^{n/d})^{\\mu(d)} - where `\\mu(d)` is the Möbius function that is 1 if d has an even - number of distinct prime divisors, -1 if it has an odd number of - distinct prime divisors, and 0 if d is not squarefree. + where `\\mu(d)` is the Möbius function that is 1 if `d` has an even + number of distinct prime divisors, `-1` if it has an odd number of + distinct prime divisors, and `0` if `d` is not squarefree. Multiplications and divisions by polynomials of the form `1-x^n` can be done very quickly in a single pass. - If sparse is ``True``, the result is returned as a dictionary of + If ``sparse`` is ``True``, the result is returned as a dictionary of the non-zero entries, otherwise the result is returned as a list of python ints. @@ -72,17 +74,19 @@ def cyclotomic_coeffs(nn, sparse=None): Check that it has the right degree:: - sage: euler_phi(30) + sage: euler_phi(30) # needs sage.libs.pari 8 - sage: R(cyclotomic_coeffs(14)).factor() + sage: R(cyclotomic_coeffs(14)).factor() # needs sage.libs.pari x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 The coefficients are not always +/-1:: sage: cyclotomic_coeffs(105) - [1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1] + [1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, + 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2, + -1, -1, 0, 0, 1, 1, 1] - In fact the height is not bounded by any polynomial in n (Erdos), + In fact the height is not bounded by any polynomial in `n` (Erdos), although takes a while just to exceed linear:: sage: v = cyclotomic_coeffs(1181895) @@ -200,10 +204,10 @@ def cyclotomic_value(n, x): INPUT: - - `n` -- an Integer, specifying which cyclotomic polynomial is to be + - ``n`` -- an Integer, specifying which cyclotomic polynomial is to be evaluated - - `x` -- an element of a ring + - ``x`` -- an element of a ring OUTPUT: @@ -247,9 +251,12 @@ def cyclotomic_value(n, x): TESTS:: - sage: R. = QQ[] - sage: K. = NumberField(x^2 + 1) - sage: for y in [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11), GF(9,'a').gen(), Zp(3)(54), i, x^2+2]: + sage: elements = [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11)] + sage: R. = QQ[]; elements += [x^2 + 2] + sage: K. = NumberField(x^2 + 1); elements += [i] # needs sage.rings.number_fields + sage: elements += [GF(9,'a').gen()] # needs sage.rings.finite_rings + sage: elements += [Zp(3)(54)] # needs sage.rings.padics + sage: for y in elements: ....: for n in [1..60]: ....: val1 = cyclotomic_value(n, y) ....: val2 = cyclotomic_polynomial(n)(y) @@ -258,29 +265,31 @@ def cyclotomic_value(n, x): ....: if val1.parent() is not val2.parent(): ....: print("Wrong parent for cyclotomic_value(%s, %s) in %s"%(n,y,parent(y))) - sage: cyclotomic_value(20, I) + sage: cyclotomic_value(20, I) # needs sage.symbolic 5 sage: a = cyclotomic_value(10, mod(3, 11)); a 6 sage: a.parent() Ring of integers modulo 11 - sage: cyclotomic_value(30, -1.0) + sage: cyclotomic_value(30, -1.0) # needs sage.rings.real_mpfr 1.00000000000000 + + sage: # needs sage.libs.pari sage: S. = R.quotient(R.cyclotomic_polynomial(15)) sage: cyclotomic_value(15, t) 0 sage: cyclotomic_value(30, t) 2*t^7 - 2*t^5 - 2*t^3 + 2*t sage: S. = R.quotient(x^10) - sage: cyclotomic_value(2^128-1, t) + sage: cyclotomic_value(2^128 - 1, t) -t^7 - t^6 - t^5 + t^2 + t + 1 - sage: cyclotomic_value(10,mod(3,4)) + sage: cyclotomic_value(10, mod(3,4)) 1 Check that the issue with symbolic element in :trac:`14982` is fixed:: - sage: a = cyclotomic_value(3, I) - sage: parent(a) + sage: a = cyclotomic_value(3, I) # needs sage.rings.number_fields + sage: parent(a) # needs sage.rings.number_fields Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ n = ZZ(n) @@ -387,7 +396,7 @@ def bateman_bound(nn): EXAMPLES:: sage: from sage.rings.polynomial.cyclotomic import bateman_bound - sage: bateman_bound(2**8*1234567893377) + sage: bateman_bound(2**8 * 1234567893377) # needs sage.libs.pari 66944986927 """ _, n = nn.val_unit(2) diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index eeb20ea35c1..cfc5f96179c 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -111,37 +111,41 @@ def __init__(self, domain): :: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: R = K['x','y']['a','b'] # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: R = K['x','y']['a','b'] sage: from sage.rings.polynomial.flatten import FlatteningMorphism - sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field - sage: f(R('v*a*x^2 + b^2 + 1/v*y')) # optional - sage.rings.number_field + sage: f = FlatteningMorphism(R) + sage: f(R('v*a*x^2 + b^2 + 1/v*y')) v*x^2*a + b^2 + (1/2*v^2)*y :: - sage: R = QQbar['x','y']['a','b'] # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R = QQbar['x','y']['a','b'] sage: from sage.rings.polynomial.flatten import FlatteningMorphism - sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field - sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) # optional - sage.rings.number_field + sage: f = FlatteningMorphism(R) + sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) # needs sage.symbolic 1.414213562373095?*x^2*a + b^2 + I*y :: - sage: R. = PolynomialRing(QQbar, 1) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 1) sage: from sage.rings.polynomial.flatten import FlatteningMorphism - sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field - sage: f.domain(), f.codomain() # optional - sage.rings.number_field + sage: f = FlatteningMorphism(R) + sage: f.domain(), f.codomain() (Multivariate Polynomial Ring in z over Algebraic Field, Multivariate Polynomial Ring in z over Algebraic Field) :: - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar) sage: from sage.rings.polynomial.flatten import FlatteningMorphism - sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field - sage: f.domain(), f.codomain() # optional - sage.rings.number_field + sage: f = FlatteningMorphism(R) + sage: f.domain(), f.codomain() (Univariate Polynomial Ring in z over Algebraic Field, Univariate Polynomial Ring in z over Algebraic Field) @@ -376,8 +380,8 @@ def _call_(self, p): sage: from sage.rings.polynomial.flatten import FlatteningMorphism sage: rings = [ZZ['x']['y']['a,b,c']] - sage: rings += [GF(4)['x','y']['a','b']] # optional - sage.rings.finite_rings - sage: rings += [AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']] # optional - sage.rings.number_field + sage: rings += [GF(4)['x','y']['a','b']] # needs sage.rings.finite_rings + sage: rings += [AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']] # needs sage.rings.number_field sage: for R in rings: ....: f = FlatteningMorphism(R) ....: g = f.section() @@ -490,8 +494,9 @@ def __init__(self, domain, D): sage: P. = AffineSpace(R, 1) sage: H = End(P) sage: f = H([z^2 + c]) - sage: f.specialization({c:1}) - Scheme endomorphism of Affine Space of dimension 1 over Real Field with 53 bits of precision + sage: f.specialization({c:1}) # needs sage.modules + Scheme endomorphism of + Affine Space of dimension 1 over Real Field with 53 bits of precision Defn: Defined on coordinates by sending (z) to (z^2 + 1.00000000000000) """ diff --git a/src/sage/rings/polynomial/groebner_fan.py b/src/sage/rings/polynomial/groebner_fan.py index 5177b2eaf27..7e067a3a087 100644 --- a/src/sage/rings/polynomial/groebner_fan.py +++ b/src/sage/rings/polynomial/groebner_fan.py @@ -1246,27 +1246,27 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), INPUT: - - ``file`` - a filename if you prefer the output + - ``file`` -- a filename if you prefer the output saved to a file. This will be in xfig format. - - ``shift`` - shift the positions of the variables in + - ``shift`` -- shift the positions of the variables in the drawing. For example, with shift=1, the corners will be b (right), c (left), and d (top). The shifting is done modulo the number of variables in the polynomial ring. The default is 0. - - ``larger`` - bool (default: ``False``); if ``True``, make + - ``larger`` -- bool (default: ``False``); if ``True``, make the triangle larger so that the shape of the Groebner region appears. Affects the xfig file but probably not the sage graphics (?) - - ``rgbcolor`` - This will not affect the saved xfig + - ``rgbcolor`` -- This will not affect the saved xfig file, only the sage graphics produced. - - ``polyfill`` - Whether or not to fill the cones with + - ``polyfill`` -- Whether or not to fill the cones with a color determined by the highest degree in each reduced Groebner basis for that cone. - - ``scale_colors`` - if True, this will normalize + - ``scale_colors`` -- if True, this will normalize color values to try to maximize the range @@ -1274,23 +1274,23 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), sage: R. = PolynomialRing(QQ,3) sage: G = R.ideal([y^3 - x^2, y^2 - 13*x,z]).groebner_fan() - sage: test_render = G.render() + sage: test_render = G.render() # needs sage.plot :: sage: R. = PolynomialRing(QQ,3) sage: G = R.ideal([x^2*y - z, y^2*z - x, z^2*x - y]).groebner_fan() - sage: test_render = G.render(larger=True) + sage: test_render = G.render(larger=True) # needs sage.plot TESTS: Testing the case where the number of generators is < 3. Currently, - this should raise a ``NotImplementedError`` error. + this should raise a :class:`NotImplementedError`. :: sage: R. = PolynomialRing(QQ, 2) - sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render() + sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render() # needs sage.plot Traceback (most recent call last): ... NotImplementedError @@ -1460,17 +1460,17 @@ def render3d(self, verbose=False): sage: R4. = PolynomialRing(QQ,4) sage: gf = R4.ideal([w^2-x,x^2-y,y^2-z,z^2-x]).groebner_fan() - sage: three_d = gf.render3d() + sage: three_d = gf.render3d() # needs sage.plot TESTS: Now test the case where the number of generators is not 4. Currently, - this should raise a ``NotImplementedError`` error. + this should raise a :class:`NotImplementedError` error. :: sage: P. = PolynomialRing(QQ, 3, order="lex") - sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d() + sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d() # needs sage.plot Traceback (most recent call last): ... NotImplementedError diff --git a/src/sage/rings/polynomial/hilbert.pyx b/src/sage/rings/polynomial/hilbert.pyx index ccf5159dfac..ff191640fc3 100644 --- a/src/sage/rings/polynomial/hilbert.pyx +++ b/src/sage/rings/polynomial/hilbert.pyx @@ -20,9 +20,10 @@ in any example with more than 34 variables. # #***************************************************************************** +import sage.interfaces.abc + from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint -from sage.interfaces.singular import Singular from cysignals.memory cimport sig_malloc from cpython.list cimport PyList_GET_ITEM @@ -476,7 +477,7 @@ def first_hilbert_series(I, grading=None, return_grading=False): cdef Polynomial_integer_dense_flint fhs = Polynomial_integer_dense_flint.__new__(Polynomial_integer_dense_flint) fhs._parent = PR fhs._is_gen = 0 - if isinstance(I.parent(), Singular): + if isinstance(I, sage.interfaces.abc.SingularElement): S = I._check_valid() # First, we need to deal with quotient rings, which also covers the case # of graded commutative rings that arise as cohomology rings in odd characteristic. diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index d84264e9d69..a117c7bd663 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -32,9 +32,9 @@ def residue_class_degree(self): EXAMPLES:: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: P = R.ideal(t^4 + t + 1) # optional - sage.rings.finite_rings - sage: P.residue_class_degree() # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: P = R.ideal(t^4 + t + 1) + sage: P.residue_class_degree() 4 """ return self.gen().degree() @@ -45,8 +45,8 @@ def residue_field(self, names=None, check=True): EXAMPLES:: - sage: R. = GF(17)[]; P = R.ideal(t^3 + 2*t + 9) # optional - sage.rings.finite_rings - sage: k. = P.residue_field(); k # optional - sage.rings.finite_rings + sage: R. = GF(17)[]; P = R.ideal(t^3 + 2*t + 9) + sage: k. = P.residue_field(); k # needs sage.rings.finite_rings Residue field in a of Principal ideal (t^3 + 2*t + 9) of Univariate Polynomial Ring in t over Finite Field of size 17 """ @@ -75,11 +75,11 @@ def groebner_basis(self, algorithm=None): sage: R. = QQ[] sage: I = R.ideal([x^2 - 1, x^3 - 1]) - sage: G = I.groebner_basis(); G # optional - sage.libs.singular + sage: G = I.groebner_basis(); G [x - 1] - sage: type(G) # optional - sage.libs.singular + sage: type(G) - sage: list(G) # optional - sage.libs.singular + sage: list(G) [x - 1] """ gb = self.gens_reduced() diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index cad5877fd0f..fc8449b340e 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -48,8 +48,8 @@ There is a permutation action on Infinite Polynomial Rings by permuting the indices of the variables:: - sage: P = Permutation(((4,5),(2,3))) # optional - sage.combinat - sage: c^P # optional - sage.combinat + sage: P = Permutation(((4,5),(2,3))) + sage: c^P x_2^3 + x_2*y_5 - 2*y_5^4 Note that ``P(0)==0``, and thus variables of index zero are invariant @@ -299,16 +299,16 @@ def polynomial(self): EXAMPLES:: - sage: X. = InfinitePolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: p = x[2]*y[1] + 3*y[0] # optional - sage.rings.finite_rings - sage: p # optional - sage.rings.finite_rings + sage: X. = InfinitePolynomialRing(GF(7)) + sage: p = x[2]*y[1] + 3*y[0] + sage: p x_2*y_1 + 3*y_0 - sage: p.polynomial() # optional - sage.rings.finite_rings + sage: p.polynomial() x_2*y_1 + 3*y_0 - sage: p.polynomial().parent() # optional - sage.rings.finite_rings + sage: p.polynomial().parent() Multivariate Polynomial Ring in x_2, x_1, x_0, y_2, y_1, y_0 over Finite Field of size 7 - sage: p.parent() # optional - sage.rings.finite_rings + sage: p.parent() Infinite polynomial ring in x, y over Finite Field of size 7 """ @@ -440,13 +440,14 @@ def subs(self, fixed=None, **kwargs): The substitution can also handle matrices:: - sage: M = matrix([[1,0], [0,2]]) # optional - sage.modules - sage: N = matrix([[0,3], [4,0]]) # optional - sage.modules - sage: g = x[0]^2 + 3*x[1] # optional - sage.modules - sage: g.subs({'x_0': M}) # optional - sage.modules + sage: # needs sage.modules + sage: M = matrix([[1,0], [0,2]]) + sage: N = matrix([[0,3], [4,0]]) + sage: g = x[0]^2 + 3*x[1] + sage: g.subs({'x_0': M}) [3*x_1 + 1 0] [ 0 3*x_1 + 4] - sage: g.subs({x[0]: M, x[1]: N}) # optional - sage.modules + sage: g.subs({x[0]: M, x[1]: N}) [ 1 9] [12 4] @@ -464,7 +465,7 @@ def subs(self, fixed=None, **kwargs): TESTS:: - sage: g.subs(fixed=x[0], x_1=N) + sage: g.subs(fixed=x[0], x_1=N) # needs sage.modules Traceback (most recent call last): ... ValueError: fixed must be a dict @@ -540,10 +541,10 @@ def is_nilpotent(self): EXAMPLES:: - sage: R. = InfinitePolynomialRing(QQbar) # optional - sage.rings.number_field - sage: (x[0] + x[1]).is_nilpotent() # optional - sage.rings.number_field + sage: R. = InfinitePolynomialRing(QQbar) # needs sage.rings.number_field + sage: (x[0] + x[1]).is_nilpotent() # needs sage.rings.number_field False - sage: R(0).is_nilpotent() # optional - sage.rings.number_field + sage: R(0).is_nilpotent() # needs sage.rings.number_field True sage: _. = InfinitePolynomialRing(Zmod(4)) sage: (2*x[0]).is_nilpotent() @@ -656,7 +657,7 @@ def _div_(self, x): sage: z = 1/(x[2]*(x[1]+x[2]))+1/(x[1]*(x[1]+x[2])) sage: z.parent() Fraction Field of Infinite polynomial ring in x over Rational Field - sage: factor(z) # optional - sage.libs.singular + sage: factor(z) # needs sage.libs.singular x_1^-1 * x_2^-1 """ if not x.variables(): @@ -896,11 +897,11 @@ def symmetric_cancellation_order(self, other): sage: X. = InfinitePolynomialRing(QQ) sage: (x[2]*x[1]).symmetric_cancellation_order(x[2]^2) (None, 1, 1) - sage: (x[2]*x[1]).symmetric_cancellation_order(x[2]*x[3]*y[1]) # optional - sage.combinat + sage: (x[2]*x[1]).symmetric_cancellation_order(x[2]*x[3]*y[1]) (-1, [2, 3, 1], y_1) - sage: (x[2]*x[1]*y[1]).symmetric_cancellation_order(x[2]*x[3]*y[1]) # optional - sage.combinat + sage: (x[2]*x[1]*y[1]).symmetric_cancellation_order(x[2]*x[3]*y[1]) (None, 1, 1) - sage: (x[2]*x[1]*y[1]).symmetric_cancellation_order(x[2]*x[3]*y[2]) # optional - sage.combinat + sage: (x[2]*x[1]*y[1]).symmetric_cancellation_order(x[2]*x[3]*y[2]) (-1, [2, 3, 1], 1) """ @@ -1097,7 +1098,7 @@ def reduce(self, I, tailreduce=False, report=None): reduction. However, reduction by ``y[1]*x[2]^2`` works, since one can change variable index 1 into 2 and 2 into 3:: - sage: p.reduce([y[1]*x[2]^2]) + sage: p.reduce([y[1]*x[2]^2]) # needs sage.libs.singular y_3*y_1^2 The next example shows that tail reduction is not done, unless @@ -1107,13 +1108,13 @@ def reduce(self, I, tailreduce=False, report=None): sage: I = (y[3])*X sage: p.reduce(I) x_3^3*y_2 + y_3*y_1^2 - sage: p.reduce(I, tailreduce=True) + sage: p.reduce(I, tailreduce=True) # needs sage.libs.singular x_3^3*y_2 Last, we demonstrate the ``report`` option:: sage: p = x[1]^2 + y[2]^2 + x[1]*x[2]*y[3] + x[1]*y[4] - sage: p.reduce(I, tailreduce=True, report=True) + sage: p.reduce(I, tailreduce=True, report=True) # needs sage.libs.singular :T[2]:> > x_1^2 + y_2^2 @@ -1258,8 +1259,8 @@ def __call__(self, *args, **kwargs): sage: a(x_1=x[100]) x_100 + x_0 - sage: M = matrix([[1,1], [2,0]]) # optional - sage.modules - sage: a(x_1=M) # optional - sage.modules + sage: M = matrix([[1,1], [2,0]]) # needs sage.modules + sage: a(x_1=M) # needs sage.modules [x_0 + 1 1] [ 2 x_0] """ @@ -1389,8 +1390,8 @@ def __pow__(self, n): sage: X. = InfinitePolynomialRing(QQ, implementation='sparse') sage: p = x[10]*y[2] + 2*x[1]*y[3] - sage: P = Permutation(((1,2),(3,4,5))) # optional - sage.combinat - sage: p^P # indirect doctest # optional - sage.combinat + sage: P = Permutation(((1,2),(3,4,5))) + sage: p^P # indirect doctest x_10*y_1 + 2*x_2*y_4 """ @@ -1480,10 +1481,10 @@ def _richcmp_(self, x, op): An example in which a previous version had failed:: - sage: X. = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='sparse') # optional - sage.rings.finite_rings - sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') # optional - sage.rings.finite_rings - sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') # optional - sage.rings.finite_rings - sage: p < q # indirect doctest # optional - sage.rings.finite_rings + sage: X. = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='sparse') + sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') + sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') + sage: p < q False """ @@ -1583,10 +1584,10 @@ def _richcmp_(self, x, op): An example in which a previous version had failed:: - sage: X. = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='dense') # optional - sage.rings.finite_rings - sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') # optional - sage.rings.finite_rings - sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') # optional - sage.rings.finite_rings - sage: p < q # optional - sage.rings.finite_rings + sage: X. = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='dense') + sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') + sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') + sage: p < q False """ @@ -1665,8 +1666,8 @@ def __pow__(self, n): sage: x[10]^3 x_10^3 sage: p = x[10]*y[2] + 2*x[1]*y[3] - sage: P = Permutation(((1,2),(3,4,5))) # optional - sage.combinat - sage: p^P # optional - sage.combinat + sage: P = Permutation(((1,2),(3,4,5))) + sage: p^P x_10*y_1 + 2*x_2*y_4 """ diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index b9318c36d49..32f62258a7c 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -86,10 +86,10 @@ There is a permutation action on the variables, by permuting positive variable indices:: - sage: P = Permutation(((10,1))) # optional - sage.combinat - sage: p^P # optional - sage.combinat + sage: P = Permutation(((10,1))) + sage: p^P x_5*x_1^2 + 3*x_1^2*y_10 + 2*x_1^2 - sage: p2^P # optional - sage.combinat + sage: p2^P alpha_5*alpha_1^2 + 3*alpha_1^2*beta_10 + 2*alpha_1^2 Note that `x_0^P = x_0`, since the permutations only change *positive* @@ -103,7 +103,7 @@ base ring is a field, one can compute Symmetric Groebner Bases:: sage: J = A * (alpha[1]*beta[2]) - sage: J.groebner_basis() # optional - sage.combinat + sage: J.groebner_basis() # needs sage.combinat sage.libs.singular [alpha_1*beta_2, alpha_2*beta_1] For more details, see :class:`~sage.rings.polynomial.symmetric_ideal.SymmetricIdeal`. @@ -810,8 +810,8 @@ def construction(self): EXAMPLES:: - sage: R. = InfinitePolynomialRing(GF(5)) # optional - sage.rings.finite_rings - sage: R.construction() # optional - sage.rings.finite_rings + sage: R. = InfinitePolynomialRing(GF(5)) + sage: R.construction() [InfPoly{[x,y], "lex", "dense"}, Finite Field of size 5] """ @@ -1109,10 +1109,10 @@ def is_noetherian(self): TESTS:: - sage: R = InfinitePolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: R # optional - sage.rings.finite_rings + sage: R = InfinitePolynomialRing(GF(2)) + sage: R Infinite polynomial ring in x over Finite Field of size 2 - sage: R.is_noetherian() # optional - sage.rings.finite_rings + sage: R.is_noetherian() False sage: R. = InfinitePolynomialRing(QQ) @@ -1136,10 +1136,10 @@ def is_field(self, *args, **kwds): TESTS:: - sage: R = InfinitePolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: R # optional - sage.rings.finite_rings + sage: R = InfinitePolynomialRing(GF(2)) + sage: R Infinite polynomial ring in x over Finite Field of size 2 - sage: R.is_field() # optional - sage.rings.finite_rings + sage: R.is_field() False :trac:`9443`:: @@ -1230,8 +1230,8 @@ def gen(self, i=None): x_1 sage: X.gen() is X.gen(0) True - sage: XX = InfinitePolynomialRing(GF(5)) # optional - sage.rings.finite_rings - sage: XX.gen(0) is XX.gen() # optional - sage.rings.finite_rings + sage: XX = InfinitePolynomialRing(GF(5)) + sage: XX.gen(0) is XX.gen() True """ if i is not None and i > len(self._names): @@ -1297,10 +1297,10 @@ def characteristic(self): EXAMPLES:: - sage: X. = InfinitePolynomialRing(GF(25,'a')) # optional - sage.rings.finite_rings - sage: X # optional - sage.rings.finite_rings + sage: X. = InfinitePolynomialRing(GF(25,'a')) # needs sage.rings.finite_rings + sage: X # needs sage.rings.finite_rings Infinite polynomial ring in x, y over Finite Field in a of size 5^2 - sage: X.characteristic() # optional - sage.rings.finite_rings + sage: X.characteristic() # needs sage.rings.finite_rings 5 """ @@ -1349,8 +1349,8 @@ def order(self): EXAMPLES:: - sage: R. = InfinitePolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: R.order() # optional - sage.rings.finite_rings + sage: R. = InfinitePolynomialRing(GF(2)) + sage: R.order() +Infinity """ from sage.rings.infinity import Infinity @@ -1363,13 +1363,14 @@ def key_basis(self): EXAMPLES:: - sage: R. = InfinitePolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: R.key_basis() # optional - sage.rings.finite_rings + sage: R. = InfinitePolynomialRing(GF(2)) + sage: R.key_basis() # needs sage.combinat Key polynomial basis over Finite Field of size 2 """ from sage.combinat.key_polynomial import KeyPolynomialBasis return KeyPolynomialBasis(self) + class InfinitePolynomialGen(SageObject): """ This class provides the object which is responsible for returning @@ -1572,8 +1573,8 @@ def construction(self): EXAMPLES:: - sage: R. = InfinitePolynomialRing(GF(5)) # optional - sage.rings.finite_rings - sage: R.construction() # optional - sage.rings.finite_rings + sage: R. = InfinitePolynomialRing(GF(5)) + sage: R.construction() [InfPoly{[x,y], "lex", "dense"}, Finite Field of size 5] """ return [InfinitePolynomialFunctor(self._names, self._order, 'dense'), self._base] diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index b9aa5a69f8e..4be246c6688 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -27,8 +27,8 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: L. = LaurentPolynomialRing(QQ) # indirect doctest # optional - sage.modules - sage: x*y # optional - sage.modules + sage: L. = LaurentPolynomialRing(QQ) # indirect doctest # needs sage.modules + sage: x*y # needs sage.modules x*y """ cdef type t = type(self) @@ -110,18 +110,19 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: - sage: L. = LaurentPolynomialRing(QQ) # optional - sage.modules - sage: L(42)._integer_(ZZ) # optional - sage.modules + sage: # needs sage.modules + sage: L. = LaurentPolynomialRing(QQ) + sage: L(42)._integer_(ZZ) 42 - sage: a._integer_(ZZ) # optional - sage.modules + sage: a._integer_(ZZ) Traceback (most recent call last): ... ValueError: a is not constant - sage: L(2/3)._integer_(ZZ) # optional - sage.modules + sage: L(2/3)._integer_(ZZ) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer - sage: ZZ(L(42)) # optional - sage.modules + sage: ZZ(L(42)) 42 """ if not self.is_constant(): @@ -152,14 +153,15 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: - sage: L. = LaurentPolynomialRing(QQ) # optional - sage.modules - sage: L(42)._rational_() # optional - sage.modules + sage: # needs sage.modules + sage: L. = LaurentPolynomialRing(QQ) + sage: L(42)._rational_() 42 - sage: a._rational_() # optional - sage.modules + sage: a._rational_() Traceback (most recent call last): ... ValueError: a is not constant - sage: QQ(L(2/3)) # optional - sage.modules + sage: QQ(L(2/3)) 2/3 """ if not self.is_constant(): @@ -175,14 +177,14 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): sage: R. = LaurentPolynomialRing(QQ) sage: a = x^2 + 3*x^3 + 5*x^-1 - sage: a.change_ring(GF(3)) # optional - sage.rings.finite_rings + sage: a.change_ring(GF(3)) 2*x^-1 + x^2 Check that :trac:`22277` is fixed:: - sage: R. = LaurentPolynomialRing(QQ) - sage: a = 2*x^2 + 3*x^3 + 4*x^-1 - sage: a.change_ring(GF(3)) # optional - sage.rings.finite_rings + sage: R. = LaurentPolynomialRing(QQ) # needs sage.modules + sage: a = 2*x^2 + 3*x^3 + 4*x^-1 # needs sage.modules + sage: a.change_ring(GF(3)) # needs sage.modules -x^2 + x^-1 """ return self._parent.change_ring(R)(self) @@ -251,40 +253,42 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: k. = GF(9) # optional - sage.rings.finite_rings - sage: R. = LaurentPolynomialRing(k) # optional - sage.rings.finite_rings - sage: f = x*a + a # optional - sage.rings.finite_rings - sage: f.map_coefficients(lambda a: a + 1) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(9) + sage: R. = LaurentPolynomialRing(k) + sage: f = x*a + a + sage: f.map_coefficients(lambda a: a + 1) (a + 1) + (a + 1)*x - sage: R. = LaurentPolynomialRing(k, 2) # optional - sage.rings.finite_rings - sage: f = x*a + 2*x^3*y*a + a # optional - sage.rings.finite_rings - sage: f.map_coefficients(lambda a: a + 1) # optional - sage.rings.finite_rings + sage: R. = LaurentPolynomialRing(k, 2) + sage: f = x*a + 2*x^3*y*a + a + sage: f.map_coefficients(lambda a: a + 1) (2*a + 1)*x^3*y + (a + 1)*x + a + 1 Examples with different base ring:: - sage: R. = GF(9); S. = GF(81) # optional - sage.rings.finite_rings - sage: h = Hom(R, S)[0]; h # optional - sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: R. = GF(9); S. = GF(81) + sage: h = Hom(R, S)[0]; h Ring morphism: From: Finite Field in r of size 3^2 To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 - sage: T. = LaurentPolynomialRing(R, 2) # optional - sage.modules sage.rings.finite_rings - sage: f = r*X + Y # optional - sage.modules sage.rings.finite_rings - sage: g = f.map_coefficients(h); g # optional - sage.modules sage.rings.finite_rings + sage: T. = LaurentPolynomialRing(R, 2) + sage: f = r*X + Y + sage: g = f.map_coefficients(h); g (2*s^3 + 2*s^2 + 1)*X + Y - sage: g.parent() # optional - sage.modules sage.rings.finite_rings + sage: g.parent() Multivariate Laurent Polynomial Ring in X, Y over Finite Field in s of size 3^4 sage: h = lambda x: x.trace() - sage: g = f.map_coefficients(h); g # optional - sage.modules sage.rings.finite_rings + sage: g = f.map_coefficients(h); g X - Y - sage: g.parent() # optional - sage.modules sage.rings.finite_rings + sage: g.parent() Multivariate Laurent Polynomial Ring in X, Y over Finite Field in r of size 3^2 - sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g # optional - sage.modules sage.rings.finite_rings + sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g X - Y - sage: g.parent() # optional - sage.modules sage.rings.finite_rings + sage: g.parent() Multivariate Laurent Polynomial Ring in X, Y over Finite Field of size 3 """ @@ -329,13 +333,14 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): :: - sage: S. = LaurentPolynomialRing(GF(5)) # optional - sage.rings.finite_rings sage.rings.padics - sage: T. = PolynomialRing(pAdicRing(5)) # optional - sage.rings.finite_rings sage.rings.padics - sage: S(t) # optional - sage.rings.finite_rings sage.rings.padics + sage: # needs sage.rings.padics + sage: S. = LaurentPolynomialRing(GF(5)) + sage: T. = PolynomialRing(pAdicRing(5)) + sage: S(t) s - sage: parent(S(t)) # optional - sage.rings.finite_rings sage.rings.padics + sage: parent(S(t)) Univariate Laurent Polynomial Ring in s over Finite Field of size 5 - sage: parent(S(t)[1]) # optional - sage.rings.finite_rings sage.rings.padics + sage: parent(S(t)[1]) Finite Field of size 5 :: @@ -385,7 +390,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: Pxy = PolynomialRing(QQ, "x,y") sage: Paxb = PolynomialRing(QQ, "a,x,b") sage: Qx = PolynomialRing(ZZ, "x") - sage: Rx = PolynomialRing(GF(2), "x") # optional - sage.rings.finite_rings + sage: Rx = PolynomialRing(GF(2), "x") sage: p1 = Lx.gen() sage: p2 = Lx.zero() sage: p3 = Lx.one() @@ -395,7 +400,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: Pxes = [(Px, Px.gen()), (Qx, Qx.gen()), ....: (Pxy, Pxy.gen(0)), (Paxb, Paxb.gen(1))] - sage: Pxes += [(Rx, Rx.gen())] # optional - sage.rings.finite_rings + sage: Pxes += [(Rx, Rx.gen())] sage: for P, x in Pxes: ....: assert P(p1) == x and parent(P(p1)) is P ....: assert P(p2) == P.zero() and parent(P(p2)) is P @@ -510,13 +515,14 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): You can specify a map on the base ring:: + sage: # needs sage.rings.number_field sage: Zx. = ZZ[] - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: cc = K.hom([-i]) # optional - sage.rings.number_field - sage: R. = LaurentPolynomialRing(K) # optional - sage.rings.number_field - sage: H = Hom(R, R) # optional - sage.rings.number_field - sage: phi = H([t^-2], base_map=cc) # optional - sage.rings.number_field - sage: phi(i*t) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: cc = K.hom([-i]) + sage: R. = LaurentPolynomialRing(K) + sage: H = Hom(R, R) + sage: phi = H([t^-2], base_map=cc) + sage: phi(i*t) -i*t^-2 """ x = im_gens[0] @@ -811,22 +817,22 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ EXAMPLES:: + sage: # needs sage.symbolic sage: R. = LaurentPolynomialRing(QQ) sage: f = x^3 + 2/x - sage: g = f._symbolic_(SR); g # optional - sage.symbolic + sage: g = f._symbolic_(SR); g (x^4 + 2)/x - sage: g(x=2) # optional - sage.symbolic + sage: g(x=2) 9 - - sage: g = SR(f) # optional - sage.symbolic - sage: g(x=2) # optional - sage.symbolic + sage: g = SR(f) + sage: g(x=2) 9 Since :trac:`24072` the symbolic ring does not accept positive characteristic:: - sage: R. = LaurentPolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: SR(2*w^3 + 1) # optional - sage.rings.finite_rings sage.symbolic + sage: R. = LaurentPolynomialRing(GF(7)) + sage: SR(2*w^3 + 1) # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -1046,10 +1052,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ EXAMPLES:: - sage: R. = LaurentPolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: f = 1/x^3 + x + x^2 + 3*x^4 # optional - sage.rings.finite_rings - sage: g = 1 - x + x^2 - x^4 # optional - sage.rings.finite_rings - sage: f*g # optional - sage.rings.finite_rings + sage: R. = LaurentPolynomialRing(GF(2)) + sage: f = 1/x^3 + x + x^2 + 3*x^4 + sage: g = 1 - x + x^2 - x^4 + sage: f*g x^-3 + x^-2 + x^-1 + x^8 """ cdef LaurentPolynomial_univariate right = right_r @@ -1625,10 +1631,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): The answer is dependent of the base ring:: - sage: S. = LaurentPolynomialRing(QQbar) # optional - sage.rings.number_field - sage: (2 + 4*t + 2*t^2).is_square() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: S. = LaurentPolynomialRing(QQbar) + sage: (2 + 4*t + 2*t^2).is_square() False - sage: (2 + 4*u + 2*u^2).is_square() # optional - sage.rings.number_field + sage: (2 + 4*u + 2*u^2).is_square() True TESTS:: @@ -1751,12 +1758,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Check that :trac:`28187` is fixed:: + sage: # needs sage.symbolic sage: R. = LaurentPolynomialRing(ZZ) sage: p = 1/x + 1 + x - sage: x,y = var("x, y") # optional - sage.symbolic - sage: p._derivative(x) # optional - sage.symbolic + sage: x,y = var("x, y") + sage: p._derivative(x) -x^-2 + 1 - sage: p._derivative(y) # optional - sage.symbolic + sage: p._derivative(y) Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1903,7 +1911,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: R. = LaurentPolynomialRing(ZZ) sage: f = 4*t^-7 + 3*t^3 + 2*t^4 + t^-6 - sage: f.factor() # optional - sage.libs.pari + sage: f.factor() # needs sage.libs.pari (t^-7) * (4 + t + 3*t^10 + 2*t^11) """ cdef LaurentPolynomial_univariate u, d diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 2289b69e111..aa18314e523 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.libs.singular sage.modules (because all doctests need laurent_polynomial_mpair, Groebner bases) r""" Ideals in Laurent polynomial rings. @@ -57,15 +57,16 @@ def __init__(self, ring, gens, coerce=True, hint=None): sage: R.ideal([x, y]) Ideal (x, y) of Multivariate Laurent Polynomial Ring in x, y over Integer Ring - sage: R. = LaurentPolynomialRing(GF(3), 2) # optional - sage.rings.finite_rings - sage: R.ideal([x0^2, x1^-3]) # optional - sage.rings.finite_rings + sage: R. = LaurentPolynomialRing(GF(3), 2) + sage: R.ideal([x0^2, x1^-3]) Ideal (x0^2, x1^-3) of Multivariate Laurent Polynomial Ring in x0, x1 over Finite Field of size 3 sage: P. = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([~x + ~y - 1]) sage: print(I) - Ideal (-1 + y^-1 + x^-1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field + Ideal (-1 + y^-1 + x^-1) of + Multivariate Laurent Polynomial Ring in x, y over Rational Field sage: I.is_zero() False sage: (x^(-2) + x^(-1)*y^(-1) - x^(-1)) in I @@ -83,9 +84,9 @@ def __init__(self, ring, gens, coerce=True, hint=None): (Ideal (-1/2*z^2 + y - 1/2*z, x + z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field,) - sage: K. = CyclotomicField(4) # optional - sage.rings.number_field - sage: J = I1.base_extend(K) # optional - sage.rings.number_field - sage: J.base_ring() # optional - sage.rings.number_field + sage: K. = CyclotomicField(4) # needs sage.rings.number_field + sage: J = I1.base_extend(K) # needs sage.rings.number_field + sage: J.base_ring() # needs sage.rings.number_field Cyclotomic Field of order 4 and degree 2 """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) @@ -228,8 +229,8 @@ def base_extend(self, F): sage: P. = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([x + y]) - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: I.base_extend(K) # optional - sage.rings.number_field + sage: K. = CyclotomicField(3) # needs sage.rings.number_field + sage: I.base_extend(K) # needs sage.rings.number_field Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 """ @@ -250,8 +251,8 @@ def apply_map(self, f, new_ring=None, new_base_ring=None, apply_to_hint=None): sage: I.apply_map(lambda z: z + 2) Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: K. = CyclotomicField(4) # optional - sage.rings.number_field - sage: I.apply_map(lambda z: z + 2, new_base_ring=K) # optional - sage.rings.number_field + sage: K. = CyclotomicField(4) # needs sage.rings.number_field + sage: I.apply_map(lambda z: z + 2, new_base_ring=K) # needs sage.rings.number_field Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 4 and degree 2 """ @@ -276,16 +277,17 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): EXAMPLES:: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: P. = LaurentPolynomialRing(K, 2) # optional - sage.rings.number_field - sage: I = P.ideal([x + z, y - z]) # optional - sage.rings.number_field - sage: h = K.hom([z^2]) # optional - sage.rings.number_field - sage: I.apply_coeff_map(h) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: P. = LaurentPolynomialRing(K, 2) + sage: I = P.ideal([x + z, y - z]) + sage: h = K.hom([z^2]) + sage: I.apply_coeff_map(h) Ideal (x - z - 1, y + z + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 - sage: K1. = CyclotomicField(12) # optional - sage.rings.number_field - sage: h1 = K.hom([z1^4]) # optional - sage.rings.number_field - sage: I.apply_coeff_map(h1, new_base_ring=K1) # optional - sage.rings.number_field + sage: K1. = CyclotomicField(12) + sage: h1 = K.hom([z1^4]) + sage: I.apply_coeff_map(h1, new_base_ring=K1) Ideal (x + z1^2 - 1, y - z1^2 + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 12 and degree 4 """ @@ -310,11 +312,12 @@ def toric_coordinate_change(self, M, forward_hint=True): EXAMPLES:: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: P. = LaurentPolynomialRing(K, 2) # optional - sage.rings.number_field - sage: I = P.ideal([x + 1, y - 1]) # optional - sage.rings.number_field - sage: M = Matrix([[2,1], [1,-3]]) # optional - sage.rings.number_field - sage: I.toric_coordinate_change(M) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: P. = LaurentPolynomialRing(K, 2) + sage: I = P.ideal([x + 1, y - 1]) + sage: M = Matrix([[2,1], [1,-3]]) + sage: I.toric_coordinate_change(M) Ideal (x^2*y + 1, -1 + x*y^-3) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 7f99b0635b5..5db2df9dbbd 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -234,12 +234,13 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): check compatibility with :trac:`26105`:: - sage: F. = GF(4) # optional - sage.rings.finite_rings - sage: LF. = LaurentPolynomialRing(F) # optional - sage.rings.finite_rings - sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F. = GF(4) + sage: LF. = LaurentPolynomialRing(F) + sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) + sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs a + (t + 1)*b^-1 + t*a^-3*b^2 - sage: s == rho(rs) # optional - sage.rings.finite_rings + sage: s == rho(rs) True """ p = self._poly @@ -984,17 +985,17 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: L. = LaurentPolynomialRing(QQ) sage: f = x^3 + y^-3 sage: g = y + x - sage: f // g + sage: f // g # needs sage.libs.singular x^5*y^-3 - x^4*y^-2 + x^3*y^-1 sage: h = x + y^(-1) - sage: f // h + sage: f // h # needs sage.libs.singular x^2 - x*y^-1 + y^-2 - sage: h * (f // h) == f + sage: h * (f // h) == f # needs sage.libs.singular True sage: f // 1 x^3 + y^-3 - sage: 1 // f + sage: 1 // f # needs sage.libs.singular 0 TESTS: @@ -1006,8 +1007,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): Check that :trac:`21999` is fixed:: - sage: L. = LaurentPolynomialRing(QQbar) - sage: (a+a*b) // a + sage: L. = LaurentPolynomialRing(QQbar) # needs sage.rings.number_field + sage: (a+a*b) // a # needs sage.libs.singular sage.rings.number_field b + 1 """ cdef LaurentPolynomial_mpair ans = self._new_c() @@ -1035,24 +1036,25 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): EXAMPLES:: sage: R. = LaurentPolynomialRing(QQ) - sage: (s^2 - t^2).quo_rem(s - t) + sage: (s^2 - t^2).quo_rem(s - t) # needs sage.libs.singular (s + t, 0) - sage: (s^-2 - t^2).quo_rem(s - t) + sage: (s^-2 - t^2).quo_rem(s - t) # needs sage.libs.singular (s + t, -s^2 + s^-2) - sage: (s^-2 - t^2).quo_rem(s^-1 - t) + sage: (s^-2 - t^2).quo_rem(s^-1 - t) # needs sage.libs.singular (t + s^-1, 0) TESTS: Verify that :trac:`31257` is fixed:: + sage: # needs sage.libs.singular sage: R. = LaurentPolynomialRing(QQ) sage: q, r = (1/x).quo_rem(y) sage: q, r (x^-1*y^-1, 0) sage: q*y + r == 1/x True - sage: q,r = (x^-2 - y^2).quo_rem(x - y) + sage: q, r = (x^-2 - y^2).quo_rem(x - y) sage: q*(x - y) + r == x^-2 - y^2 True """ @@ -1347,15 +1349,15 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): """ EXAMPLES:: + sage: # needs sage.symbolic sage: R. = LaurentPolynomialRing(QQ) sage: f = x^3 + y/x - sage: g = f._symbolic_(SR); g # optional - sage.symbolic + sage: g = f._symbolic_(SR); g (x^4 + y)/x - sage: g(x=2, y=2) # optional - sage.symbolic + sage: g(x=2, y=2) 9 - - sage: g = SR(f) # optional - sage.symbolic - sage: g(x=2, y=2) # optional - sage.symbolic + sage: g = SR(f) + sage: g(x=2, y=2) 9 """ d = {repr(g): R.var(g) for g in self._parent.gens()} @@ -1633,14 +1635,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: p = x^-2*y + x*y^-2 sage: p.rescale_vars({0: 2, 1: 3}) 2/9*x*y^-2 + 3/4*x^-2*y - sage: F = GF(2) # optional - sage.rings.finite_rings - sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) # optional - sage.rings.finite_rings + sage: F = GF(2) + sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) x*y^-2 + x^-2*y Test for :trac:`30331`:: - sage: F. = CyclotomicField(3) # optional - sage.rings.number_field - sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) # optional - sage.rings.number_field + sage: F. = CyclotomicField(3) # needs sage.rings.number_field + sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) # needs sage.rings.number_field 2*z*x*y^-2 + 1/4*z*x^-2*y """ cdef int i @@ -1695,8 +1697,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: p = 2*x^2 + y - x*y sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]])) 2*x^2*y^2 - x^-2*y^2 + x^-3*y - sage: F = GF(2) # optional - sage.rings.finite_rings - sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]]), # optional - sage.rings.finite_rings + sage: F = GF(2) + sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]]), ....: new_ring=L.change_ring(F)) x^-2*y^2 + x^-3*y @@ -1772,8 +1774,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: L. = LaurentPolynomialRing(QQ, 2) sage: p = x + y - sage: F. = CyclotomicField(3) - sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) + sage: F. = CyclotomicField(3) # needs sage.rings.number_field + sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) # needs sage.rings.number_field (-z - 1)*x^3*y^3 + z*x^-2*y^-2 sage: P. = LaurentPolynomialRing(QQ, 1) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index ece3c70c34f..d922a1a57fc 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -20,7 +20,7 @@ sage: A. = QQ[] sage: R. = LaurentPolynomialRing(A) - sage: matrix(R,2,2,[X,0,0,1]) # optional - sage.modules + sage: matrix(R,2,2,[X,0,0,1]) # needs sage.modules [X 0] [0 1] @@ -64,8 +64,8 @@ def is_LaurentPolynomialRing(R): See https://github.com/sagemath/sage/issues/35229 for details. False - sage: R = LaurentPolynomialRing(QQ,3,'x') # optional - sage.modules - sage: is_LaurentPolynomialRing(R) # optional - sage.modules + sage: R = LaurentPolynomialRing(QQ,3,'x') # needs sage.modules + sage: is_LaurentPolynomialRing(R) # needs sage.modules True """ from sage.misc.superseded import deprecation @@ -121,9 +121,9 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R. = LaurentPolynomialRing(QQ, 2); R # optional - sage.modules + sage: R. = LaurentPolynomialRing(QQ, 2); R # needs sage.modules Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: f = x^2 - 2*y^-2 # optional - sage.modules + sage: f = x^2 - 2*y^-2 # needs sage.modules You can't just globally change the names of those variables. This is because objects all over Sage could have pointers to @@ -131,7 +131,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R._assign_names(['z','w']) # optional - sage.modules + sage: R._assign_names(['z','w']) # needs sage.modules Traceback (most recent call last): ... ValueError: variable names cannot be changed after object creation. @@ -163,7 +163,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): sage: R. = LaurentPolynomialRing(QQ, sparse=True); R Univariate Laurent Polynomial Ring in abc over Rational Field - sage: R. = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R # optional - sage.rings.finite_rings + sage: R. = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 @@ -176,31 +176,32 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R # optional - sage.modules + sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S # optional - sage.modules + sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T # optional - sage.modules + sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field All three rings are identical. :: - sage: (R is S) and (S is T) # optional - sage.modules + sage: (R is S) and (S is T) # needs sage.modules True There is a unique Laurent polynomial ring with each term order:: - sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R # optional - sage.modules + sage: # needs sage.modules + sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S # optional - sage.modules + sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex') # optional - sage.modules + sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex') True - sage: R == S # optional - sage.modules + sage: R == S False @@ -211,27 +212,27 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: LaurentPolynomialRing(QQ, 'x', 10) # optional - sage.modules + sage: LaurentPolynomialRing(QQ, 'x', 10) # needs sage.modules Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field - sage: LaurentPolynomialRing(GF(7), 'y', 5) # optional - sage.modules sage.rings.finite_rings + sage: LaurentPolynomialRing(GF(7), 'y', 5) # needs sage.modules Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7 - sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) # optional - sage.modules + sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) # needs sage.modules Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field By calling the :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: - sage: R = LaurentPolynomialRing(GF(7), 15, 'w'); R # optional - sage.modules sage.rings.finite_rings + sage: R = LaurentPolynomialRing(GF(7), 15, 'w'); R # needs sage.modules Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 - sage: R.inject_variables() # optional - sage.modules sage.rings.finite_rings + sage: R.inject_variables() # needs sage.modules Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 - sage: (w0 + 2*w8 + w13)^2 # optional - sage.modules sage.rings.finite_rings + sage: (w0 + 2*w8 + w13)^2 # needs sage.modules w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing @@ -354,12 +355,13 @@ def _split_laurent_polynomial_dict_(P, M, d): TESTS:: - sage: L. = LaurentPolynomialRing(ZZ) # optional - sage.modules - sage: M = LaurentPolynomialRing(ZZ, 'c, d') # optional - sage.modules - sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules - sage: M(c/d + 1/c) # indirect doctest # optional - sage.modules + sage: # needs sage.modules + sage: L. = LaurentPolynomialRing(ZZ) + sage: M = LaurentPolynomialRing(ZZ, 'c, d') + sage: N = LaurentPolynomialRing(M, 'a, b') + sage: M(c/d + 1/c) # indirect doctest c*d^-1 + c^-1 - sage: N(a + b/c/d + 1/b) # indirect doctest # optional - sage.modules + sage: N(a + b/c/d + 1/b) # indirect doctest a + (c^-1*d^-1)*b + b^-1 """ vars_P = P.variable_names() @@ -410,11 +412,12 @@ def from_fraction_field(L, x): EXAMPLES:: + sage: # needs sage.modules sage: from sage.rings.polynomial.laurent_polynomial_ring import from_fraction_field - sage: L. = LaurentPolynomialRing(ZZ) # optional - sage.modules - sage: F = L.fraction_field() # optional - sage.modules - sage: xi = F(~x) # optional - sage.modules - sage: from_fraction_field(L, xi) == ~x # optional - sage.modules + sage: L. = LaurentPolynomialRing(ZZ) + sage: F = L.fraction_field() + sage: xi = F(~x) + sage: from_fraction_field(L, xi) == ~x True """ d = L(x.denominator()) @@ -466,37 +469,39 @@ def _element_constructor_(self, x): sage: L(1/2) 1/2 - sage: L(x + 3/x) + sage: L(x + 3/x) # needs sage.symbolic 3*x^-1 + x :: - sage: L(exp(x)) + sage: L(exp(x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: + sage: # needs sage.modules sage: U = LaurentPolynomialRing(QQ, 'a') sage: V = LaurentPolynomialRing(QQ, 'c') sage: L. = LaurentPolynomialRing(QQ) - sage: M = LaurentPolynomialRing(QQ, 'c, d') # optional - sage.modules - sage: Mc, Md = M.gens() # optional - sage.modules - sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules - sage: Na, Nb = N.gens() # optional - sage.modules - sage: U(Na) # optional - sage.modules + sage: M = LaurentPolynomialRing(QQ, 'c, d') + sage: Mc, Md = M.gens() + sage: N = LaurentPolynomialRing(M, 'a, b') + sage: Na, Nb = N.gens() + sage: U(Na) a - sage: V(Mc) # optional - sage.modules + sage: V(Mc) c - sage: M(L(0)) # optional - sage.modules + sage: # needs sage.modules + sage: M(L(0)) 0 - sage: N(L(0)) # optional - sage.modules + sage: N(L(0)) 0 - sage: L(M(0)) # optional - sage.modules + sage: L(M(0)) 0 - sage: L(N(0)) # optional - sage.modules + sage: L(N(0)) 0 :: @@ -508,8 +513,8 @@ def _element_constructor_(self, x): sage: C. = LaurentPolynomialRing(B) sage: B(C(b)) b - sage: D. = LaurentPolynomialRing(B) # optional - sage.modules - sage: B(D(b)) # optional - sage.modules + sage: D. = LaurentPolynomialRing(B) # needs sage.modules + sage: B(D(b)) # needs sage.modules b TESTS: @@ -578,11 +583,11 @@ def __init__(self, R): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') # optional - sage.modules - sage: type(L) # optional - sage.modules + sage: L = LaurentPolynomialRing(QQ,2,'x') # needs sage.modules + sage: type(L) # needs sage.modules - sage: L == loads(dumps(L)) # optional - sage.modules + sage: L == loads(dumps(L)) # needs sage.modules True """ if R.ngens() <= 0: @@ -597,9 +602,9 @@ def _repr_(self): """ TESTS:: - sage: LaurentPolynomialRing(QQ,2,'x').__repr__() # optional - sage.modules + sage: LaurentPolynomialRing(QQ,2,'x').__repr__() # needs sage.modules 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' - sage: LaurentPolynomialRing(QQ,1,'x').__repr__() # optional - sage.modules + sage: LaurentPolynomialRing(QQ,1,'x').__repr__() # needs sage.modules 'Multivariate Laurent Polynomial Ring in x over Rational Field' """ return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) @@ -610,21 +615,22 @@ def monomial(self, *args): EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ, 'x', 2) # optional - sage.modules - sage: L.monomial(-3, 5) # optional - sage.modules + sage: # needs sage.modules + sage: L = LaurentPolynomialRing(QQ, 'x', 2) + sage: L.monomial(-3, 5) x0^-3*x1^5 - sage: L.monomial(1, 1) # optional - sage.modules + sage: L.monomial(1, 1) x0*x1 - sage: L.monomial(0, 0) # optional - sage.modules + sage: L.monomial(0, 0) 1 - sage: L.monomial(-2, -3) # optional - sage.modules + sage: L.monomial(-2, -3) x0^-2*x1^-3 - sage: x0, x1 = L.gens() # optional - sage.modules - sage: L.monomial(-1, 2) == x0^-1 * x1^2 # optional - sage.modules + sage: x0, x1 = L.gens() # needs sage.modules + sage: L.monomial(-1, 2) == x0^-1 * x1^2 # needs sage.modules True - sage: L.monomial(1, 2, 3) # optional - sage.modules + sage: L.monomial(1, 2, 3) # needs sage.modules Traceback (most recent call last): ... TypeError: tuple key must have same length as ngens @@ -640,96 +646,103 @@ def _element_constructor_(self, x, mon=None): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') # optional - sage.modules - sage: L(1/2) # optional - sage.modules + sage: L = LaurentPolynomialRing(QQ,2,'x') # needs sage.modules + sage: L(1/2) # needs sage.modules 1/2 - sage: M = LaurentPolynomialRing(QQ, 'x, y') # optional - sage.modules - sage: var('x, y') # optional - sage.modules + sage: M = LaurentPolynomialRing(QQ, 'x, y') # needs sage.modules + sage: var('x, y') # needs sage.modules sage.symbolic (x, y) - sage: M(x/y + 3/x) # optional - sage.modules + sage: M(x/y + 3/x) # needs sage.modules sage.symbolic x*y^-1 + 3*x^-1 :: - sage: M(exp(x)) # optional - sage.modules + sage: M(exp(x)) # needs sage.modules sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: - sage: L. = LaurentPolynomialRing(QQ) # optional - sage.modules - sage: M = LaurentPolynomialRing(QQ, 'c, d') # optional - sage.modules - sage: Mc, Md = M.gens() # optional - sage.modules - sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules - sage: Na, Nb = N.gens() # optional - sage.modules - sage: M(c/d) # optional - sage.modules + sage: # needs sage.modules + sage: L. = LaurentPolynomialRing(QQ) + sage: M = LaurentPolynomialRing(QQ, 'c, d') + sage: Mc, Md = M.gens() + sage: N = LaurentPolynomialRing(M, 'a, b') + sage: Na, Nb = N.gens() + sage: M(c/d) c*d^-1 - sage: N(a*b/c/d) # optional - sage.modules + sage: N(a*b/c/d) (c^-1*d^-1)*a*b - sage: N(c/d) # optional - sage.modules + sage: N(c/d) c*d^-1 - sage: L(Mc) # optional - sage.modules + sage: L(Mc) c - sage: L(Nb) # optional - sage.modules + sage: L(Nb) b - sage: M(L(0)) # optional - sage.modules + sage: # needs sage.modules + sage: M(L(0)) 0 - sage: N(L(0)) # optional - sage.modules + sage: N(L(0)) 0 - sage: L(M(0)) # optional - sage.modules + sage: L(M(0)) 0 - sage: L(N(0)) # optional - sage.modules + sage: L(N(0)) 0 + sage: # needs sage.modules sage: U = LaurentPolynomialRing(QQ, 'a') sage: Ua = U.gen() sage: V = LaurentPolynomialRing(QQ, 'c') sage: Vc = V.gen() - sage: L(Ua) # optional - sage.modules + sage: L(Ua) a - sage: L(Vc) # optional - sage.modules + sage: L(Vc) c - sage: N(Ua) # optional - sage.modules + sage: N(Ua) a - sage: M(Vc) # optional - sage.modules + sage: M(Vc) c - sage: P = LaurentPolynomialRing(QQ, 'a, b') # optional - sage.modules - sage: Q = LaurentPolynomialRing(P, 'c, d') # optional - sage.modules - sage: Q(P.0) # optional - sage.modules + sage: # needs sage.modules + sage: P = LaurentPolynomialRing(QQ, 'a, b') + sage: Q = LaurentPolynomialRing(P, 'c, d') + sage: Q(P.0) a :: + sage: # needs sage.modules sage: A. = LaurentPolynomialRing(QQ) sage: B. = LaurentPolynomialRing(A) - sage: C = LaurentPolynomialRing(QQ, 'a, b') # optional - sage.modules - sage: C(B({1: a})) # optional - sage.modules + sage: C = LaurentPolynomialRing(QQ, 'a, b') + sage: C(B({1: a})) a*b - sage: D. = LaurentPolynomialRing(B) # optional - sage.modules - sage: F. = LaurentPolynomialRing(D) # optional - sage.modules - sage: D(F(d*e)) # optional - sage.modules + sage: D. = LaurentPolynomialRing(B) + sage: F. = LaurentPolynomialRing(D) + sage: D(F(d*e)) d*e :: + sage: # needs sage.modules sage: from sage.rings.polynomial.polydict import ETuple - sage: R. = LaurentPolynomialRing(QQ) # optional - sage.modules - sage: mon = ETuple({}, int(3)) # optional - sage.modules - sage: P = R.polynomial_ring() # optional - sage.modules - sage: R(sum(P.gens()), mon) # optional - sage.modules + sage: R. = LaurentPolynomialRing(QQ) + sage: mon = ETuple({}, int(3)) + sage: P = R.polynomial_ring() + sage: R(sum(P.gens()), mon) x + y + z - sage: R(sum(P.gens()), (-1,-1,-1)) # optional - sage.modules + sage: R(sum(P.gens()), (-1,-1,-1)) y^-1*z^-1 + x^-1*z^-1 + x^-1*y^-1 :: - sage: RL = R.localization(x+1) # optional - sage.modules - sage: xi = RL(~x) # optional - sage.modules - sage: R(xi) == ~x # indirect doctests # optional - sage.modules + sage: # needs sage.modules + sage: RL = R.localization(x + 1) + sage: xi = RL(~x) + sage: R(xi) == ~x # indirect doctests True """ from sage.structure.element import Expression @@ -786,8 +799,8 @@ def __reduce__(self): EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ, 2, 'x') # optional - sage.modules - sage: loads(dumps(L)) == L # optional - sage.modules + sage: L = LaurentPolynomialRing(QQ, 2, 'x') # needs sage.modules + sage: loads(dumps(L)) == L # needs sage.modules True """ return LaurentPolynomialRing_mpair, (self._R,) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 014fa20efaa..0c9022c492c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Ring of Laurent Polynomials (base class) @@ -212,6 +212,7 @@ def completion(self, p=None, prec=20, extras=None): sage: 1 / g -x^-1 + 1 + O(x^19) + sage: # needs sage.combinat sage: PP = P.completion(x, prec=oo); PP Lazy Laurent Series Ring in x over Rational Field sage: g = 1 / PP(f); g @@ -302,7 +303,7 @@ def __eq__(self, right): sage: P == R False """ - if type(self) != type(right): + if type(self) is not type(right): return False return self._R == right._R @@ -390,15 +391,16 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: T. = ZZ[] - sage: K. = NumberField(t^2 + 1) # optional - sage.rings.number_field - sage: L. = LaurentPolynomialRing(K) # optional - sage.rings.number_field - sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) # optional - sage.rings.number_field + sage: K. = NumberField(t^2 + 1) + sage: L. = LaurentPolynomialRing(K) + sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) True - sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() # optional - sage.rings.padics - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion # optional - sage.rings.padics + sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() # needs sage.rings.padics + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion # needs sage.rings.padics False - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) # optional - sage.rings.padics + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) # needs sage.rings.padics True """ if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): @@ -463,7 +465,7 @@ def characteristic(self): sage: LaurentPolynomialRing(QQ, 2, 'x').characteristic() 0 - sage: LaurentPolynomialRing(GF(3), 2, 'x').characteristic() # optional - sage.libs.pari + sage: LaurentPolynomialRing(GF(3), 2, 'x').characteristic() 3 """ @@ -518,8 +520,8 @@ def change_ring(self, base_ring=None, names=None, sparse=False, order=None): sage: P. = LaurentPolynomialRing(QQ, 1) sage: P Multivariate Laurent Polynomial Ring in x over Rational Field - sage: K. = CyclotomicField(4) # optional - sage.rings.number_field - sage: P.change_ring(K) # optional - sage.rings.number_field + sage: K. = CyclotomicField(4) # needs sage.rings.number_field + sage: P.change_ring(K) # needs sage.rings.number_field Multivariate Laurent Polynomial Ring in x over Cyclotomic Field of order 4 and degree 2 """ diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index cf2382c0148..d0a430bbfd8 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -14,7 +14,6 @@ from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.structure.coerce cimport coercion_model from sage.misc.derivative import multi_derivative -from sage.combinat.integer_lists.invlex import IntegerListsLex from itertools import chain from sage.misc.misc_c import prod @@ -27,10 +26,7 @@ def is_MPolynomial(x): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.categories.map cimport Map -from sage.modules.free_module_element import vector from sage.rings.rational_field import QQ -from sage.rings.complex_interval_field import ComplexIntervalField -from sage.rings.real_mpfr import RealField from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_element cimport Polynomial @@ -44,7 +40,8 @@ cdef class MPolynomial(CommutativePolynomial): r""" TESTS:: - sage: ZZ(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: ZZ(RR['x,y'](0)) # indirect doctest 0 sage: ZZ(RR['x,y'](0.5)) Traceback (most recent call last): @@ -55,20 +52,23 @@ cdef class MPolynomial(CommutativePolynomial): ... TypeError: unable to convert non-constant polynomial x to Integer Ring - sage: RR(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: RR(RR['x,y'](0)) # indirect doctest 0.000000000000000 sage: RR(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Real Field with 53 bits of precision - sage: CC(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: CC(RR['x,y'](0)) # indirect doctest 0.000000000000000 sage: CC(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Complex Field with 53 bits of precision + sage: # needs sage.rings.real_mpfr sage: RDF(RR['x,y'](0)) 0.0 sage: RDF(ZZ['x,y'].gen(0)) @@ -76,13 +76,15 @@ cdef class MPolynomial(CommutativePolynomial): ... TypeError: unable to convert non-constant polynomial x to Real Double Field - sage: CDF(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: CDF(RR['x,y'](0)) # indirect doctest 0.0 sage: CDF(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Complex Double Field + sage: # needs sage.libs.flint sage.rings.real_mpfr sage: a = RR['x,y'](1) sage: RBF(a) 1.000000000000000 @@ -92,8 +94,7 @@ cdef class MPolynomial(CommutativePolynomial): 1.000000000000000 sage: CIF(a) 1 - - sage: CBF(RR['x,y'](1)) # indirect doctest + sage: CBF(RR['x,y'](1)) # indirect doctest 1.000000000000000 sage: CBF(ZZ['x,y'].gen(0)) Traceback (most recent call last): @@ -101,8 +102,8 @@ cdef class MPolynomial(CommutativePolynomial): TypeError: unable to convert non-constant polynomial x to Complex ball field with 53 bits of precision sage: x = polygen(QQ) - sage: A. = NumberField(x^3 - 2) - sage: A(A['x,y'](u)) + sage: A. = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: A(A['x,y'](u)) # needs sage.rings.number_field u """ if self.degree() <= 0: @@ -130,7 +131,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: type(RR['x, y'](0)) - sage: int(RR['x,y'](0)) # indirect doctest + sage: int(RR['x,y'](0)) # indirect doctest 0 sage: int(RR['x,y'](10)) 10 @@ -139,7 +140,7 @@ cdef class MPolynomial(CommutativePolynomial): ... TypeError: unable to convert non-constant polynomial x to - sage: ZZ(RR['x,y'](0)) # indirect doctest + sage: ZZ(RR['x,y'](0)) # indirect doctest 0 sage: ZZ(RR['x,y'](0.5)) Traceback (most recent call last): @@ -156,7 +157,7 @@ cdef class MPolynomial(CommutativePolynomial): r""" TESTS:: - sage: float(RR['x,y'](0)) # indirect doctest + sage: float(RR['x,y'](0)) # indirect doctest 0.0 sage: float(ZZ['x,y'].gen(0)) Traceback (most recent call last): @@ -169,7 +170,7 @@ cdef class MPolynomial(CommutativePolynomial): r""" TESTS:: - sage: QQ(RR['x,y'](0.5)) # indirect doctest + sage: QQ(RR['x,y'](0.5)) # indirect doctest 1/2 sage: QQ(RR['x,y'].gen(0)) Traceback (most recent call last): @@ -183,15 +184,15 @@ cdef class MPolynomial(CommutativePolynomial): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: R. = QQ[] sage: f = x^3 + y - sage: g = f._symbolic_(SR); g # optional - sage.symbolic + sage: g = f._symbolic_(SR); g x^3 + y - sage: g(x=2, y=2) # optional - sage.symbolic + sage: g(x=2, y=2) 10 - - sage: g = SR(f) # optional - sage.symbolic - sage: g(x=2, y=2) # optional - sage.symbolic + sage: g = SR(f) + sage: g(x=2, y=2) 10 """ d = dict([(repr(g), R.var(g)) for g in self.parent().gens()]) @@ -314,13 +315,14 @@ cdef class MPolynomial(CommutativePolynomial): Polynomials implemented via Singular:: - sage: R. = PolynomialRing(FiniteField(5)) # optional - sage.rings.finite_rings - sage: f = x^3*y^5 + x^7*y # optional - sage.rings.finite_rings - sage: type(f) # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: R. = PolynomialRing(FiniteField(5)) + sage: f = x^3*y^5 + x^7*y + sage: type(f) - sage: f.derivative(x) # optional - sage.rings.finite_rings + sage: f.derivative(x) 2*x^6*y - 2*x^2*y^5 - sage: f.derivative(y) # optional - sage.rings.finite_rings + sage: f.derivative(y) x^7 Generic multivariate polynomials:: @@ -330,29 +332,30 @@ cdef class MPolynomial(CommutativePolynomial): sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 sage: type(f) - sage: f.derivative(x) # with respect to x + sage: f.derivative(x) # with respect to x (2*t^2 + O(t^3))*x*y^3 + (111*t^4 + O(t^5))*x^2 - sage: f.derivative(y) # with respect to y + sage: f.derivative(y) # with respect to y (3*t^2 + O(t^3))*x^2*y^2 - sage: f.derivative(t) # with respect to t (recurses into base ring) + sage: f.derivative(t) # with respect to t (recurses into base ring) (2*t + O(t^2))*x^2*y^3 + (148*t^3 + O(t^4))*x^3 - sage: f.derivative(x, y) # with respect to x and then y + sage: f.derivative(x, y) # with respect to x and then y (6*t^2 + O(t^3))*x*y^2 - sage: f.derivative(y, 3) # with respect to y three times + sage: f.derivative(y, 3) # with respect to y three times (6*t^2 + O(t^3))*x^2 - sage: f.derivative() # can't figure out the variable + sage: f.derivative() # can't figure out the variable Traceback (most recent call last): ... ValueError: must specify which variable to differentiate with respect to Polynomials over the symbolic ring (just for fun....):: - sage: x = var("x") # optional - sage.symbolic - sage: S. = PolynomialRing(SR) # optional - sage.symbolic - sage: f = u*v*x # optional - sage.symbolic - sage: f.derivative(x) == u*v # optional - sage.symbolic + sage: # needs sage.symbolic + sage: x = var("x") + sage: S. = PolynomialRing(SR) + sage: f = u*v*x + sage: f.derivative(x) == u*v True - sage: f.derivative(u) == v*x # optional - sage.symbolic + sage: f.derivative(u) == v*x True """ return multi_derivative(self, args) @@ -388,11 +391,11 @@ cdef class MPolynomial(CommutativePolynomial): z^5 + x*w*k*z + w^5 + 17*x*w^3 + x^3 + 3*x*w + 5 sage: f.polynomial(k) x*w*z*k + w^5 + z^5 + 17*x*w^3 + x^3 + 3*x*w + 5 - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: f = x^2 + x + y # optional - sage.rings.finite_rings - sage: f.polynomial(x) # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: f = x^2 + x + y + sage: f.polynomial(x) x^2 + x + y - sage: f.polynomial(y) # optional - sage.rings.finite_rings + sage: f.polynomial(y) y + x^2 + x """ cdef int ind @@ -445,8 +448,9 @@ cdef class MPolynomial(CommutativePolynomial): TESTS:: - sage: R = Qp(7)['x,y,z,t,p']; S = ZZ['x,z,t']['p'] # optional - sage.rings.padics - sage: R(S.0) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: R = Qp(7)['x,y,z,t,p']; S = ZZ['x,z,t']['p'] + sage: R(S.0) p sage: R = QQ['x,y,z,t,p']; S = ZZ['x']['y,z,t']['p'] sage: z = S.base_ring().gen(1) @@ -456,8 +460,8 @@ cdef class MPolynomial(CommutativePolynomial): sage: z = S.base_ring().gen(1); p = S.0; x = S.base_ring().base_ring().gen() sage: R(z+p) z + p - sage: R = Qp(7)['x,y,z,p']; S = ZZ['x']['y,z,t']['p'] # shouldn't work, but should throw a better error # optional - sage.rings.padics - sage: R(S.0) # optional - sage.rings.padics + sage: R = Qp(7)['x,y,z,p']; S = ZZ['x']['y,z,t']['p'] # shouldn't work, but should throw a better error + sage: R(S.0) p See :trac:`2601`:: @@ -466,7 +470,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: a._mpoly_dict_recursive(('c', 'b', 'a')) {(0, 0, 1): 1} sage: testR. = PolynomialRing(QQ,3) - sage: id_ringA = ideal([a^2-b,b^2-c,c^2-a]) + sage: id_ringA = ideal([a^2 - b, b^2 - c, c^2 - a]) sage: id_ringB = ideal(id_ringA.gens()).change_ring(PolynomialRing(QQ,'c,b,a')) """ if not self: @@ -560,9 +564,9 @@ cdef class MPolynomial(CommutativePolynomial): Verify that :trac:`16251` has been resolved, i.e., polynomials with unhashable coefficients are unhashable:: - sage: K. = Qq(9) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: hash(t) # optional - sage.rings.padics + sage: K. = Qq(9) # needs sage.rings.padics + sage: R. = K[] # needs sage.rings.padics + sage: hash(t) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' @@ -690,9 +694,9 @@ cdef class MPolynomial(CommutativePolynomial): In particular, this can be surprising in positive characteristic:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: f = x + 1 # optional - sage.rings.finite_rings - sage: f.homogenize(x) # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: f = x + 1 + sage: f.homogenize(x) 0 TESTS:: @@ -815,15 +819,15 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = (x^2*y + 2*x - 3) sage: g = (x + 1)*f - sage: g % f # optional - sage.libs.singular + sage: g % f # needs sage.libs.singular 0 - sage: (g+1) % f # optional - sage.libs.singular + sage: (g+1) % f # needs sage.libs.singular 1 sage: M = x*y sage: N = x^2*y^3 - sage: M.divides(N) # optional - sage.libs.singular + sage: M.divides(N) # needs sage.libs.singular True """ try: @@ -847,21 +851,22 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^3 + 3/5*y + 1 - sage: f.change_ring(GF(7)) # optional - sage.rings.finite_rings + sage: f.change_ring(GF(7)) x^3 + 2*y + 1 :: - sage: R. = GF(9,'a')[] # optional - sage.rings.finite_rings - sage: (x+2*y).change_ring(GF(3)) # optional - sage.rings.finite_rings + sage: R. = GF(9,'a')[] # needs sage.rings.finite_rings + sage: (x+2*y).change_ring(GF(3)) x - y :: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: f = x^2 + z*y # optional - sage.rings.number_field - sage: f.change_ring(K.embeddings(CC)[1]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: R. = K[] + sage: f = x^2 + z*y + sage: f.change_ring(K.embeddings(CC)[1]) x^2 + (-0.500000000000000 - 0.866025403784438*I)*y TESTS: @@ -869,7 +874,7 @@ cdef class MPolynomial(CommutativePolynomial): Check that :trac:`25022` is fixed:: sage: K. = ZZ[] - sage: (x*y).change_ring(SR).monomials() # optional - sage.rings.number_field sage.symbolic + sage: (x*y).change_ring(SR).monomials() # needs sage.rings.number_field sage.symbolic [x*y] """ if isinstance(R, Map): @@ -891,27 +896,27 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.groups sage: R. = QQ[] sage: p = (x+y+z)**2 - 3 * (x+y)*(x+z)*(y+z) - sage: p.is_symmetric() # optional - sage.groups + sage: p.is_symmetric() True - sage: (x + y - z).is_symmetric() # optional - sage.groups + sage: (x + y - z).is_symmetric() False - sage: R.one().is_symmetric() # optional - sage.groups + sage: R.one().is_symmetric() True - sage: p = (x-y)*(y-z)*(z-x) - sage: p.is_symmetric() # optional - sage.groups + sage: p.is_symmetric() False - sage: p.is_symmetric(AlternatingGroup(3)) # optional - sage.groups + sage: p.is_symmetric(AlternatingGroup(3)) True sage: R. = QQ[] - sage: ((x + y)**2).is_symmetric() # optional - sage.groups + sage: ((x + y)**2).is_symmetric() # needs sage.groups True - sage: R.one().is_symmetric() # optional - sage.groups + sage: R.one().is_symmetric() # needs sage.groups True - sage: (x + 2*y).is_symmetric() # optional - sage.groups + sage: (x + 2*y).is_symmetric() # needs sage.groups False An example with a GAP permutation group (here the quaternions):: @@ -921,23 +926,23 @@ cdef class MPolynomial(CommutativePolynomial): sage: p = sum(prod(x[i] for i in e) ....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), ....: (3,4,5), (3,4,6), (3,5,6), (4,5,6)]) - sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # optional - sage.groups + sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs sage.groups True sage: p = sum(prod(x[i] for i in e) ....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), ....: (3,4,5), (3,4,6), (3,5,6)]) - sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # optional - sage.groups + sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs sage.groups False TESTS:: sage: R = PolynomialRing(QQ, 'x', 3) - sage: R.one().is_symmetric(3) # optional - sage.groups + sage: R.one().is_symmetric(3) # needs sage.groups Traceback (most recent call last): ... ValueError: argument must be a permutation group - sage: R.one().is_symmetric(SymmetricGroup(4)) # optional - sage.groups + sage: R.one().is_symmetric(SymmetricGroup(4)) # needs sage.groups Traceback (most recent call last): ... ValueError: invalid data to initialize a permutation @@ -979,40 +984,43 @@ cdef class MPolynomial(CommutativePolynomial): Multivariate polynomial over integers:: + sage: # needs sage.libs.gap sage: R. = ZZ[] - sage: gap(-x*y + 3*z) # indirect doctest # optional - sage.libs.gap + sage: gap(-x*y + 3*z) # indirect doctest -x*y+3*z - sage: gap(R.zero()) # indirect doctest # optional - sage.libs.gap + sage: gap(R.zero()) # indirect doctest 0 - sage: (x+y+z)._gap_(libgap) # optional - sage.libs.gap + sage: (x+y+z)._gap_(libgap) x+y+z - sage: g = gap(x - y + 3*x*y*z) # optional - sage.libs.gap - sage: R(g) # optional - sage.libs.gap + sage: g = gap(x - y + 3*x*y*z) # needs sage.libs.gap + sage: R(g) # needs sage.libs.gap 3*x*y*z + x - y - sage: g = libgap(5*x - y*z) # optional - sage.libs.gap - sage: R(g) # optional - sage.libs.gap + sage: g = libgap(5*x - y*z) # needs sage.libs.gap + sage: R(g) # needs sage.libs.gap -y*z + 5*x Multivariate polynomial over a cyclotomic field:: - sage: F. = CyclotomicField(8) # optional - sage.rings.number_field - sage: P. = F[] # optional - sage.rings.number_field - sage: p = zeta + zeta^2*x + zeta^3*y + (1+zeta)*x*y # optional - sage.rings.number_field - sage: gap(p) # indirect doctest # optional - sage.libs.gap sage.rings.number_field + sage: # needs sage.libs.gap sage.rings.number_field + sage: F. = CyclotomicField(8) + sage: P. = F[] + sage: p = zeta + zeta^2*x + zeta^3*y + (1+zeta)*x*y + sage: gap(p) # indirect doctest (1+E(8))*x*y+E(4)*x+E(8)^3*y+E(8) - sage: libgap(p) # indirect doctest # optional - sage.libs.gap sage.rings.number_field + sage: libgap(p) # indirect doctest (1+E(8))*x*y+E(4)*x+E(8)^3*y+E(8) Multivariate polynomial over a polynomial ring over a cyclotomic field:: - sage: S. = F[] # optional - sage.rings.number_field - sage: P. = S[] # optional - sage.rings.number_field - sage: p = zeta + zeta^2*x*z + zeta^3*y*z^2 + (1+zeta)*x*y*z # optional - sage.rings.number_field - sage: gap(p) # indirect doctest # optional - sage.libs.gap sage.rings.number_field + sage: # needs sage.libs.gap sage.rings.number_field + sage: S. = F[] + sage: P. = S[] + sage: p = zeta + zeta^2*x*z + zeta^3*y*z^2 + (1+zeta)*x*y*z + sage: gap(p) # indirect doctest ((1+E(8))*z)*x*y+E(4)*z*x+E(8)^3*z^2*y+E(8) - sage: libgap(p) # indirect doctest # optional - sage.libs.gap sage.rings.number_field + sage: libgap(p) # indirect doctest ((1+E(8))*z)*x*y+E(4)*z*x+E(8)^3*z^2*y+E(8) """ R = gap(self.parent()) @@ -1024,9 +1032,9 @@ cdef class MPolynomial(CommutativePolynomial): TESTS:: sage: R. = ZZ[] - sage: libgap(-x*y + 3*z) # indirect doctest # optional - sage.libs.gap + sage: libgap(-x*y + 3*z) # indirect doctest # needs sage.libs.gap -x*y+3*z - sage: libgap(R.zero()) # indirect doctest # optional - sage.libs.gap + sage: libgap(R.zero()) # indirect doctest # needs sage.libs.gap 0 """ from sage.libs.gap.libgap import libgap @@ -1039,20 +1047,21 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: k. = GF(25); R. = k[] # optional - sage.rings.finite_rings - sage: f = y*x^2*b + x*(b+1) + 1 # optional - sage.rings.finite_rings - sage: magma = Magma() # so var names same below # optional - sage.rings.finite_rings - sage: magma(f) # optional - magma # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(25); R. = k[] + sage: f = y*x^2*b + x*(b+1) + 1 + sage: magma = Magma() # so var names same below + sage: magma(f) # optional - magma b*x^2*y + b^22*x + 1 - sage: f._magma_init_(magma) # optional - magma # optional - sage.rings.finite_rings + sage: f._magma_init_(magma) # optional - magma '_sage_[...]!((_sage_[...]!(_sage_[...]))*_sage_[...]^2*_sage_[...]+(_sage_[...]!(_sage_[...] + 1))*_sage_[...]+(_sage_[...]!(1))*1)' A more complicated nested example:: sage: R. = QQ[]; S. = R[]; f = (2/3)*x^3*z + w^2 + 5 - sage: f._magma_init_(magma) # optional - magma + sage: f._magma_init_(magma) # optional - magma '_sage_[...]!((_sage_[...]!((1/1)*1))*_sage_[...]^2+(_sage_[...]!((2/3)*_sage_[...]^3))*_sage_[...]+(_sage_[...]!((5/1)*1))*1)' - sage: magma(f) # optional - magma + sage: magma(f) # optional - magma w^2 + 2/3*x^3*z + 5 """ R = magma(self.parent()) @@ -1074,13 +1083,14 @@ cdef class MPolynomial(CommutativePolynomial): TESTS:: - sage: R. = GF(101)['e,i'][] # optional - sage.rings.finite_rings - sage: f = R('e*i') * x + y^2 # optional - sage.rings.finite_rings - sage: f._giac_init_() # optional - sage.rings.finite_rings + sage: # needs sage.libs.giac + sage: R. = GF(101)['e,i'][] + sage: f = R('e*i') * x + y^2 + sage: f._giac_init_() '((1)*1)*sageVARy^2+((1)*sageVARe*sageVARi)*sageVARx' - sage: giac(f) # optional - sage.rings.finite_rings + sage: giac(f) sageVARy^2+sageVARe*sageVARi*sageVARx - sage: giac(R.zero()) # optional - sage.rings.finite_rings + sage: giac(R.zero()) 0 """ g = ['sageVAR' + x for x in self.parent().variable_names()] @@ -1125,20 +1135,19 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = 1 + x*y + x^3 + y^3 - sage: P = f.newton_polytope() # optional - sage.geometry.polyhedron - sage: P # optional - sage.geometry.polyhedron + sage: P = f.newton_polytope(); P # needs sage.geometry.polyhedron A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices - sage: P.is_simple() # optional - sage.geometry.polyhedron + sage: P.is_simple() # needs sage.geometry.polyhedron True TESTS:: sage: R. = QQ[] - sage: R(0).newton_polytope() # optional - sage.geometry.polyhedron + sage: R(0).newton_polytope() # needs sage.geometry.polyhedron The empty polyhedron in ZZ^0 - sage: R(1).newton_polytope() # optional - sage.geometry.polyhedron + sage: R(1).newton_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex - sage: R(x^2+y^2).newton_polytope().integral_points() # optional - sage.geometry.polyhedron + sage: R(x^2+y^2).newton_polytope().integral_points() # needs sage.geometry.polyhedron ((0, 2), (1, 1), (2, 0)) """ from sage.geometry.polyhedron.constructor import Polyhedron @@ -1288,32 +1297,33 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: k. = GF(9); R. = k[]; f = x*a + 2*x^3*y*a + a # optional - sage.rings.finite_rings - sage: f.map_coefficients(lambda a: a + 1) # optional - sage.rings.finite_rings + sage: k. = GF(9); R. = k[]; f = x*a + 2*x^3*y*a + a # needs sage.rings.finite_rings + sage: f.map_coefficients(lambda a: a + 1) # needs sage.rings.finite_rings (-a + 1)*x^3*y + (a + 1)*x + (a + 1) Examples with different base ring:: - sage: R. = GF(9); S. = GF(81) # optional - sage.rings.finite_rings - sage: h = Hom(R,S)[0]; h # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(9); S. = GF(81) + sage: h = Hom(R,S)[0]; h Ring morphism: From: Finite Field in r of size 3^2 To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 - sage: T. = R[] # optional - sage.rings.finite_rings - sage: f = r*X + Y # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings + sage: T. = R[] + sage: f = r*X + Y + sage: g = f.map_coefficients(h); g (-s^3 - s^2 + 1)*X + Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() Multivariate Polynomial Ring in X, Y over Finite Field in s of size 3^4 - sage: h = lambda x: x.trace() # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings + sage: h = lambda x: x.trace() + sage: g = f.map_coefficients(h); g X - Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() Multivariate Polynomial Ring in X, Y over Finite Field in r of size 3^2 - sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g # optional - sage.rings.finite_rings + sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g X - Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() Multivariate Polynomial Ring in X, Y over Finite Field of size 3 """ @@ -1337,10 +1347,11 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: k. = GF(9) # optional - sage.rings.finite_rings - sage: R. = PolynomialRing(k) # optional - sage.rings.finite_rings - sage: f = (x-a) * (y-a) # optional - sage.rings.finite_rings - sage: f._norm_over_nonprime_finite_field() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(9) + sage: R. = PolynomialRing(k) + sage: f = (x-a) * (y-a) + sage: f._norm_over_nonprime_finite_field() x^2*y^2 - x^2*y - x*y^2 - x^2 + x*y - y^2 + x + y + 1 """ P = self.parent() @@ -1376,8 +1387,8 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(ZZ) sage: f = (y + 1)*x + 3*x**2 sage: g = (y + 2)*x + 4*x**2 - sage: M = f.sylvester_matrix(g, x) # optional - sage.modules - sage: M # optional - sage.modules + sage: M = f.sylvester_matrix(g, x) # needs sage.modules + sage: M # needs sage.modules [ 3 y + 1 0 0] [ 0 3 y + 1 0] [ 4 y + 2 0 0] @@ -1386,10 +1397,10 @@ cdef class MPolynomial(CommutativePolynomial): If the polynomials share a non-constant common factor then the determinant of the Sylvester matrix will be zero:: - sage: M.determinant() # optional - sage.modules + sage: M.determinant() # needs sage.modules 0 - sage: f.sylvester_matrix(1 + g, x).determinant() # optional - sage.modules + sage: f.sylvester_matrix(1 + g, x).determinant() # needs sage.modules y^2 - y + 7 If both polynomials are of positive degree with respect to ``variable``, the @@ -1397,7 +1408,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: f = R.random_element(4) or (x^2 * y^2) sage: g = R.random_element(4) or (x^2 * y^2) - sage: f.sylvester_matrix(g, x).determinant() == f.resultant(g, x) # optional - sage.modules + sage: f.sylvester_matrix(g, x).determinant() == f.resultant(g, x) # needs sage.libs.singular sage.modules True TESTS: @@ -1406,25 +1417,26 @@ cdef class MPolynomial(CommutativePolynomial): sage: f = x + y sage: g = x + y - sage: f.sylvester_matrix(g) # optional - sage.modules + sage: f.sylvester_matrix(g) # needs sage.modules [1 y] [1 y] Polynomials must be defined over compatible base rings:: + sage: # needs sage.modules sage: K. = QQ[] sage: f = x + y sage: L. = ZZ[] sage: g = x + y - sage: R. = GF(25, 'a')[] + sage: R. = GF(25, 'a')[] # needs sage.rings.finite_rings sage: h = x + y - sage: f.sylvester_matrix(g, 'x') # optional - sage.modules + sage: f.sylvester_matrix(g, 'x') [1 y] [1 y] - sage: g.sylvester_matrix(h, 'x') # optional - sage.modules + sage: g.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings [1 y] [1 y] - sage: f.sylvester_matrix(h, 'x') # optional - sage.modules + sage: f.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -1434,31 +1446,32 @@ cdef class MPolynomial(CommutativePolynomial): sage: f = x + y sage: L. = QQ[] sage: g = x + z - sage: f.sylvester_matrix(g) # optional - sage.modules + sage: f.sylvester_matrix(g) [1 y] [1 z] Corner cases:: - sage: K.=QQ[] + sage: # needs sage.modules + sage: K. = QQ[] sage: f = x^2 + 1 sage: g = K(0) - sage: f.sylvester_matrix(g) # optional - sage.modules + sage: f.sylvester_matrix(g) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: g.sylvester_matrix(f) # optional - sage.modules + sage: g.sylvester_matrix(f) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: g.sylvester_matrix(g) # optional - sage.modules + sage: g.sylvester_matrix(g) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: K(3).sylvester_matrix(x^2) # optional - sage.modules + sage: K(3).sylvester_matrix(x^2) [3 0] [0 3] - sage: K(3).sylvester_matrix(K(4)) # optional - sage.modules + sage: K(3).sylvester_matrix(K(4)) [] """ @@ -1522,11 +1535,11 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = 4*x*y^2 + 1/4*x*y*z + 3/2*x*z^2 - 1/2*z^2 - sage: f.discriminant(x) # optional - sage.libs.singular + sage: f.discriminant(x) # needs sage.libs.singular 1 - sage: f.discriminant(y) # optional - sage.libs.singular + sage: f.discriminant(y) # needs sage.libs.singular -383/16*x^2*z^2 + 8*x*z^2 - sage: f.discriminant(z) # optional - sage.libs.singular + sage: f.discriminant(z) # needs sage.libs.singular -383/16*x^2*y^2 + 8*x*y^2 Note that, unlike the univariate case, the result lives in @@ -1534,20 +1547,21 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1 - sage: f.discriminant(y) # optional - sage.libs.singular + sage: f.discriminant(y) # needs sage.libs.singular x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 - sage: f.polynomial(y).discriminant() # optional - sage.libs.singular + sage: f.polynomial(y).discriminant() x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 - sage: f.discriminant(y).parent() == f.polynomial(y).discriminant().parent() # optional - sage.libs.singular + sage: f.discriminant(y).parent() == f.polynomial(y).discriminant().parent() # needs sage.libs.singular False TESTS: Test polynomials over QQbar (:trac:`25265`):: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1 # optional - sage.rings.number_field - sage: f.discriminant(y) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1 + sage: f.discriminant(y) x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 AUTHOR: Miguel Marco @@ -1626,7 +1640,7 @@ cdef class MPolynomial(CommutativePolynomial): The number of polynomials has to match the number of variables:: sage: R. = PolynomialRing(QQ, 3) - sage: y.macaulay_resultant(x + z) # optional - sage.modules + sage: y.macaulay_resultant(x + z) # needs sage.modules Traceback (most recent call last): ... TypeError: number of polynomials(= 2) must equal number of variables (= 3) @@ -1634,7 +1648,7 @@ cdef class MPolynomial(CommutativePolynomial): The polynomials need to be all homogeneous:: sage: R. = PolynomialRing(QQ, 3) - sage: y.macaulay_resultant([x + z, z + x^3]) # optional - sage.modules + sage: y.macaulay_resultant([x + z, z + x^3]) # needs sage.modules Traceback (most recent call last): ... TypeError: resultant for non-homogeneous polynomials is not supported @@ -1643,7 +1657,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ, 3) sage: S. = PolynomialRing(QQ, 2) - sage: y.macaulay_resultant(z + x, z) # optional - sage.modules + sage: y.macaulay_resultant(z + x, z) # needs sage.modules Traceback (most recent call last): ... TypeError: not all inputs are polynomials in the calling ring @@ -1652,7 +1666,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: K. = PolynomialRing(ZZ, 2) sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,2]) - sage: flist[0].macaulay_resultant(flist[1:]) # optional - sage.modules + sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7 + u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8 + u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - 2*u0*u2*u3*u5*u9 + u0^2*u5^2*u9 @@ -1663,7 +1677,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: K. = PolynomialRing(ZZ, 2) sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,1]) - sage: flist[0].macaulay_resultant(flist[1:]) # optional - sage.modules + sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules -u2*u4*u6 + u1*u5*u6 + u2*u3*u7 - u0*u5*u7 - u1*u3*u8 + u0*u4*u8 The following example is by Patrick Ingram (:arxiv:`1310.4114`):: @@ -1673,38 +1687,38 @@ cdef class MPolynomial(CommutativePolynomial): sage: f0 = y0*x2^2 - x0^2 + 2*x1*x2 sage: f1 = y1*x2^2 - x1^2 + 2*x0*x2 sage: f2 = x0*x1 - x2^2 - sage: f0.macaulay_resultant(f1, f2) # optional - sage.modules + sage: f0.macaulay_resultant(f1, f2) # needs sage.modules y0^2*y1^2 - 4*y0^3 - 4*y1^3 + 18*y0*y1 - 27 a simple example with constant rational coefficients:: sage: R. = PolynomialRing(QQ, 4) - sage: w.macaulay_resultant([z, y, x]) # optional - sage.modules + sage: w.macaulay_resultant([z, y, x]) # needs sage.modules 1 an example where the resultant vanishes:: sage: R. = PolynomialRing(QQ, 3) - sage: (x + y).macaulay_resultant([y^2, x]) # optional - sage.modules + sage: (x + y).macaulay_resultant([y^2, x]) # needs sage.modules 0 an example of bad reduction at a prime ``p = 5``:: sage: R. = PolynomialRing(QQ, 3) - sage: y.macaulay_resultant([x^3 + 25*y^2*x, 5*z]) # optional - sage.modules + sage: y.macaulay_resultant([x^3 + 25*y^2*x, 5*z]) # needs sage.libs.pari sage.modules 125 The input can given as an unpacked list of polynomials:: sage: R. = PolynomialRing(QQ, 3) - sage: y.macaulay_resultant(x^3 + 25*y^2*x, 5*z) # optional - sage.modules + sage: y.macaulay_resultant(x^3 + 25*y^2*x, 5*z) # needs sage.libs.pari sage.modules 125 an example when the coefficients live in a finite field:: - sage: F = FiniteField(11) # optional - sage.rings.finite_rings - sage: R. = PolynomialRing(F, 4) # optional - sage.rings.finite_rings - sage: z.macaulay_resultant([x^3, 5*y, w]) # optional - sage.rings.finite_rings sage.modules + sage: F = FiniteField(11) + sage: R. = PolynomialRing(F, 4) + sage: z.macaulay_resultant([x^3, 5*y, w]) # needs sage.modules sage.rings.finite_rings 4 example when the denominator in the algorithm vanishes(in this case @@ -1712,7 +1726,7 @@ cdef class MPolynomial(CommutativePolynomial): char polynomials of numerator/denominator):: sage: R. = PolynomialRing(QQ, 3) - sage: y.macaulay_resultant([x + z, z^2]) # optional - sage.modules + sage: y.macaulay_resultant([x + z, z^2]) # needs sage.libs.pari sage.modules -1 When there are only 2 polynomials, the Macaulay resultant degenerates to the traditional resultant:: @@ -1722,7 +1736,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: fh = f.homogenize() sage: gh = g.homogenize() sage: RH = fh.parent() - sage: f.resultant(g) == fh.macaulay_resultant(gh) # optional - sage.modules + sage: f.resultant(g) == fh.macaulay_resultant(gh) # needs sage.modules True """ @@ -1763,10 +1777,11 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: R. = NumberField(symbolic_expression(x^2+3),'a')['x,y'] # optional - sage.rings.number_field sage.symbolic - sage: f = (1/17)*x^19 + (1/6)*y - (2/3)*x + 1/3; f # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: R. = NumberField(symbolic_expression(x^2+3),'a')['x,y'] + sage: f = (1/17)*x^19 + (1/6)*y - (2/3)*x + 1/3; f 1/17*x^19 - 2/3*x + 1/6*y + 1/3 - sage: f.denominator() # optional - sage.rings.number_field sage.symbolic + sage: f.denominator() 102 Finally, we try to compute the denominator of a polynomial with @@ -1775,27 +1790,27 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: R. = RR[] - sage: f = a + b + RR('0.3'); f + sage: R. = RR[] # needs sage.rings.real_mpfr + sage: f = a + b + RR('0.3'); f # needs sage.rings.real_mpfr a + b + 0.300000000000000 - sage: f.denominator() + sage: f.denominator() # needs sage.rings.real_mpfr 1.00000000000000 Check that the denominator is an element over the base whenever the base has no denominator function. This closes :trac:`9063`:: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: x = R(0) # optional - sage.rings.finite_rings - sage: x.denominator() # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: x = R(0) + sage: x.denominator() 1 - sage: type(x.denominator()) # optional - sage.rings.finite_rings + sage: type(x.denominator()) - sage: type(a.denominator()) # optional - sage.rings.finite_rings + sage: type(a.denominator()) sage: from sage.rings.polynomial.multi_polynomial_element import MPolynomial - sage: isinstance(a / b, MPolynomial) # optional - sage.rings.finite_rings + sage: isinstance(a / b, MPolynomial) False - sage: isinstance(a.numerator() / a.denominator(), MPolynomial) # optional - sage.rings.finite_rings + sage: isinstance(a.numerator() / a.denominator(), MPolynomial) True """ if self.degree() == -1: @@ -1840,12 +1855,13 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: R. = NumberField(symbolic_expression(x^2+3), 'a')['x,y'] # optional - sage.rings.number_field sage.symbolic - sage: f = (1/17)*y^19 - (2/3)*x + 1/3; f # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: R. = NumberField(symbolic_expression(x^2+3), 'a')['x,y'] + sage: f = (1/17)*y^19 - (2/3)*x + 1/3; f 1/17*y^19 - 2/3*x + 1/3 - sage: f.numerator() # optional - sage.rings.number_field sage.symbolic + sage: f.numerator() 3*y^19 - 34*x + 17 - sage: f == f.numerator() # optional - sage.rings.number_field sage.symbolic + sage: f == f.numerator() False We try to compute the numerator of a polynomial with coefficients in @@ -1853,10 +1869,10 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: K. = GF(3)['x, y, z'] # optional - sage.rings.finite_rings - sage: f = 2*x*z + 2*z^2 + 2*y + 1; f # optional - sage.rings.finite_rings + sage: K. = GF(3)['x, y, z'] + sage: f = 2*x*z + 2*z^2 + 2*y + 1; f -x*z - z^2 - y + 1 - sage: f.numerator() # optional - sage.rings.finite_rings + sage: f.numerator() -x*z - z^2 - y + 1 We check that the computation the numerator and denominator @@ -1864,9 +1880,10 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['x']['s,t'] # optional - sage.rings.number_field sage.symbolic - sage: f = K.random_element() # optional - sage.rings.number_field sage.symbolic - sage: f.numerator() / f.denominator() == f # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['x']['s,t'] + sage: f = K.random_element() + sage: f.numerator() / f.denominator() == f True sage: R = RR['x,y,z'] sage: f = R.random_element() @@ -1882,13 +1899,13 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: A. = PolynomialRing(CC, 2, order='degrevlex') sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7 ]) sage: f = x*y^13 + y^12 - sage: M = f.lift(I) - sage: M + sage: M = f.lift(I); M # needs sage.libs.singular [y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4] - sage: sum( map( mul , zip( M, I.gens() ) ) ) == f + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True """ raise NotImplementedError @@ -1911,9 +1928,9 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1) - sage: f = x1 + 3*x2^2; g = f.inverse_mod(I); g # optional - sage.libs.singular + sage: f = x1 + 3*x2^2; g = f.inverse_mod(I); g # needs sage.libs.singular 1/16*x1 + 3/16 - sage: (f*g).reduce(I) # optional - sage.libs.singular + sage: (f*g).reduce(I) # needs sage.libs.singular 1 Test a non-invertible element:: @@ -1921,7 +1938,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1) sage: f = x1 + x2 - sage: f.inverse_mod(I) # optional - sage.libs.singular + sage: f.inverse_mod(I) # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: element is non-invertible @@ -1954,38 +1971,38 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = GF(7)[] # optional - sage.rings.finite_rings - sage: p = x^3 + y + x*z^2 # optional - sage.rings.finite_rings - sage: p.weighted_degree({z:0, x:1, y:2}) # optional - sage.rings.finite_rings + sage: R. = GF(7)[] + sage: p = x^3 + y + x*z^2 + sage: p.weighted_degree({z:0, x:1, y:2}) 3 - sage: p.weighted_degree(1, 2, 0) # optional - sage.rings.finite_rings + sage: p.weighted_degree(1, 2, 0) 3 - sage: p.weighted_degree((1, 4, 2)) # optional - sage.rings.finite_rings + sage: p.weighted_degree((1, 4, 2)) 5 - sage: p.weighted_degree((1, 4, 1)) # optional - sage.rings.finite_rings + sage: p.weighted_degree((1, 4, 1)) 4 - sage: p.weighted_degree(2**64, 2**50, 2**128) # optional - sage.rings.finite_rings + sage: p.weighted_degree(2**64, 2**50, 2**128) 680564733841876926945195958937245974528 - sage: q = R.random_element(100, 20) #random # optional - sage.rings.finite_rings - sage: q.weighted_degree(1, 1, 1) == q.total_degree() # optional - sage.rings.finite_rings + sage: q = R.random_element(100, 20) + sage: q.weighted_degree(1, 1, 1) == q.total_degree() True You may also work with negative weights :: - sage: p.weighted_degree(-1, -2, -1) # optional - sage.rings.finite_rings + sage: p.weighted_degree(-1, -2, -1) -2 Note that only integer weights are allowed :: - sage: p.weighted_degree(x, 1, 1) # optional - sage.rings.finite_rings + sage: p.weighted_degree(x, 1, 1) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Integer Ring - sage: p.weighted_degree(2/1, 1, 1) # optional - sage.rings.finite_rings + sage: p.weighted_degree(2/1, 1, 1) 6 The :meth:`weighted_degree` coincides with the :meth:`degree` of a weighted @@ -2000,6 +2017,7 @@ cdef class MPolynomial(CommutativePolynomial): TESTS:: + sage: # needs sage.modules sage: R = PolynomialRing(QQ, 'a', 5) sage: f = R.random_element(terms=20) sage: w = random_vector(ZZ,5) @@ -2076,7 +2094,7 @@ cdef class MPolynomial(CommutativePolynomial): Some multivariate polynomial rings have no gcd implementation:: - sage: R. = GaussianIntegers()[] + sage: R. = GaussianIntegers()[] # needs sage.rings.number_field sage: x.gcd(x) Traceback (most recent call last): ... @@ -2315,7 +2333,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = 19*x^8 - 262*x^7*h + 1507*x^6*h^2 - 4784*x^5*h^3 + 9202*x^4*h^4\ -10962*x^3*h^5 + 7844*x^2*h^6 - 3040*x*h^7 + 475*h^8 - sage: f.reduced_form(prec=200, smallest_coeffs=False) # optional - sage.modules + sage: f.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( -x^8 - 2*x^7*h + 7*x^6*h^2 + 16*x^5*h^3 + 2*x^4*h^4 - 2*x^3*h^5 + 4*x^2*h^6 - 5*h^8, @@ -2328,7 +2346,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = x^3 + 378666*x^2*y - 12444444*x*y^2 + 1234567890*y^3 sage: j = f * (x-545*y)^9 - sage: j.reduced_form(prec=200, smallest_coeffs=False) # optional - sage.modules + sage: j.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: cannot have a root with multiplicity >= 12/2 @@ -2337,7 +2355,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: F = x^6 + 3*x^5*y - 8*x^4*y^2 - 2*x^3*y^3 - 44*x^2*y^4 - 8*x*y^5 - sage: F.reduced_form(smallest_coeffs=False, prec=400) # optional - sage.modules + sage: F.reduced_form(smallest_coeffs=False, prec=400) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ArithmeticError: Newton's method converged to z not in the upper half plane @@ -2346,7 +2364,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: F = 5*x^2*y - 5*x*y^2 - 30*y^3 - sage: F.reduced_form(smallest_coeffs=False) # optional - sage.modules + sage: F.reduced_form(smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( [1 1] 5*x^2*y + 5*x*y^2 - 30*y^3, [0 1] @@ -2357,12 +2375,12 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: F = (-16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3 ....: - 666*x^3*y^4 - 481*x^2*y^5 - 207*x*y^6 - 40*y^7) - sage: F.reduced_form(prec=50, smallest_coeffs=False) # optional - sage.modules + sage: F.reduced_form(prec=50, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: accuracy of Newton's root not within tolerance(0.000012... > 1e-06), increase precision - sage: F.reduced_form(prec=100, smallest_coeffs=False) # optional - sage.modules + sage: F.reduced_form(prec=100, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( [-1 -1] -x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1 0] @@ -2372,14 +2390,14 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: F = - 8*x^4 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 1825511633*y^4 - sage: F.reduced_form(return_conjugation=False) # optional - sage.modules + sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field x^4 + 9*x^3*y - 3*x*y^3 - 8*y^4 :: sage: R. = QQ[] sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3 - sage: F.reduced_form() # optional - sage.modules + sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field ( [1 4] -2*x^3 - 22*x^2*y - 77*x*y^2 + 43*y^3, [0 1] @@ -2389,7 +2407,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = QQ[] sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3 - sage: F.reduced_form(norm_type='height') # optional - sage.modules + sage: F.reduced_form(norm_type='height') # needs sage.modules sage.rings.complex_interval_field ( [5 4] -58*x^3 - 47*x^2*y + 52*x*y^2 + 43*y^3, [1 1] @@ -2399,7 +2417,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: F = x^4 + x^3*y*z + y^2*z - sage: F.reduced_form() # optional - sage.modules + sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: (=x^3*y*z + x^4 + y^2*z) must have two variables @@ -2408,7 +2426,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(ZZ) sage: F = - 8*x^6 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 99*y^6 - sage: F.reduced_form(return_conjugation=False) # optional - sage.modules + sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: (=-8*x^6 - 99*y^6 - 3933*x^3*y - 725085*x^2*y^2 - @@ -2419,7 +2437,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(RR) sage: F = (217.992172373276*x^3 + 96023.1505442490*x^2*y ....: + 1.40987971253579e7*x*y^2 + 6.90016027113216e8*y^3) - sage: F.reduced_form(smallest_coeffs=False) # tol 1e-8 # optional - sage.modules + sage: F.reduced_form(smallest_coeffs=False) # tol 1e-8 # needs sage.modules sage.rings.complex_interval_field ( -39.5673942565918*x^3 + 111.874026298523*x^2*y + 231.052762985229*x*y^2 - 138.380829811096*y^3, @@ -2430,12 +2448,12 @@ cdef class MPolynomial(CommutativePolynomial): :: - sage: R. = PolynomialRing(CC) - sage: F = ((0.759099196558145 + 0.845425869641446*CC.0)*x^3 + sage: R. = PolynomialRing(CC) # needs sage.rings.real_mpfr + sage: F = ((0.759099196558145 + 0.845425869641446*CC.0)*x^3 # needs sage.rings.real_mpfr ....: + (84.8317207268542 + 93.8840848648033*CC.0)*x^2*y ....: + (3159.07040755858 + 3475.33037377779*CC.0)*x*y^2 ....: + (39202.5965389079 + 42882.5139724962*CC.0)*y^3) - sage: F.reduced_form(smallest_coeffs=False) # tol 1e-11 # optional - sage.modules + sage: F.reduced_form(smallest_coeffs=False) # tol 1e-11 # needs sage.modules sage.rings.complex_interval_field sage.rings.real_mpfr ( (-0.759099196558145 - 0.845425869641446*I)*x^3 + (-0.571709908900118 - 0.0418133346027929*I)*x^2*y @@ -2447,6 +2465,9 @@ cdef class MPolynomial(CommutativePolynomial): ) """ from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + from sage.rings.complex_interval_field import ComplexIntervalField + from sage.rings.real_mpfr import RealField if self.parent().ngens() != 2: raise ValueError("(=%s) must have two variables"%self) @@ -2459,7 +2480,7 @@ cdef class MPolynomial(CommutativePolynomial): emb = kwds.get('emb', None) # getting a numerical approximation of the roots of our polynomial - CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error + CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error RF = RealField(prec=prec) R = self.parent() x,y = R.gens() @@ -2527,16 +2548,17 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x + y).is_unit() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: (x + y).is_unit() False - sage: R(0).is_unit() # optional - sage.rings.number_field + sage: R(0).is_unit() False - sage: R(-1).is_unit() # optional - sage.rings.number_field + sage: R(-1).is_unit() True - sage: R(-1 + x).is_unit() # optional - sage.rings.number_field + sage: R(-1 + x).is_unit() False - sage: R(2).is_unit() # optional - sage.rings.number_field + sage: R(2).is_unit() True Check that :trac:`22454` is fixed:: @@ -2573,10 +2595,10 @@ cdef class MPolynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x + y).is_nilpotent() # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: (x + y).is_nilpotent() # needs sage.rings.number_field False - sage: R(0).is_nilpotent() # optional - sage.rings.number_field + sage: R(0).is_nilpotent() # needs sage.rings.number_field True sage: _. = Zmod(4)[] sage: (2*x).is_nilpotent() @@ -2605,8 +2627,8 @@ cdef class MPolynomial(CommutativePolynomial): TESTS:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x + y)._test_subs() # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: (x + y)._test_subs() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -2758,6 +2780,8 @@ cdef class MPolynomial(CommutativePolynomial): if self.degree() == 2: quadratic_derivs = set([self]) else: + from sage.combinat.integer_lists.invlex import IntegerListsLex + gens = self.parent().gens() quadratic_derivs = set() multi_exponents = IntegerListsLex(self.degree() - 2, length=len(gens)) @@ -2890,7 +2914,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: isinstance(x, MPolynomial_libsingular) False sage: R2. = QQ[] - sage: isinstance(y, MPolynomial_libsingular) # optional - sage.libs.singular + sage: isinstance(y, MPolynomial_libsingular) # needs sage.libs.singular True By design, there is a unique direct subclass:: diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 86d62c77bf9..27b6f577f16 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -31,8 +31,8 @@ We verify Lagrange's four squares identity:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: ((a0^2 + a1^2 + a2^2 + a3^2) * (b0^2 + b1^2 + b2^2 + b3^2) == # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: ((a0^2 + a1^2 + a2^2 + a3^2) * (b0^2 + b1^2 + b2^2 + b3^2) == # needs sage.rings.number_field ....: (a0*b0 - a1*b1 - a2*b2 - a3*b3)^2 + (a0*b1 + a1*b0 + a2*b3 - a3*b2)^2 ....: + (a0*b2 - a1*b3 + a2*b0 + a3*b1)^2 + (a0*b3 + a1*b2 - a2*b1 + a3*b0)^2) True @@ -94,13 +94,14 @@ def __init__(self, parent, x): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: L. = K.extension(x^3 - 3) # optional - sage.rings.number_field - sage: S. = L.extension(x^2 - 2) # optional - sage.rings.number_field - sage: S # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: L. = K.extension(x^3 - 3) + sage: S. = L.extension(x^2 - 2) + sage: S Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field - sage: P. = PolynomialRing(S) # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(S) # indirect doctest """ CommutativeRingElement.__init__(self, parent) self.__element = x @@ -109,8 +110,8 @@ def _repr_(self): """ EXAMPLES:: - sage: P. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: x + QQbar(sqrt(2) - 1/2*I) # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: x + QQbar(sqrt(2) - 1/2*I) # indirect doctest # needs sage.rings.number_field sage.symbolic x + 1.414213562373095? - 0.50000000000000000?*I """ return "%s"%self.__element @@ -127,6 +128,7 @@ def __call__(self, *x, **kwds): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R. = CC[] sage: f = x^2 + y^2 sage: f(1,2) @@ -136,9 +138,9 @@ def __call__(self, *x, **kwds): :: - sage: x = PolynomialRing(CC,3,'x').gens() - sage: f = x[0] + x[1] - 2*x[1]*x[2] - sage: f + sage: # needs sage.rings.real_mpfr + sage: x = PolynomialRing(CC, 3, 'x').gens() + sage: f = x[0] + x[1] - 2*x[1]*x[2]; f (-2.00000000000000)*x1*x2 + x0 + x1 sage: f(1,2,0) 3.00000000000000 @@ -187,26 +189,26 @@ def _richcmp_(self, right, op): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 3, order='lex') # optional - sage.rings.number_field - sage: x^1*y^2 > y^3*z^4 # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3, order='lex') # needs sage.rings.number_field + sage: x^1*y^2 > y^3*z^4 # needs sage.rings.number_field True - sage: x^3*y^2*z^4 < x^3*y^2*z^1 # optional - sage.rings.number_field + sage: x^3*y^2*z^4 < x^3*y^2*z^1 # needs sage.rings.number_field False :: - sage: R. = PolynomialRing(CC, 3, order='deglex') - sage: x^1*y^2*z^3 > x^3*y^2*z^0 + sage: R. = PolynomialRing(CC, 3, order='deglex') # needs sage.rings.real_mpfr + sage: x^1*y^2*z^3 > x^3*y^2*z^0 # needs sage.rings.real_mpfr True - sage: x^1*y^2*z^4 < x^1*y^1*z^5 + sage: x^1*y^2*z^4 < x^1*y^1*z^5 # needs sage.rings.real_mpfr False :: - sage: R. = PolynomialRing(QQbar, 3, order='degrevlex') # optional - sage.rings.number_field - sage: x^1*y^5*z^2 > x^4*y^1*z^3 # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3, order='degrevlex') # needs sage.rings.number_field + sage: x^1*y^5*z^2 > x^4*y^1*z^3 # needs sage.rings.number_field True - sage: x^4*y^7*z^1 < x^4*y^2*z^3 # optional - sage.rings.number_field + sage: x^4*y^7*z^1 < x^4*y^2*z^3 # needs sage.rings.number_field False """ return self.__element.rich_compare(right.__element, op, @@ -216,9 +218,9 @@ def _im_gens_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 2) # optional - sage.rings.number_field - sage: f = R.hom([y, x], R) # optional - sage.rings.number_field - sage: f(x^2 + 3*y^5) # indirect doctest # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 2) # needs sage.rings.number_field + sage: f = R.hom([y, x], R) # needs sage.rings.number_field + sage: f(x^2 + 3*y^5) # indirect doctest # needs sage.rings.number_field 3*x^5 + y^2 You can specify a map on the base ring:: @@ -250,6 +252,7 @@ def number_of_terms(self): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R. = CC[] sage: f = x^3 - y sage: f.number_of_terms() @@ -262,7 +265,7 @@ def number_of_terms(self): The method :meth:`hamming_weight` is an alias:: - sage: f.hamming_weight() + sage: f.hamming_weight() # needs sage.rings.real_mpfr 101 """ return len(self.element().dict()) @@ -275,10 +278,10 @@ def __neg__(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: -x # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: -x # needs sage.rings.number_field -x - sage: -(y-1) # optional - sage.rings.number_field + sage: -(y-1) # needs sage.rings.number_field -y + 1 """ return self.__class__(self.parent(), -self.__element) @@ -289,8 +292,8 @@ def _add_(self, right): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x + y # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: x + y # needs sage.rings.number_field x + y """ elt = self.__element + right.__element @@ -303,8 +306,8 @@ def _sub_(self, right): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x - y # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: x - y # needs sage.rings.number_field x - y """ elt = self.__element - right.__element @@ -317,8 +320,8 @@ def _mul_(self, right): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x * y # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: x * y # needs sage.rings.number_field x*y """ elt = self.__element * right.__element @@ -337,9 +340,9 @@ def _lmul_(self, a): :: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = (x + y) # optional - sage.rings.number_field - sage: 3 * f # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = (x + y) # needs sage.rings.number_field + sage: 3 * f # needs sage.rings.number_field 3*x + 3*y """ elt = self.__element.scalar_lmult(a) @@ -358,9 +361,9 @@ def _rmul_(self, a): :: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = (x + y) # optional - sage.rings.number_field - sage: f * 3 # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = (x + y) # needs sage.rings.number_field + sage: f * 3 # needs sage.rings.number_field 3*x + 3*y """ elt = self.__element.scalar_rmult(a) @@ -371,19 +374,19 @@ def _div_(self, right): r""" EXAMPLES:: - sage: R. = CC['x,y'] - sage: f = (x + y)/x; f + sage: R. = CC['x,y'] # needs sage.rings.real_mpfr + sage: f = (x + y)/x; f # needs sage.rings.real_mpfr (x + y)/x - sage: f.parent() + sage: f.parent() # needs sage.rings.real_mpfr Fraction Field of Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision If dividing by a scalar, there is no need to go to the fraction field of the polynomial ring:: - sage: f = (x + y)/2; f + sage: f = (x + y)/2; f # needs sage.rings.real_mpfr 0.500000000000000*x + 0.500000000000000*y - sage: f.parent() + sage: f.parent() # needs sage.rings.real_mpfr Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision @@ -423,15 +426,16 @@ def change_ring(self, R): sage: R. = QQ[] sage: f = x^2 + 5*y - sage: f.change_ring(GF(5)) # optional - sage.rings.finite_rings + sage: f.change_ring(GF(5)) x^2 :: - sage: K. = CyclotomicField(5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: f = x^2 + w*y # optional - sage.rings.number_field - sage: f.change_ring(K.embeddings(QQbar)[1]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(5) + sage: R. = K[] + sage: f = x^2 + w*y + sage: f.change_ring(K.embeddings(QQbar)[1]) x^2 + (-0.8090169943749474? + 0.5877852522924731?*I)*y """ if isinstance(R, Morphism): @@ -452,10 +456,10 @@ def __init__(self, parent, x): """ EXAMPLES:: - sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() # optional - sage.rings.number_field - sage: x # optional - sage.rings.number_field + sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() # needs sage.rings.number_field + sage: x # needs sage.rings.number_field (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) - sage: loads(dumps(x)) == x # optional - sage.rings.number_field + sage: loads(dumps(x)) == x # needs sage.rings.number_field True """ if not isinstance(x, polydict.PolyDict): @@ -485,12 +489,13 @@ def _repr_(self): """ EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: repr(-x^2 - y + 1) # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: repr(-x^2 - y + 1) # indirect doctest '-x^2 - y + 1' - sage: K. = QuadraticField(-1) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: repr(-I*y - x^2) # indirect doctest # optional - sage.rings.number_field + sage: K. = QuadraticField(-1) + sage: R. = K[] + sage: repr(-I*y - x^2) # indirect doctest '-x^2 + (-I)*y' """ try: @@ -506,12 +511,13 @@ def _latex_(self): r""" EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: latex(-x^2 - y + 1) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: latex(-x^2 - y + 1) -x^{2} - y + 1 - sage: K. = QuadraticField(-1) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: latex(-I*y + I*x^2) # optional - sage.rings.number_field + sage: K. = QuadraticField(-1) + sage: R. = K[] + sage: latex(-I*y + I*x^2) \left(\sqrt{-1}\right) x^{2} + \left(-\sqrt{-1}\right) y """ try: @@ -526,9 +532,9 @@ def _repr_with_changed_varnames(self, varnames): """ EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = -x^2 - y + 1 # optional - sage.rings.number_field - sage: f._repr_with_changed_varnames(['jack', 'jill']) # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = -x^2 - y + 1 # needs sage.rings.number_field + sage: f._repr_with_changed_varnames(['jack', 'jill']) # needs sage.rings.number_field '-jack^2 - jill + 1' """ try: @@ -543,8 +549,8 @@ def _macaulay2_(self, macaulay2=None): """ EXAMPLES:: - sage: R = GF(13)['a,b']['c,d'] # optional - sage.rings.finite_rings - sage: macaulay2(R('a^2 + c')) # optional - macaulay2 sage.rings.finite_rings + sage: R = GF(13)['a,b']['c,d'] + sage: macaulay2(R('a^2 + c')) # optional - macaulay2 2 c + a @@ -553,7 +559,7 @@ def _macaulay2_(self, macaulay2=None): Elements of the base ring are coerced to the polynomial ring correctly:: - sage: macaulay2(R('a^2')).ring()._operator('===', R) # optional - macaulay2 sage.rings.finite_rings + sage: macaulay2(R('a^2')).ring()._operator('===', R) # optional - macaulay2 true """ if macaulay2 is None: @@ -571,20 +577,21 @@ def degrees(self): EXAMPLES:: - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.degrees() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar) + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.degrees() (2, 2, 0) - sage: f = x^2 + z^2 # optional - sage.rings.number_field - sage: f.degrees() # optional - sage.rings.number_field + sage: f = x^2 + z^2 + sage: f.degrees() (2, 0, 2) - sage: f.total_degree() # this simply illustrates that total degree is not the sum of the degrees # optional - sage.rings.number_field + sage: f.total_degree() # this simply illustrates that total degree is not the sum of the degrees 2 - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: f = (1-x) * (1+y+z+x^3)^5 # optional - sage.rings.number_field - sage: f.degrees() # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar) + sage: f = (1-x) * (1+y+z+x^3)^5 + sage: f.degrees() (16, 5, 5, 0) - sage: R(0).degrees() # optional - sage.rings.number_field + sage: R(0).degrees() (0, 0, 0, 0) """ if not self: @@ -653,46 +660,47 @@ def degree(self, x=None, std_grading=False): :: sage: x, y = ZZ['x','y'].gens() - sage: GF(3037000453)['x','y'].gen(0).degree(x) + sage: GF(3037000453)['x','y'].gen(0).degree(x) # needs sage.rings.finite_rings 1 sage: x0, y0 = QQ['x','y'].gens() - sage: GF(3037000453)['x','y'].gen(0).degree(x0) + sage: GF(3037000453)['x','y'].gen(0).degree(x0) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: x must canonically coerce to parent - sage: GF(3037000453)['x','y'].gen(0).degree(x^2) # optional - sage.rings.finite_rings + sage: GF(3037000453)['x','y'].gen(0).degree(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: x must be one of the generators of the parent TESTS:: - sage: R = PolynomialRing(GF(2)['t'], 'x,y', order=TermOrder('wdeglex', (2,3))) # optional - sage.rings.finite_rings - sage: x, y = R.gens() # optional - sage.rings.finite_rings - sage: x.degree() # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(2)['t'], 'x,y', + ....: order=TermOrder('wdeglex', (2,3))) + sage: x, y = R.gens() + sage: x.degree() 2 - sage: y.degree() # optional - sage.rings.finite_rings + sage: y.degree() 3 - sage: x.degree(y), x.degree(x), y.degree(x), y.degree(y) # optional - sage.rings.finite_rings + sage: x.degree(y), x.degree(x), y.degree(x), y.degree(y) (0, 1, 0, 1) - sage: f = (x^2*y + x*y^2) # optional - sage.rings.finite_rings - sage: f.degree(x) # optional - sage.rings.finite_rings + sage: f = (x^2*y + x*y^2) + sage: f.degree(x) 2 - sage: f.degree(y) # optional - sage.rings.finite_rings + sage: f.degree(y) 2 - sage: f.degree() # optional - sage.rings.finite_rings + sage: f.degree() 8 - sage: f.degree(std_grading=True) # optional - sage.rings.finite_rings + sage: f.degree(std_grading=True) 3 - sage: R(0).degree() # optional - sage.rings.finite_rings + sage: R(0).degree() -1 Degree of zero polynomial for other implementation :trac:`20048` :: - sage: R. = GF(3037000453)[] # optional - sage.rings.finite_rings - sage: R.zero().degree(x) # optional - sage.rings.finite_rings + sage: R. = GF(3037000453)[] # needs sage.rings.finite_rings + sage: R.zero().degree(x) -1 """ if x is None: @@ -718,24 +726,25 @@ def total_degree(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 2*x*y^3*z^2 # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 2*x*y^3*z^2 + sage: f.total_degree() 6 - sage: f = 4*x^2*y^2*z^3 # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: f = 4*x^2*y^2*z^3 + sage: f.total_degree() 7 - sage: f = 99*x^6*y^3*z^9 # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: f = 99*x^6*y^3*z^9 + sage: f.total_degree() 18 - sage: f = x*y^3*z^6 + 3*x^2 # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: f = x*y^3*z^6 + 3*x^2 + sage: f.total_degree() 10 - sage: f = z^3 + 8*x^4*y^5*z # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: f = z^3 + 8*x^4*y^5*z + sage: f.total_degree() 10 - sage: f = z^9 + 10*x^4 + y^8*x^2 # optional - sage.rings.number_field - sage: f.total_degree() # optional - sage.rings.number_field + sage: f = z^9 + 10*x^4 + y^8*x^2 + sage: f.total_degree() 10 """ return self.degree() @@ -766,33 +775,36 @@ def monomial_coefficient(self, mon): :: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 2 * x * y # optional - sage.rings.number_field - sage: c = f.monomial_coefficient(x*y); c # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 2 * x * y + sage: c = f.monomial_coefficient(x*y); c 2 - sage: c.parent() # optional - sage.rings.number_field + sage: c.parent() Algebraic Field :: - sage: f = y^2 + y^2*x - x^9 - 7*x + 5*x*y # optional - sage.rings.number_field - sage: f.monomial_coefficient(y^2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: f = y^2 + y^2*x - x^9 - 7*x + 5*x*y + sage: f.monomial_coefficient(y^2) 1 - sage: f.monomial_coefficient(x*y) # optional - sage.rings.number_field + sage: f.monomial_coefficient(x*y) 5 - sage: f.monomial_coefficient(x^9) # optional - sage.rings.number_field + sage: f.monomial_coefficient(x^9) -1 - sage: f.monomial_coefficient(x^10) # optional - sage.rings.number_field + sage: f.monomial_coefficient(x^10) 0 :: + sage: # needs sage.rings.number_field sage: a = polygen(ZZ, 'a') - sage: K. = NumberField(a^2 + a + 1) # optional - sage.rings.number_field - sage: P. = K[] # optional - sage.rings.number_field - sage: f = (a*x - 1) * ((a+1)*y - 1); f # optional - sage.rings.number_field + sage: K. = NumberField(a^2 + a + 1) + sage: P. = K[] + sage: f = (a*x - 1) * ((a+1)*y - 1); f -x*y + (-a)*x + (-a - 1)*y + 1 - sage: f.monomial_coefficient(x) # optional - sage.rings.number_field + sage: f.monomial_coefficient(x) -a """ if parent(mon) is not self.parent(): @@ -814,23 +826,23 @@ def __iter__(self): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, order='lex') # optional - sage.rings.number_field - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # optional - sage.rings.number_field - sage: list(f) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='lex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x^4*y*z^3), (1, x^2*z), (1, x*y^5*z^2)] :: - sage: R. = PolynomialRing(QQbar, order='deglex') # optional - sage.rings.number_field - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # optional - sage.rings.number_field - sage: list(f) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='deglex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x^4*y*z^3), (1, x*y^5*z^2), (1, x^2*z)] :: - sage: R. = PolynomialRing(QQbar, order='degrevlex') # optional - sage.rings.number_field - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # optional - sage.rings.number_field - sage: list(f) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='degrevlex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x*y^5*z^2), (1, x^4*y*z^3), (1, x^2*z)] :: @@ -861,22 +873,23 @@ def __getitem__(self, x): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 2) # optional - sage.rings.number_field - sage: f = -10*x^3*y + 17*x*y # optional - sage.rings.number_field - sage: f[3,1] # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 2) + sage: f = -10*x^3*y + 17*x*y + sage: f[3,1] -10 - sage: f[1,1] # optional - sage.rings.number_field + sage: f[1,1] 17 - sage: f[0,1] # optional - sage.rings.number_field + sage: f[0,1] 0 :: - sage: R. = PolynomialRing(QQbar, 1); R # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 1); R # needs sage.rings.number_field Multivariate Polynomial Ring in x over Algebraic Field - sage: f = 5*x^2 + 3; f # optional - sage.rings.number_field + sage: f = 5*x^2 + 3; f # needs sage.rings.number_field 5*x^2 + 3 - sage: f[2] # optional - sage.rings.number_field + sage: f[2] # needs sage.rings.number_field 5 """ if isinstance(x, MPolynomial): @@ -902,14 +915,14 @@ def iterator_exp_coeff(self, as_ETuples=True): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, order='lex') # optional - sage.rings.number_field - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # optional - sage.rings.number_field - sage: list(f.iterator_exp_coeff()) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='lex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f.iterator_exp_coeff()) # needs sage.rings.number_field [((4, 1, 3), 1), ((2, 0, 1), 1), ((1, 5, 2), 1)] - sage: R. = PolynomialRing(QQbar, order='deglex') # optional - sage.rings.number_field - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # optional - sage.rings.number_field - sage: list(f.iterator_exp_coeff(as_ETuples=False)) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='deglex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f.iterator_exp_coeff(as_ETuples=False)) # needs sage.rings.number_field [((4, 1, 3), 1), ((1, 5, 2), 1), ((2, 0, 1), 1)] """ elt = self.element() @@ -954,35 +967,37 @@ def coefficient(self, degrees): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 2 * x * y # optional - sage.rings.number_field - sage: c = f.coefficient({x: 1, y: 1}); c # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 2 * x * y + sage: c = f.coefficient({x: 1, y: 1}); c 2 - sage: c.parent() # optional - sage.rings.number_field + sage: c.parent() Multivariate Polynomial Ring in x, y over Algebraic Field - sage: c in PolynomialRing(QQbar, 2, names=['x', 'y']) # optional - sage.rings.number_field + sage: c in PolynomialRing(QQbar, 2, names=['x', 'y']) True - sage: f = y^2 - x^9 - 7*x + 5*x*y # optional - sage.rings.number_field - sage: f.coefficient({y: 1}) # optional - sage.rings.number_field + sage: f = y^2 - x^9 - 7*x + 5*x*y + sage: f.coefficient({y: 1}) 5*x - sage: f.coefficient({y: 0}) # optional - sage.rings.number_field + sage: f.coefficient({y: 0}) -x^9 + (-7)*x - sage: f.coefficient({x: 0, y: 0}) # optional - sage.rings.number_field + sage: f.coefficient({x: 0, y: 0}) 0 - sage: f = (1+y+y^2) * (1+x+x^2) # optional - sage.rings.number_field - sage: f.coefficient({x: 0}) # optional - sage.rings.number_field + sage: f = (1+y+y^2) * (1+x+x^2) + sage: f.coefficient({x: 0}) y^2 + y + 1 - sage: f.coefficient([0, None]) # optional - sage.rings.number_field + sage: f.coefficient([0, None]) y^2 + y + 1 - sage: f.coefficient(x) # optional - sage.rings.number_field + sage: f.coefficient(x) y^2 + y + 1 sage: # Be aware that this may not be what you think! sage: # The physical appearance of the variable x is deceiving -- particularly if the exponent would be a variable. - sage: f.coefficient(x^0) # outputs the full polynomial # optional - sage.rings.number_field + sage: f.coefficient(x^0) # outputs the full polynomial x^2*y^2 + x^2*y + x*y^2 + x^2 + x*y + y^2 + x + y + 1 :: + sage: # needs sage.rings.real_mpfr sage: R. = RR[] sage: f = x*y + 5 sage: c = f.coefficient({x: 0, y: 0}); c @@ -1026,42 +1041,44 @@ def global_height(self, prec=None): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 2) # optional - sage.rings.number_field - sage: f = QQbar(i)*x^2 + 3*x*y # optional - sage.rings.number_field - sage: f.global_height() # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 2) # needs sage.rings.number_field + sage: f = QQbar(i)*x^2 + 3*x*y # needs sage.rings.number_field + sage: f.global_height() # needs sage.rings.number_field 1.09861228866811 Scaling should not change the result:: - sage: R. = PolynomialRing(QQbar, 2) # optional - sage.rings.number_field - sage: f = 1/25*x^2 + 25/3*x + 1 + QQbar(sqrt(2))*y^2 # optional - sage.rings.number_field sage.symbolic - sage: f.global_height() # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: R. = PolynomialRing(QQbar, 2) + sage: f = 1/25*x^2 + 25/3*x + 1 + QQbar(sqrt(2))*y^2 + sage: f.global_height() 6.43775164973640 - sage: g = 100 * f # optional - sage.rings.number_field sage.symbolic - sage: g.global_height() # optional - sage.rings.number_field sage.symbolic + sage: g = 100 * f + sage: g.global_height() 6.43775164973640 :: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: Q. = PolynomialRing(K, implementation='generic') # optional - sage.rings.number_field - sage: f = 12 * q # optional - sage.rings.number_field - sage: f.global_height() # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: Q. = PolynomialRing(K, implementation='generic') + sage: f = 12 * q + sage: f.global_height() 0.000000000000000 :: sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 1/123*x*y + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 0*x*y - sage: f.global_height() + sage: f.global_height() # needs sage.rings.real_mpfr 0.000000000000000 """ if prec is None: @@ -1071,16 +1088,16 @@ def global_height(self, prec=None): from sage.rings.real_mpfr import RealField return RealField(prec).zero() - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields - from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics K = self.base_ring() - if K in NumberFields() or is_NumberFieldOrder(K): + if K in NumberFields() or isinstance(K, (sage.rings.abc.Order, sage.rings.integer_ring.IntegerRing_class)): from sage.schemes.projective.projective_space import ProjectiveSpace Pr = ProjectiveSpace(K, self.number_of_terms()-1) return Pr.point(self.coefficients()).global_height(prec=prec) - if K is QQbar: + if isinstance(K, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import number_field_elements_from_algebraics + K_pre, P, phi = number_field_elements_from_algebraics(list(self.coefficients())) from sage.schemes.projective.projective_space import ProjectiveSpace Pr = ProjectiveSpace(K_pre, len(P)-1) @@ -1106,34 +1123,34 @@ def local_height(self, v, prec=None): sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 1/1331*x^2 + 1/4000*y - sage: f.local_height(1331) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^2 - 5) # optional - sage.rings.number_field - sage: T. = PolynomialRing(K, implementation='generic') # optional - sage.rings.number_field - sage: I = K.ideal(3) # optional - sage.rings.number_field - sage: f = 1/3*t*w + 3 # optional - sage.rings.number_field - sage: f.local_height(I) # optional - sage.rings.number_field sage.symbolic + sage: K. = NumberField(x^2 - 5) + sage: T. = PolynomialRing(K, implementation='generic') + sage: I = K.ideal(3) + sage: f = 1/3*t*w + 3 + sage: f.local_height(I) # needs sage.symbolic 1.09861228866811 :: sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 1/2*x*y + 2 - sage: f.local_height(2, prec=2) + sage: f.local_height(2, prec=2) # needs sage.rings.real_mpfr 0.75 """ - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, (sage.rings.abc.Order, IntegerRing_class))): raise TypeError("must be over a Numberfield or a Numberfield order") return max([K(c).local_height(v, prec=prec) for c in self.coefficients()]) @@ -1156,33 +1173,33 @@ def local_height_arch(self, i, prec=None): sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 210*x*y - sage: f.local_height_arch(0) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^2 - 5) # optional - sage.rings.number_field - sage: T. = PolynomialRing(K, implementation='generic') # optional - sage.rings.number_field - sage: f = 1/2*t*w + 3 # optional - sage.rings.number_field - sage: f.local_height_arch(1, prec=52) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 5) + sage: T. = PolynomialRing(K, implementation='generic') + sage: f = 1/2*t*w + 3 + sage: f.local_height_arch(1, prec=52) 1.09861228866811 :: sage: R. = PolynomialRing(QQ, implementation='generic') sage: f = 1/2*x*y + 3 - sage: f.local_height_arch(0, prec=2) + sage: f.local_height_arch(0, prec=2) # needs sage.rings.real_mpfr 1.0 """ - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, (sage.rings.abc.Order, IntegerRing_class))): return TypeError("must be over a Numberfield or a Numberfield Order") if K == QQ: @@ -1197,9 +1214,9 @@ def _exponents(self): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 3) # optional - sage.rings.number_field - sage: f = a^3 + b + 2*b^2 # optional - sage.rings.number_field - sage: f._exponents # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3) # needs sage.rings.number_field + sage: f = a^3 + b + 2*b^2 # needs sage.rings.number_field + sage: f._exponents # needs sage.rings.number_field [(3, 0, 0), (0, 2, 0), (0, 1, 0)] """ return sorted(self.element().dict(), key=self.parent().term_order().sortkey, reverse=True) @@ -1219,29 +1236,30 @@ def exponents(self, as_ETuples=True): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, 3) # optional - sage.rings.number_field - sage: f = a^3 + b + 2*b^2 # optional - sage.rings.number_field - sage: f.exponents() # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3) # needs sage.rings.number_field + sage: f = a^3 + b + 2*b^2 # needs sage.rings.number_field + sage: f.exponents() # needs sage.rings.number_field [(3, 0, 0), (0, 2, 0), (0, 1, 0)] By default the list of exponents is a list of ETuples:: - sage: type(f.exponents()[0]) # optional - sage.rings.number_field + sage: type(f.exponents()[0]) # needs sage.rings.number_field - sage: type(f.exponents(as_ETuples=False)[0]) # optional - sage.rings.number_field + sage: type(f.exponents(as_ETuples=False)[0]) # needs sage.rings.number_field <... 'tuple'> TESTS: Check that we can mutate the list and not change the result:: - sage: R. = PolynomialRing(QQbar, 3) # optional - sage.rings.number_field - sage: f = a^3 + b + 2*b^2 # optional - sage.rings.number_field - sage: E = f.exponents(); E # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3) + sage: f = a^3 + b + 2*b^2 + sage: E = f.exponents(); E [(3, 0, 0), (0, 2, 0), (0, 1, 0)] - sage: E.pop() # optional - sage.rings.number_field + sage: E.pop() (0, 1, 0) - sage: E != f.exponents() # optional - sage.rings.number_field + sage: E != f.exponents() True """ if as_ETuples: @@ -1273,18 +1291,19 @@ def is_homogeneous(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x + y).is_homogeneous() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: (x + y).is_homogeneous() True - sage: (x.parent()(0)).is_homogeneous() # optional - sage.rings.number_field + sage: (x.parent()(0)).is_homogeneous() True - sage: (x + y^2).is_homogeneous() # optional - sage.rings.number_field + sage: (x + y^2).is_homogeneous() False - sage: (x^2 + y^2).is_homogeneous() # optional - sage.rings.number_field + sage: (x^2 + y^2).is_homogeneous() True - sage: (x^2 + y^2*x).is_homogeneous() # optional - sage.rings.number_field + sage: (x^2 + y^2*x).is_homogeneous() False - sage: (x^2*y + y^2*x).is_homogeneous() # optional - sage.rings.number_field + sage: (x^2*y + y^2*x).is_homogeneous() True """ return self.element().is_homogeneous() @@ -1306,11 +1325,12 @@ def _homogenize(self, var): EXAMPLES:: - sage: P. = QQbar[] # optional - sage.rings.number_field - sage: f = x^2 + y + 1 + 5*x*y^1 # optional - sage.rings.number_field - sage: g = f.homogenize('z'); g # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = QQbar[] + sage: f = x^2 + y + 1 + 5*x*y^1 + sage: g = f.homogenize('z'); g # indirect doctest x^2 + 5*x*y + y*z + z^2 - sage: g.parent() # optional - sage.rings.number_field + sage: g.parent() Multivariate Polynomial Ring in x, y, z over Algebraic Field SEE: ``self.homogenize`` @@ -1328,12 +1348,13 @@ def is_generator(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x.is_generator() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: x.is_generator() True - sage: (x + y - y).is_generator() # optional - sage.rings.number_field + sage: (x + y - y).is_generator() True - sage: (x*y).is_generator() # optional - sage.rings.number_field + sage: (x*y).is_generator() False """ elt = self.element() @@ -1351,21 +1372,22 @@ def is_monomial(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x.is_monomial() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: x.is_monomial() True - sage: (x + 2*y).is_monomial() # optional - sage.rings.number_field + sage: (x + 2*y).is_monomial() False - sage: (2*x).is_monomial() # optional - sage.rings.number_field + sage: (2*x).is_monomial() False - sage: (x*y).is_monomial() # optional - sage.rings.number_field + sage: (x*y).is_monomial() True To allow a non-1 leading coefficient, use :meth:`is_term`:: - sage: (2*x*y).is_term() # optional - sage.rings.number_field + sage: (2*x*y).is_term() # needs sage.rings.number_field True - sage: (2*x*y).is_monomial() # optional - sage.rings.number_field + sage: (2*x*y).is_monomial() # needs sage.rings.number_field False """ return len(self.element()) == 1 and self.element().coefficients()[0] == 1 @@ -1380,21 +1402,22 @@ def is_term(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x.is_term() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: x.is_term() True - sage: (x + 2*y).is_term() # optional - sage.rings.number_field + sage: (x + 2*y).is_term() False - sage: (2*x).is_term() # optional - sage.rings.number_field + sage: (2*x).is_term() True - sage: (7*x^5*y).is_term() # optional - sage.rings.number_field + sage: (7*x^5*y).is_term() True To require leading coefficient 1, use :meth:`is_monomial`:: - sage: (2*x*y).is_monomial() # optional - sage.rings.number_field + sage: (2*x*y).is_monomial() # needs sage.rings.number_field False - sage: (2*x*y).is_term() # optional - sage.rings.number_field + sage: (2*x*y).is_term() # needs sage.rings.number_field True """ return len(self.element()) == 1 @@ -1421,11 +1444,12 @@ def subs(self, fixed=None, **kw): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = x^2 + y + x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f((5, y)) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = x^2 + y + x^2*y^2 + 5 + sage: f((5, y)) 25*y^2 + y + 30 - sage: f.subs({x: 5}) # optional - sage.rings.number_field + sage: f.subs({x: 5}) 25*y^2 + y + 30 """ variables = list(self.parent().gens()) @@ -1445,21 +1469,22 @@ def monomials(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.monomials() # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # needs sage.rings.number_field + sage: f.monomials() # needs sage.rings.number_field [x^2*y^2, x^2, y, 1] :: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: F = (fx*gy - fy*gx)^3; F # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: F = (fx*gy - fy*gx)^3; F -fy^3*gx^3 + 3*fx*fy^2*gx^2*gy + (-3)*fx^2*fy*gx*gy^2 + fx^3*gy^3 - sage: F.monomials() # optional - sage.rings.number_field + sage: F.monomials() [fy^3*gx^3, fx*fy^2*gx^2*gy, fx^2*fy*gx*gy^2, fx^3*gy^3] - sage: F.coefficients() # optional - sage.rings.number_field + sage: F.coefficients() [-1, 3, -3, 1] - sage: sum(map(mul, zip(F.coefficients(), F.monomials()))) == F # optional - sage.rings.number_field + sage: sum(map(mul, zip(F.coefficients(), F.monomials()))) == F True """ ring = self.parent() @@ -1473,12 +1498,13 @@ def constant_coefficient(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.constant_coefficient() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.constant_coefficient() 5 - sage: f = 3*x^2 # optional - sage.rings.number_field - sage: f.constant_coefficient() # optional - sage.rings.number_field + sage: f = 3*x^2 + sage: f.constant_coefficient() 0 """ #v = (0,)*int(self.parent().ngens()) @@ -1495,16 +1521,17 @@ def is_univariate(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.is_univariate() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.is_univariate() False - sage: g = f.subs({x: 10}); g # optional - sage.rings.number_field + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.is_univariate() # optional - sage.rings.number_field + sage: g.is_univariate() True - sage: f = x^0 # optional - sage.rings.number_field - sage: f.is_univariate() # optional - sage.rings.number_field + sage: f = x^0 + sage: f.is_univariate() True """ mons = self.element().dict() @@ -1537,17 +1564,18 @@ def univariate_polynomial(self, R=None): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.univariate_polynomial() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.univariate_polynomial() Traceback (most recent call last): ... TypeError: polynomial must involve at most one variable - sage: g = f.subs({x: 10}); g # optional - sage.rings.number_field + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.univariate_polynomial() # optional - sage.rings.number_field + sage: g.univariate_polynomial() 700*y^2 - 2*y + 305 - sage: g.univariate_polynomial(PolynomialRing(QQ, 'z')) # optional - sage.rings.number_field + sage: g.univariate_polynomial(PolynomialRing(QQ, 'z')) 700*z^2 - 2*z + 305 TESTS:: @@ -1602,13 +1630,14 @@ def variables(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.variables() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.variables() (x, y) - sage: g = f.subs({x: 10}); g # optional - sage.rings.number_field + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.variables() # optional - sage.rings.number_field + sage: g.variables() (y,) TESTS: @@ -1627,11 +1656,12 @@ def variable(self,i): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.variable(0) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.variable(0) x - sage: f.variable(1) # optional - sage.rings.number_field + sage: f.variable(1) y """ return self.variables()[int(i)] @@ -1642,13 +1672,14 @@ def nvariables(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.nvariables() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.nvariables() 2 - sage: g = f.subs({x: 10}); g # optional - sage.rings.number_field + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.nvariables() # optional - sage.rings.number_field + sage: g.nvariables() 1 """ return len(self.degrees().nonzero_positions()) @@ -1659,12 +1690,13 @@ def is_constant(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # optional - sage.rings.number_field - sage: f.is_constant() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 + sage: f.is_constant() False - sage: g = 10*x^0 # optional - sage.rings.number_field - sage: g.is_constant() # optional - sage.rings.number_field + sage: g = 10*x^0 + sage: g.is_constant() True """ return self.element().is_constant() @@ -1676,14 +1708,15 @@ def lm(self): EXAMPLES:: - sage: R. = PolynomialRing(GF(7), 3, order='lex') # optional - sage.rings.finite_rings - sage: (x^1*y^2 + y^3*z^4).lm() # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(7), 3, order='lex') + sage: (x^1*y^2 + y^3*z^4).lm() x*y^2 - sage: (x^3*y^2*z^4 + x^3*y^2*z^1).lm() # optional - sage.rings.finite_rings + sage: (x^3*y^2*z^4 + x^3*y^2*z^1).lm() x^3*y^2*z^4 :: + sage: # needs sage.rings.real_mpfr sage: R. = PolynomialRing(CC, 3, order='deglex') sage: (x^1*y^2*z^3 + x^3*y^2*z^0).lm() x*y^2*z^3 @@ -1692,18 +1725,19 @@ def lm(self): :: - sage: R. = PolynomialRing(QQbar, 3, order='degrevlex') # optional - sage.rings.number_field - sage: (x^1*y^5*z^2 + x^4*y^1*z^3).lm() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, 3, order='degrevlex') + sage: (x^1*y^5*z^2 + x^4*y^1*z^3).lm() x*y^5*z^2 - sage: (x^4*y^7*z^1 + x^4*y^2*z^3).lm() # optional - sage.rings.number_field + sage: (x^4*y^7*z^1 + x^4*y^2*z^3).lm() x^4*y^7*z TESTS:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - sage: R. = MPolynomialRing_polydict(GF(2), 2, order='lex') # optional - sage.rings.finite_rings - sage: f = x + y # optional - sage.rings.finite_rings - sage: f.lm() # optional - sage.rings.finite_rings + sage: R. = MPolynomialRing_polydict(GF(2), 2, order='lex') + sage: f = x + y + sage: f.lm() x """ @@ -1725,9 +1759,9 @@ def lc(self): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = 3*x^2 - y^2 - x*y # optional - sage.rings.number_field - sage: f.lc() # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = 3*x^2 - y^2 - x*y # needs sage.rings.number_field + sage: f.lc() # needs sage.rings.number_field 3 """ try: @@ -1748,21 +1782,22 @@ def lt(self): EXAMPLES:: - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: f = 3*x^2 - y^2 - x*y # optional - sage.rings.number_field - sage: f.lt() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar) + sage: f = 3*x^2 - y^2 - x*y + sage: f.lt() 3*x^2 - sage: R. = PolynomialRing(QQbar, order="invlex") # optional - sage.rings.number_field - sage: f = 3*x^2 - y^2 - x*y # optional - sage.rings.number_field - sage: f.lt() # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order="invlex") + sage: f = 3*x^2 - y^2 - x*y + sage: f.lt() -y^2 TESTS:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - sage: R. = MPolynomialRing_polydict(GF(2), 2, order='lex') # optional - sage.rings.finite_rings - sage: f = x + y # optional - sage.rings.finite_rings - sage: f.lt() # optional - sage.rings.finite_rings + sage: R. = MPolynomialRing_polydict(GF(2), 2, order='lex') + sage: f = x + y + sage: f.lt() x """ try: @@ -1816,14 +1851,15 @@ def _floordiv_(self, right): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: 2*x*y//y # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: 2*x*y//y 2*x - sage: 2*x//y # optional - sage.rings.number_field + sage: 2*x//y 0 - sage: 2*x//4 # optional - sage.rings.number_field + sage: 2*x//4 1/2*x - sage: type(0//y) # optional - sage.rings.number_field + sage: type(0//y) """ # handle division by monomials without using Singular @@ -1853,26 +1889,27 @@ def _derivative(self, var=None): EXAMPLES:: - sage: R. = PowerSeriesRing(QQbar) # optional - sage.rings.number_field - sage: S. = PolynomialRing(R) # optional - sage.rings.number_field - sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 # optional - sage.rings.number_field - sage: f.parent() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PowerSeriesRing(QQbar) + sage: S. = PolynomialRing(R) + sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 + sage: f.parent() Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field - sage: f._derivative(x) # with respect to x # optional - sage.rings.number_field + sage: f._derivative(x) # with respect to x (2*t^2 + O(t^3))*x*y^3 + (111*t^4 + O(t^5))*x^2 - sage: f._derivative(x).parent() # optional - sage.rings.number_field + sage: f._derivative(x).parent() Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field - sage: f._derivative(y) # with respect to y # optional - sage.rings.number_field + sage: f._derivative(y) # with respect to y (3*t^2 + O(t^3))*x^2*y^2 - sage: f._derivative(t) # with respect to t (recurses into base ring) # optional - sage.rings.number_field + sage: f._derivative(t) # with respect to t (recurses into base ring) (2*t + O(t^2))*x^2*y^3 + (148*t^3 + O(t^4))*x^3 - sage: f._derivative(x)._derivative(y) # with respect to x and then y # optional - sage.rings.number_field + sage: f._derivative(x)._derivative(y) # with respect to x and then y (6*t^2 + O(t^3))*x*y^2 - sage: f.derivative(y, 3) # with respect to y three times # optional - sage.rings.number_field + sage: f.derivative(y, 3) # with respect to y three times (6*t^2 + O(t^3))*x^2 - sage: f._derivative() # can't figure out the variable # optional - sage.rings.number_field + sage: f._derivative() # can't figure out the variable Traceback (most recent call last): ... ValueError: must specify which variable to differentiate with respect to @@ -1927,26 +1964,26 @@ def integral(self, var=None): On polynomials with coefficients in power series:: - sage: R. = PowerSeriesRing(QQbar) # optional - sage.rings.number_field - sage: S. = PolynomialRing(R) # optional - sage.rings.number_field - sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 # optional - sage.rings.number_field - sage: f.parent() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PowerSeriesRing(QQbar) + sage: S. = PolynomialRing(R) + sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 + sage: f.parent() Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field - sage: f.integral(x) # with respect to x # optional - sage.rings.number_field + sage: f.integral(x) # with respect to x (1/3*t^2 + O(t^3))*x^3*y^3 + (37/4*t^4 + O(t^5))*x^4 - sage: f.integral(x).parent() # optional - sage.rings.number_field + sage: f.integral(x).parent() Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field - - sage: f.integral(y) # with respect to y # optional - sage.rings.number_field + sage: f.integral(y) # with respect to y (1/4*t^2 + O(t^3))*x^2*y^4 + (37*t^4 + O(t^5))*x^3*y - sage: f.integral(t) # with respect to t (recurses into base ring) # optional - sage.rings.number_field + sage: f.integral(t) # with respect to t (recurses into base ring) (1/3*t^3 + O(t^4))*x^2*y^3 + (37/5*t^5 + O(t^6))*x^3 TESTS:: - sage: f.integral() # can't figure out the variable # optional - sage.rings.number_field + sage: f.integral() # can't figure out the variable # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: must specify which variable to integrate with respect to @@ -2023,22 +2060,23 @@ def factor(self, proof=None): Check if we can factor a constant polynomial, see :trac:`8207`:: - sage: R. = CC[] - sage: R(1).factor() + sage: R. = CC[] # needs sage.rings.real_mpfr + sage: R(1).factor() # needs sage.rings.real_mpfr 1.00000000000000 Check that we prohibit too large moduli, :trac:`11829`:: - sage: R. = GF(previous_prime(2^31))[] - sage: factor(x+y+1) + sage: R. = GF(previous_prime(2^31))[] # needs sage.rings.finite_rings + sage: factor(x + y + 1) # needs sage.rings.finite_rings Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over prime fields with characteristic > 2^29 is not implemented. Check that we can factor over the algebraic field (:trac:`25390`):: - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: factor(x^2 + y^2) # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: factor(x^2 + y^2) # needs sage.rings.number_field (x + (-1*I)*y) * (x + 1*I*y) Check that the global proof flag for polynomials is honored:: @@ -2049,7 +2087,9 @@ def factor(self, proof=None): ....: f.factor() Traceback (most recent call last): ... - NotImplementedError: Provably correct factorization not implemented. Disable this error by wrapping your code in a `with proof.WithProof('polynomial', False):` block. + NotImplementedError: Provably correct factorization not implemented. + Disable this error by wrapping your code in a + `with proof.WithProof('polynomial', False):` block. sage: with proof.WithProof('polynomial', False): ....: f.factor() Traceback (most recent call last): @@ -2060,7 +2100,7 @@ def factor(self, proof=None): sage: K. = PolynomialRing(QQ) sage: R. = PolynomialRing(FractionField(K)) - sage: factor(x) + sage: factor(x) # needs sage.libs.pari x In the example below, we set the special method @@ -2074,26 +2114,29 @@ def factor(self, proof=None): ... NotImplementedError: ... sage: R.base_ring()._factor_multivariate_polynomial = lambda f, **kwargs: f.change_ring(QQ).factor() - sage: (x*y).factor() + sage: (x*y).factor() # needs sage.libs.pari y * x sage: del R.base_ring()._factor_multivariate_polynomial # clean up Check that a "multivariate" polynomial in one variable is factored correctly:: - sage: R. = PolynomialRing(CC,1) - sage: f = z^4 - 6*z + 3 - sage: f.factor() - (z - 1.60443920904349) * (z - 0.511399619393097) * (z + 1.05791941421830 - 1.59281852704435*I) * (z + 1.05791941421830 + 1.59281852704435*I) + sage: R. = PolynomialRing(CC,1) # needs sage.rings.real_mpfr + sage: f = z^4 - 6*z + 3 # needs sage.rings.real_mpfr + sage: f.factor() # needs sage.rings.real_mpfr + (z - 1.60443920904349) * (z - 0.511399619393097) + * (z + 1.05791941421830 - 1.59281852704435*I) + * (z + 1.05791941421830 + 1.59281852704435*I) We check a case that failed with an exception at some point:: - sage: k. = GF(4) # optional - sage.rings.finite_rings - sage: R. = k[] # optional - sage.rings.finite_rings - sage: l. = R.quo(v^3 + v + 1) # optional - sage.rings.finite_rings - sage: R. = l[] # optional - sage.rings.finite_rings - sage: f = y^3 + x^3 + (u + 1)*x # optional - sage.rings.finite_rings - sage: f.factor() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(4) + sage: R. = k[] + sage: l. = R.quo(v^3 + v + 1) + sage: R. = l[] + sage: f = y^3 + x^3 + (u + 1)*x + sage: f.factor() x^3 + y^3 + (u + 1)*x """ @@ -2159,24 +2202,25 @@ def lift(self,I): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: A. = PolynomialRing(CC, 2, order='degrevlex') sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7]) sage: f = x*y^13 + y^12 - sage: M = f.lift(I) - sage: M + sage: M = f.lift(I); M # needs sage.libs.singular [y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4] - sage: sum( map( mul , zip( M, I.gens() ) ) ) == f + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True TESTS: Check that this method works over ``QQbar`` (:trac:`25351`):: - sage: A. = QQbar[] # optional - sage.rings.number_field - sage: I = A.ideal([x^2 + y^2 - 1, x^2 - y^2]) # optional - sage.rings.number_field - sage: f = 2*x^2 - 1 # optional - sage.rings.number_field - sage: M = f.lift(I) # optional - sage.rings.number_field - sage: sum(map(mul, zip(M, I.gens()))) == f # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: A. = QQbar[] + sage: I = A.ideal([x^2 + y^2 - 1, x^2 - y^2]) + sage: f = 2*x^2 - 1 + sage: M = f.lift(I) # needs sage.libs.singular + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True """ fs = self._singular_() @@ -2196,19 +2240,19 @@ def quo_rem(self, right): EXAMPLES:: - sage: R. = CC[] - sage: f = y*x^2 + x + 1 - sage: f.quo_rem(x) + sage: R. = CC[] # needs sage.rings.real_mpfr + sage: f = y*x^2 + x + 1 # needs sage.rings.real_mpfr + sage: f.quo_rem(x) # needs sage.libs.singular sage.rings.real_mpfr (x*y + 1.00000000000000, 1.00000000000000) sage: R = QQ['a','b']['x','y','z'] sage: p1 = R('a + (1+2*b)*x*y + (3-a^2)*z') sage: p2 = R('x-1') - sage: p1.quo_rem(p2) + sage: p1.quo_rem(p2) # needs sage.libs.singular ((2*b + 1)*y, (2*b + 1)*y + (-a^2 + 3)*z + a) - sage: R. = Qp(5)[] - sage: x.quo_rem(y) + sage: R. = Qp(5)[] # needs sage.rings.padics + sage: x.quo_rem(y) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: no conversion of this ring to a Singular ring defined @@ -2219,9 +2263,9 @@ def quo_rem(self, right): Check that this method works over ``QQbar`` (:trac:`25351`):: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = y*x^2 + x + 1 # optional - sage.rings.number_field - sage: f.quo_rem(x) # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: f = y*x^2 + x + 1 # needs sage.rings.number_field + sage: f.quo_rem(x) # needs sage.rings.number_field (x*y + 1, 1) """ R = self.parent() @@ -2263,9 +2307,9 @@ def resultant(self, other, variable=None): sage: P. = PolynomialRing(QQ, 2) sage: a = x + y sage: b = x^3 - y^3 - sage: a.resultant(b) # optional - sage.libs.singular + sage: a.resultant(b) # needs sage.libs.singular -2*y^3 - sage: a.resultant(b, y) # optional - sage.libs.singular + sage: a.resultant(b, y) # needs sage.libs.singular 2*x^3 TESTS:: @@ -2274,15 +2318,15 @@ def resultant(self, other, variable=None): sage: P. = MPolynomialRing_polydict_domain(QQ, 2, order='degrevlex') sage: a = x + y sage: b = x^3 - y^3 - sage: a.resultant(b) # optional - sage.libs.singular + sage: a.resultant(b) # needs sage.libs.singular -2*y^3 - sage: a.resultant(b, y) # optional - sage.libs.singular + sage: a.resultant(b, y) # needs sage.libs.singular 2*x^3 Check that :trac:`15061` is fixed:: - sage: R. = AA[] # optional - sage.rings.number_field - sage: (x^2 + 1).resultant(x^2 - y) # optional - sage.rings.number_field + sage: R. = AA[] # needs sage.rings.number_field + sage: (x^2 + 1).resultant(x^2 - y) # needs sage.rings.number_field y^2 + 2*y + 1 Test for :trac:`2693`:: @@ -2290,17 +2334,18 @@ def resultant(self, other, variable=None): sage: R. = RR[] sage: p = x + y sage: q = x*y - sage: p.resultant(q) # optional - sage.libs.singular + sage: p.resultant(q) # needs sage.modules -y^2 Check that this method works over QQbar (:trac:`25351`):: - sage: P. = QQbar[] # optional - sage.rings.number_field - sage: a = x + y # optional - sage.rings.number_field - sage: b = x^3 - y^3 # optional - sage.rings.number_field - sage: a.resultant(b) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = QQbar[] + sage: a = x + y + sage: b = x^3 - y^3 + sage: a.resultant(b) (-2)*y^3 - sage: a.resultant(b, y) # optional - sage.rings.number_field + sage: a.resultant(b, y) 2*x^3 """ R = self.parent() @@ -2330,13 +2375,14 @@ def subresultants(self, other, variable=None): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: p = (y^2 + 6)*(x - 1) - y*(x^2 + 1) # optional - sage.rings.number_field - sage: q = (x^2 + 6)*(y - 1) - x*(y^2 + 1) # optional - sage.rings.number_field - sage: p.subresultants(q, y) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: p = (y^2 + 6)*(x - 1) - y*(x^2 + 1) + sage: q = (x^2 + 6)*(y - 1) - x*(y^2 + 1) + sage: p.subresultants(q, y) [2*x^6 + (-22)*x^5 + 102*x^4 + (-274)*x^3 + 488*x^2 + (-552)*x + 288, -x^3 - x^2*y + 6*x^2 + 5*x*y + (-11)*x + (-6)*y + 6] - sage: p.subresultants(q, x) # optional - sage.rings.number_field + sage: p.subresultants(q, x) [2*y^6 + (-22)*y^5 + 102*y^4 + (-274)*y^3 + 488*y^2 + (-552)*y + 288, x*y^2 + y^3 + (-5)*x*y + (-6)*y^2 + 6*x + 11*y - 6] @@ -2360,48 +2406,50 @@ def reduce(self, I): EXAMPLES:: - sage: P. = QQbar[] # optional - sage.rings.number_field - sage: f1 = -2 * x^2 + x^3 # optional - sage.rings.number_field - sage: f2 = -2 * y + x * y # optional - sage.rings.number_field - sage: f3 = -x^2 + y^2 # optional - sage.rings.number_field - sage: F = Ideal([f1, f2, f3]) # optional - sage.rings.number_field - sage: g = x*y - 3*x*y^2 # optional - sage.rings.number_field - sage: g.reduce(F) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = QQbar[] + sage: f1 = -2 * x^2 + x^3 + sage: f2 = -2 * y + x * y + sage: f3 = -x^2 + y^2 + sage: F = Ideal([f1, f2, f3]) + sage: g = x*y - 3*x*y^2 + sage: g.reduce(F) (-6)*y^2 + 2*y - sage: g.reduce(F.gens()) # optional - sage.rings.number_field + sage: g.reduce(F.gens()) (-6)*y^2 + 2*y :: - sage: f = 3*x # optional - sage.rings.number_field - sage: f.reduce([2*x, y]) # optional - sage.rings.number_field + sage: f = 3*x # needs sage.rings.number_field + sage: f.reduce([2*x, y]) # needs sage.rings.number_field 0 :: - sage: k. = CyclotomicField(3) # optional - sage.rings.number_field - sage: A. = PolynomialRing(k) # optional - sage.rings.number_field - sage: J = [y9 + y12] # optional - sage.rings.number_field - sage: f = y9 - y12; f.reduce(J) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: k. = CyclotomicField(3) + sage: A. = PolynomialRing(k) + sage: J = [y9 + y12] + sage: f = y9 - y12; f.reduce(J) -2*y12 - sage: f = y13*y15; f.reduce(J) # optional - sage.rings.number_field + sage: f = y13*y15; f.reduce(J) y13*y15 - sage: f = y13*y15 + y9 - y12; f.reduce(J) # optional - sage.rings.number_field + sage: f = y13*y15 + y9 - y12; f.reduce(J) y13*y15 - 2*y12 Make sure the remainder returns the correct type, fixing :trac:`13903`:: - sage: R. = PolynomialRing(Qp(5), 2, order='lex') # optional - sage.rings.padics - sage: G = [y1^2 + y2^2, y1*y2 + y2^2, y2^3] # optional - sage.rings.padics - sage: type((y2^3).reduce(G)) # optional - sage.rings.padics + sage: R. = PolynomialRing(Qp(5), 2, order='lex') # needs sage.rings.padics + sage: G = [y1^2 + y2^2, y1*y2 + y2^2, y2^3] # needs sage.rings.padics + sage: type((y2^3).reduce(G)) # needs sage.rings.padics TESTS: Verify that :trac:`34105` is fixed:: - sage: R. = AA[] # optional - sage.rings.number_field - sage: x.reduce(R.zero_ideal()) # optional - sage.rings.number_field + sage: R. = AA[] # needs sage.rings.number_field + sage: x.reduce(R.zero_ideal()) # needs sage.rings.number_field x """ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal @@ -2465,11 +2513,11 @@ def degree_lowest_rational_function(r, x): EXAMPLES:: - sage: R1 = PolynomialRing(FiniteField(5), 3, names=["a", "b", "c"]) # optional - sage.rings.finite_rings - sage: F = FractionField(R1) # optional - sage.rings.finite_rings - sage: a,b,c = R1.gens() # optional - sage.rings.finite_rings - sage: f = 3*a*b^2*c^3 + 4*a*b*c # optional - sage.rings.finite_rings - sage: g = a^2*b*c^2 + 2*a^2*b^4*c^7 # optional - sage.rings.finite_rings + sage: R1 = PolynomialRing(FiniteField(5), 3, names=["a", "b", "c"]) + sage: F = FractionField(R1) + sage: a,b,c = R1.gens() + sage: f = 3*a*b^2*c^3 + 4*a*b*c + sage: g = a^2*b*c^2 + 2*a^2*b^4*c^7 Consider the quotient `f/g = \frac{4 + 3 bc^{2}}{ac + 2 ab^{3}c^{6}}` (note the @@ -2477,13 +2525,14 @@ def degree_lowest_rational_function(r, x): :: - sage: r = f/g; r # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: r = f/g; r (-2*b*c^2 - 1)/(2*a*b^3*c^6 + a*c) - sage: degree_lowest_rational_function(r, a) # optional - sage.rings.finite_rings + sage: degree_lowest_rational_function(r, a) -1 - sage: degree_lowest_rational_function(r, b) # optional - sage.rings.finite_rings + sage: degree_lowest_rational_function(r, b) 0 - sage: degree_lowest_rational_function(r, c) # optional - sage.rings.finite_rings + sage: degree_lowest_rational_function(r, c) -1 """ from sage.rings.fraction_field import FractionField diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index c9753055fc7..22ada6de947 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.singular +# sage.doctest: needs sage.libs.singular r""" Ideals in multivariate polynomial rings @@ -234,36 +234,40 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from warnings import warn -from sage.interfaces.singular import singular as singular_default -from sage.interfaces.magma import magma as magma_default - -from sage.interfaces.expect import StdOutContext +import sage.rings.abc +import sage.rings.polynomial.toy_buchberger as toy_buchberger +import sage.rings.polynomial.toy_variety as toy_variety +import sage.rings.polynomial.toy_d_basis as toy_d_basis +from sage.misc.cachefunc import cached_method +from sage.misc.method_decorator import MethodDecorator +from sage.misc.misc_c import prod +from sage.misc.verbose import verbose, get_verbose from sage.rings.ideal import Ideal_generic -from sage.rings.noncommutative_ideals import Ideal_nc from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.noncommutative_ideals import Ideal_nc +from sage.rings.qqbar_decorators import handle_AA_and_QQbar from sage.structure.sequence import Sequence from sage.structure.richcmp import (richcmp_method, op_EQ, op_NE, op_LT, op_GT, op_LE, op_GE, rich_to_bool) -from sage.misc.cachefunc import cached_method -from sage.misc.misc_c import prod -from sage.misc.verbose import verbose, get_verbose -from sage.misc.method_decorator import MethodDecorator - -from sage.rings.integer_ring import ZZ -import sage.rings.abc -import sage.rings.polynomial.toy_buchberger as toy_buchberger -import sage.rings.polynomial.toy_variety as toy_variety -import sage.rings.polynomial.toy_d_basis as toy_d_basis -from warnings import warn -from sage.rings.qqbar_decorators import handle_AA_and_QQbar +try: + from sage.interfaces.expect import StdOutContext + from sage.interfaces.singular import singular as singular_default, singular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options +except ImportError: + singular_default = None + singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator -from sage.interfaces.magma import magma_gb_standard_options -from sage.interfaces.singular import singular_gb_standard_options -from sage.libs.singular.standard_options import libsingular_gb_standard_options +try: + from sage.interfaces.magma import magma as magma_default, magma_gb_standard_options +except ImportError: + magma_default = None + magma_gb_standard_options = MethodDecorator class RequireField(MethodDecorator): @@ -343,9 +347,10 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: R. = PolynomialRing(GF(127),10) # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Cyclic(R,4) # indirect doctest # needs sage.rings.finite_rings - sage: magma(I) # optional - magma # needs sage.rings.finite_rings + sage: # optional - magma + sage: R. = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R,4) # indirect doctest + sage: magma(I) Ideal of Polynomial ring of rank 10 over GF(127) Order: Graded Reverse Lexicographical Variables: a, b, c, d, e, f, g, h, i, j @@ -380,27 +385,27 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) EXAMPLES:: - sage: # needs sage.rings.finite_rings + sage: # optional - magma sage: R. = PolynomialRing(GF(127), 10) sage: I = sage.rings.ideal.Cyclic(R, 6) - sage: gb = I.groebner_basis('magma:GroebnerBasis') # optional - magma - sage: len(gb) # optional - magma + sage: gb = I.groebner_basis('magma:GroebnerBasis') + sage: len(gb) 45 We may also pass a degree bound to Magma:: - sage: # needs sage.rings.finite_rings + sage: # optional - magma sage: R. = PolynomialRing(GF(127), 10) sage: I = sage.rings.ideal.Cyclic(R, 6) - sage: gb = I.groebner_basis('magma:GroebnerBasis', deg_bound=4) # optional - magma - sage: len(gb) # optional - magma + sage: gb = I.groebner_basis('magma:GroebnerBasis', deg_bound=4) + sage: len(gb) 5 """ R = self.ring() if not deg_bound: mself = magma(self) else: - mself = magma(list(self.gens())) # PolynomialSequence converts to a Magma Ideal too, so we force a list + mself = magma(list(self.gens())) # PolynomialSequence converts to a Magma Ideal too, so we force a list if get_verbose() >= 2: prot = True @@ -1122,13 +1127,13 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): I = MPolynomialIdeal(P, self.interreduced_basis()[::-1]) else: I = self - I = MPolynomialIdeal(P, I.transformed_basis('fglm')[::-1]) # -> 'lex' - I = I.change_ring(Q) # transform to 'lex' GB + I = MPolynomialIdeal(P, I.transformed_basis('fglm')[::-1]) # -> 'lex' + I = I.change_ring(Q) # transform to 'lex' GB else: if Q == P: I = MPolynomialIdeal(P, self.groebner_basis()[::-1]) else: - I = self.change_ring(Q) # transform to 'lex' GB + I = self.change_ring(Q) # transform to 'lex' GB I = MPolynomialIdeal(Q, I.groebner_basis()[::-1]) if I.dimension() != 0: @@ -1350,14 +1355,14 @@ def _groebner_basis_ginv(self, algorithm="TQ", criteria='CritPartially', divisio Currently, only `\GF{p}` and `\QQ` are supported as base fields:: - sage: P. = PolynomialRing(QQ,order='degrevlex') + sage: # optional - ginv + sage: P. = PolynomialRing(QQ, order='degrevlex') sage: I = sage.rings.ideal.Katsura(P) - sage: I.groebner_basis(algorithm='ginv') # optional - ginv + sage: I.groebner_basis(algorithm='ginv') [z^3 - 79/210*z^2 + 1/30*y + 1/70*z, y^2 - 3/5*z^2 - 1/5*y + 1/5*z, y*z + 6/5*z^2 - 1/10*y - 2/5*z, x + 2*y + 2*z - 1] - - sage: P. = PolynomialRing(GF(127), order='degrevlex') # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # needs sage.rings.finite_rings - sage: I.groebner_basis(algorithm='ginv') # optional - ginv # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127), order='degrevlex') + sage: I = sage.rings.ideal.Katsura(P) + sage: I.groebner_basis(algorithm='ginv') ... [z^3 + 22*z^2 - 55*y + 49*z, y^2 - 26*z^2 - 51*y + 51*z, y*z + 52*z^2 + 38*y + 25*z, x + 2*y + 2*z - 1] @@ -1489,7 +1494,7 @@ def _groebner_basis_singular_raw(self, algorithm="groebner", singular=singular_d sage: R. = PolynomialRing(QQ, 4, order='lex') sage: I = sage.rings.ideal.Cyclic(R,4) - sage: I._groebner_basis_singular() # indirect doctest + sage: I._groebner_basis_singular() # indirect doctest [c^2*d^6 - c^2*d^2 - d^4 + 1, c^3*d^2 + c^2*d^3 - c - d, b*d^4 - b + d^5 - d, b*c - b*d + c^2*d^4 + c*d - 2*d^2, b^2 + 2*b*d + d^2, a + b + c + d] @@ -1974,8 +1979,8 @@ def interreduced_basis(self): The interreduced basis of 0 is 0:: - sage: P. = GF(2)[] # needs sage.rings.finite_rings - sage: Ideal(P(0)).interreduced_basis() # needs sage.rings.finite_rings + sage: P. = GF(2)[] + sage: Ideal(P(0)).interreduced_basis() [0] ALGORITHM: @@ -2460,7 +2465,11 @@ def saturation(self, other): (Ideal (y, x^5) of Multivariate Polynomial Ring in x, y, z over Algebraic Field, 4) """ from sage.libs.singular.function_factory import ff - sat = ff.elim__lib.sat + # function renamed in singular > 4.3.2p4, see issue #35980 + try: + sat = ff.elim__lib.sat_with_exp + except NameError: + sat = ff.elim__lib.sat R = self.ring() ideal, expo = sat(self, other) return (R.ideal(ideal), ZZ(expo)) @@ -2518,8 +2527,6 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True y^48 + y^41 - y^40 + y^37 - y^36 - y^33 + y^32 - y^29 + y^28 - y^25 + y^24 + y^2 + y + 1) of Multivariate Polynomial Ring in x, y over Finite Field in w of size 3^3 - - sage: # needs sage.rings.finite_rings sage: V = I.variety(); sage: sorted(V, key=str) [{y: w^2 + 2*w, x: 2*w + 2}, {y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}] @@ -2602,9 +2609,10 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True If the ground field's characteristic is too large for Singular, we resort to a toy implementation:: - sage: R. = PolynomialRing(GF(2147483659^3), order='lex') # needs sage.rings.finite_rings - sage: I = ideal([x^3 - 2*y^2, 3*x + y^4]) # needs sage.rings.finite_rings - sage: I.variety() # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(2147483659^3), order='lex') + sage: I = ideal([x^3 - 2*y^2, 3*x + y^4]) + sage: I.variety() verbose 0 (...: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. verbose 0 (...: multi_polynomial_ideal.py, variety) Warning: falling back to very slow toy implementation. @@ -2615,22 +2623,23 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True But the mapping will also accept generators of the original ring, or even generator names as strings, when provided as keys:: + sage: # needs sage.rings.number_field sage: K. = QQ[] sage: I = ideal([x^2 + 2*y - 5, x + y + 3]) - sage: v = I.variety(AA)[0]; v[x], v[y] # needs sage.rings.number_field + sage: v = I.variety(AA)[0]; v[x], v[y] (4.464101615137755?, -7.464101615137755?) - sage: list(v)[0].parent() # needs sage.rings.number_field + sage: list(v)[0].parent() Multivariate Polynomial Ring in x, y over Algebraic Real Field - sage: v[x] # needs sage.rings.number_field + sage: v[x] 4.464101615137755? - sage: v["y"] # needs sage.rings.number_field + sage: v["y"] -7.464101615137755? ``msolve`` also works over finite fields:: sage: R. = PolynomialRing(GF(536870909), 2, order='lex') # needs sage.rings.finite_rings sage: I = Ideal([x^2 - 1, y^2 - 1]) # needs sage.rings.finite_rings - sage: sorted(I.variety(algorithm='msolve', # optional - msolve # needs sage.rings.finite_rings + sage: sorted(I.variety(algorithm='msolve', # optional - msolve, needs sage.rings.finite_rings ....: proof=False), ....: key=str) [{x: 1, y: 1}, @@ -2641,9 +2650,9 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True but may fail in small characteristic, especially with ideals of high degree with respect to the characteristic:: - sage: R. = PolynomialRing(GF(3), 2, order='lex') # needs sage.rings.finite_rings - sage: I = Ideal([x^2 - 1, y^2 - 1]) # needs sage.rings.finite_rings - sage: I.variety(algorithm='msolve', proof=False) # optional - msolve, needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(3), 2, order='lex') + sage: I = Ideal([x^2 - 1, y^2 - 1]) + sage: I.variety(algorithm='msolve', proof=False) # optional - msolve Traceback (most recent call last): ... NotImplementedError: characteristic 3 too small @@ -2690,8 +2699,8 @@ def _variety_triangular_decomposition(self, ring): Testing that a bug is indeed fixed :: - sage: R = PolynomialRing(GF(2), 30, ['x%d'%(i+1) for i in range(30)], order='lex') # needs sage.rings.finite_rings - sage: R.inject_variables() # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2), 30, ['x%d'%(i+1) for i in range(30)], order='lex') + sage: R.inject_variables() Defining... sage: I = Ideal([x1 + 1, x2, x3 + 1, x5*x10 + x10 + x18, x5*x11 + x11, \ x5*x18, x6, x7 + 1, x9, x10*x11 + x10 + x18, x10*x18 + x18, \ @@ -2702,10 +2711,10 @@ def _variety_triangular_decomposition(self, ring): x11^2 + x11, x12^2 + x12, x13^2 + x13, x14^2 + x14, x15^2 + x15, \ x16^2 + x16, x17^2 + x17, x18^2 + x18, x19^2 + x19, x20^2 + x20, \ x21^2 + x21, x22^2 + x22, x23^2 + x23, x24^2 + x24, x25^2 + x25, \ - x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) # optional - sage.rings.finite_rings - sage: I.basis_is_groebner() # needs sage.rings.finite_rings + x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) + sage: I.basis_is_groebner() True - sage: sorted("".join(str(V[g]) for g in R.gens()) for V in I.variety()) # long time (6s on sage.math, 2011), needs sage.rings.finite_rings + sage: sorted("".join(str(V[g]) for g in R.gens()) for V in I.variety()) # long time (6s on sage.math, 2011) ['101000100000000110001000100110', '101000100000000110001000101110', '101000100100000101001000100110', @@ -2740,10 +2749,10 @@ def _variety_triangular_decomposition(self, ring): Check that the issue at :trac:`7425` is fixed:: - sage: S.=PolynomialRing(QQ) - sage: F.=QQ.extension(t^4+1) - sage: R.=PolynomialRing(F) - sage: I=R.ideal(x,y^4+1) + sage: S. = PolynomialRing(QQ) + sage: F. = QQ.extension(t^4 + 1) + sage: R. = PolynomialRing(F) + sage: I = R.ideal(x, y^4 + 1) sage: I.variety() [...{y: -q^3, x: 0}...] @@ -2757,7 +2766,7 @@ def _variety_triangular_decomposition(self, ring): Check that the issue at :trac:`16485` is fixed:: sage: R. = PolynomialRing(QQ, order='lex') - sage: I = R.ideal(c^2-2, b-c, a) + sage: I = R.ideal(c^2 - 2, b - c, a) sage: I.variety(QQbar) # needs sage.rings.number_field [...a: 0...] @@ -3200,7 +3209,7 @@ def _normal_basis_libsingular(self, degree, weights=None): sage: R. = PolynomialRing(QQ) sage: I = R.ideal(x^2-2*x*z+5, x*y^2+y*z+1, 3*y^2-8*x*z) - sage: I.normal_basis() #indirect doctest + sage: I.normal_basis() # indirect doctest [z^2, y*z, x*z, z, x*y, y, x, 1] sage: J = R.ideal(x^2-2*x*z+5) sage: J.normal_basis(3) # indirect doctest @@ -3515,7 +3524,7 @@ def __call_singular(self, cmd, arg=None): sage: H.inject_variables() Defining x, y, z sage: id = H.ideal(x + y, y + z) - sage: id.std() # indirect doctest # random + sage: id.std() # indirect doctest # random Left Ideal (z, y, x) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} sage: sorted(id.std().gens(), key=str) @@ -3856,8 +3865,8 @@ def __init__(self, ring, gens, coerce=True): sage: R. = PolynomialRing(IntegerRing(), 2, order='lex') sage: R.ideal([x, y]) Ideal (x, y) of Multivariate Polynomial Ring in x, y over Integer Ring - sage: R. = GF(3)[] # needs sage.rings.finite_rings - sage: R.ideal([x0^2, x1^3]) # needs sage.rings.finite_rings + sage: R. = GF(3)[] + sage: R.ideal([x0^2, x1^3]) Ideal (x0^2, x1^3) of Multivariate Polynomial Ring in x0, x1 over Finite Field of size 3 """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) @@ -4293,37 +4302,37 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal :: sage: P. = PolynomialRing(QQ,3, order='lex') - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis() [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:groebner') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:std') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdhilb') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdfglm') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:slimgb') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] @@ -4331,14 +4340,14 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal reverse lexicographical ordering here, in order to test against :trac:`21884`:: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: J = I.change_ring(P.change_ring(order='degrevlex')) - sage: gb = J.groebner_basis('giac') # random + sage: gb = J.groebner_basis('giac') # random sage: gb [c^3 - 79/210*c^2 + 1/30*b + 1/70*c, b^2 - 3/5*c^2 - 1/5*b + 1/5*c, b*c + 6/5*c^2 - 1/10*b - 2/5*c, a + 2*b + 2*c - 1] sage: J.groebner_basis.set_cache(gb) - sage: ideal(J.transformed_basis()).change_ring(P).interreduced_basis() # testing trac 21884 + sage: ideal(J.transformed_basis()).change_ring(P).interreduced_basis() # testing issue #21884 ...[a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] Giac's gbasis over `\QQ` can benefit from a probabilistic lifting and @@ -4346,7 +4355,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: A9 = PolynomialRing(QQ, 9, 'x') sage: I9 = sage.rings.ideal.Katsura(A9) - sage: print("possible output from giac", flush=True); I9.groebner_basis("giac", proba_epsilon=1e-7) # long time (3s) + sage: print("possible output from giac", flush=True); I9.groebner_basis("giac", proba_epsilon=1e-7) # long time (3s) possible output... Polynomial Sequence with 143 Polynomials in 9 Variables @@ -4355,7 +4364,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Note that ``toy:buchberger`` does not return the reduced Groebner basis, :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: gb = I.groebner_basis('toy:buchberger') sage: gb.is_groebner() True @@ -4364,7 +4373,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal but that ``toy:buchberger2`` does. :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: gb = I.groebner_basis('toy:buchberger2'); gb [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] sage: gb == gb.reduced() @@ -4373,32 +4382,36 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Here we use Macaulay2 with three different strategies over a finite field. :: - sage: R. = PolynomialRing(GF(101), 3) # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 # needs sage.rings.finite_rings - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('macaulay2:f4') # optional - macaulay2 # needs sage.rings.finite_rings - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('macaulay2:mgb') # optional - macaulay2 # needs sage.rings.finite_rings - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: # optional - macaulay2 + sage: R. = PolynomialRing(GF(101), 3) + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:gb') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:f4') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:mgb') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] Over prime fields of small characteristic, we can also use the `optional package msolve <../spkg/msolve.html>`_:: - sage: R. = PolynomialRing(GF(101), 3) # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('msolve') # optional - msolve # needs sage.rings.finite_rings - [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] + sage: R. = PolynomialRing(GF(101), 3) + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve + [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, + b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma, needs sage.rings.finite_rings - [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma + [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, + b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] Singular and libSingular can compute Groebner basis with degree restrictions. :: @@ -4459,7 +4472,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal :: - sage: I.groebner_basis('macaulay2') # optional - macaulay2 + sage: I.groebner_basis('macaulay2') # optional - macaulay2 [b^3 + b*c^2 + 12*c^3 + b^2 + b*c - 4*c^2, 2*b*c^2 - 6*c^3 + b^2 + 5*b*c + 8*c^2 - b - 2*c, 42*c^3 + b^2 + 2*b*c - 14*c^2 + b, @@ -4468,7 +4481,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Groebner bases over `\ZZ/n\ZZ` are also supported:: - sage: P. = PolynomialRing(Zmod(1000),3) + sage: P. = PolynomialRing(Zmod(1000), 3) sage: I = P * (a + 2*b + 2*c - 1, a^2 - a + 2*b^2 + 2*c^2, 2*a*b + 2*b*c - b) sage: I.groebner_basis() [b*c^2 + 732*b*c + 808*b, @@ -4501,11 +4514,11 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I = P * ( x*y*z + z^5, 2*x^2 + y^3 + z^7, 3*z^5 + y^5 ) sage: J = Ideal(I.groebner_basis()) sage: f = sum(P.random_element(terms=2)*f for f in I.gens()) - sage: f # random + sage: f # random 1/2*y^2*z^7 - 1/4*y*z^8 + 2*x*z^5 + 95*z^6 + 1/2*y^5 - 1/4*y^4*z + x^2*y^2 + 3/2*x^2*y*z + 95*x*y*z^2 - sage: f.lift(I.gens()) # random + sage: f.lift(I.gens()) # random [2*x + 95*z, 1/2*y^2 - 1/4*y*z, 0] - sage: l = f.lift(J.gens()); l # random + sage: l = f.lift(J.gens()); l # random [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1/2*y^2 + 1/4*y*z, 1/2*y^2*z^2 - 1/4*y*z^3 + 2*x + 95*z] sage: sum(map(mul, zip(l,J.gens()))) == f True @@ -4570,55 +4583,50 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Check that this method works over QQbar (:trac:`25351`):: - sage: P. = PolynomialRing(QQbar, 3, order='lex') # needs sage.rings.number_field - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis() # needs sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='lex') + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis() [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('libsingular:groebner') # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('libsingular:groebner') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('libsingular:std') # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('libsingular:std') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('libsingular:stdhilb') # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('libsingular:stdhilb') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('libsingular:stdfglm') # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('libsingular:stdfglm') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('libsingular:slimgb') # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('libsingular:slimgb') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] sage: # needs sage.rings.number_field - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: J = I.change_ring(P.change_ring(order='degrevlex')) - sage: gb = J.groebner_basis('giac') # random + sage: gb = J.groebner_basis('giac') # random sage: gb [c^3 + (-79/210)*c^2 + 1/30*b + 1/70*c, b^2 + (-3/5)*c^2 + (-1/5)*b + 1/5*c, b*c + 6/5*c^2 + (-1/10)*b + (-2/5)*c, a + 2*b + 2*c - 1] - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('toy:buchberger2') # needs sage.rings.number_field + sage: # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('toy:buchberger2') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching # needs sage.rings.number_field - sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma, needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] msolve currently supports the degrevlex order only:: - sage: R. = PolynomialRing(GF(101), 3, order='lex') # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching # needs sage.rings.finite_rings - sage: I.groebner_basis('msolve') # optional - msolve # needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(101), 3, order='lex') + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve Traceback (most recent call last): ... NotImplementedError: msolve only supports the degrevlex order (use transformed_basis()) @@ -4642,10 +4650,10 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal if not algorithm: try: gb = self._groebner_basis_libsingular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError): # conversion to Singular not supported + except (TypeError, NameError, ImportError): # conversion to Singular not supported try: gb = self._groebner_basis_singular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError, NotImplementedError): # conversion to Singular not supported + except (TypeError, NameError, NotImplementedError, ImportError): # conversion to Singular not supported R = self.ring() B = R.base_ring() if R.ngens() == 0: @@ -4750,18 +4758,22 @@ def groebner_cover(self): sage: R. = F[] sage: I = R.ideal([-x+3*y+z-5,2*x+a*z+4,4*x-3*z-1/a]) sage: I.groebner_cover() - {Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - 0 - and Y is defined by: - 2*a^2 + 3*a: [(2*a^2 + 3*a)*z + (8*a + 1), (12*a^2 + 18*a)*y + (-20*a^2 - 35*a - 2), (4*a + 6)*x + 11], - Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - ... - and Y is defined by: - 1: [1], - Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - ... - and Y is defined by: - 1: [1]} + {Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + 0 + and Y is defined by: + 2*a^2 + 3*a: [(2*a^2 + 3*a)*z + (8*a + 1), + (12*a^2 + 18*a)*y + (-20*a^2 - 35*a - 2), (4*a + 6)*x + 11], + Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + ... + and Y is defined by: + 1: [1], + Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + ... + and Y is defined by: + 1: [1]} """ from sage.schemes.affine.affine_space import AffineSpace gc = self._groebner_cover() @@ -4872,9 +4884,9 @@ def subs(self, in_dict=None, **kwds): sage: T. = PolynomialRing(QQ) sage: I.subs(a=t, b=t) Principal ideal (t^2 + 1) of Univariate Polynomial Ring in t over Rational Field - sage: var("z") + sage: var("z") # needs sage.symbolic z - sage: I.subs(a=z, b=z) + sage: I.subs(a=z, b=z) # needs sage.symbolic Principal ideal (2*z^2 + 2) of Symbolic Ring Variables that are not substituted remain unchanged:: @@ -4943,7 +4955,7 @@ def _contains_(self, f): sage: R. = QQ[] sage: I = (x^3 + y, y) * R - sage: x in I # indirect doctest + sage: x in I # indirect doctest False sage: y in I True @@ -4971,28 +4983,28 @@ def homogenize(self, var='h'): EXAMPLES:: - sage: P. = PolynomialRing(GF(2)) # needs sage.rings.finite_rings - sage: I = Ideal([x^2*y + z + 1, x + y^2 + 1]); I # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(2)) + sage: I = Ideal([x^2*y + z + 1, x + y^2 + 1]); I Ideal (x^2*y + z + 1, y^2 + x + 1) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 :: - sage: I.homogenize() # needs sage.rings.finite_rings + sage: I.homogenize() Ideal (x^2*y + z*h^2 + h^3, y^2 + x*h + h^2) of Multivariate Polynomial Ring in x, y, z, h over Finite Field of size 2 :: - sage: I.homogenize(y) # needs sage.rings.finite_rings + sage: I.homogenize(y) Ideal (x^2*y + y^3 + y^2*z, x*y) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 :: - sage: I = Ideal([x^2*y + z^3 + y^2*x, x + y^2 + 1]) # needs sage.rings.finite_rings - sage: I.homogenize() # needs sage.rings.finite_rings + sage: I = Ideal([x^2*y + z^3 + y^2*x, x + y^2 + 1]) + sage: I.homogenize() Ideal (x^2*y + x*y^2 + z^3, y^2 + x*h + h^2) of Multivariate Polynomial Ring in x, y, z, h over Finite Field of size 2 @@ -5068,51 +5080,51 @@ def degree_of_semi_regularity(self): We consider a homogeneous example:: sage: n = 8 - sage: K = GF(127) # needs sage.rings.finite_rings - sage: P = PolynomialRing(K, n, 'x') # needs sage.rings.finite_rings - sage: s = [K.random_element() for _ in range(n)] # needs sage.rings.finite_rings - sage: L = [] # needs sage.rings.finite_rings - sage: for i in range(2 * n): # needs sage.rings.finite_rings + sage: K = GF(127) + sage: P = PolynomialRing(K, n, 'x') + sage: s = [K.random_element() for _ in range(n)] + sage: L = [] + sage: for i in range(2 * n): ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) - sage: I = Ideal(L) # needs sage.rings.finite_rings - sage: I.degree_of_semi_regularity() # needs sage.rings.finite_rings + sage: I = Ideal(L) + sage: I.degree_of_semi_regularity() 4 From this, we expect a Groebner basis computation to reach at most degree 4. For homogeneous systems this is equivalent to the largest degree in the Groebner basis:: - sage: max(f.degree() for f in I.groebner_basis()) # needs sage.rings.finite_rings + sage: max(f.degree() for f in I.groebner_basis()) 4 We increase the number of polynomials and observe a decrease the degree of regularity:: - sage: for i in range(2 * n): # needs sage.rings.finite_rings + sage: for i in range(2 * n): ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) - sage: I = Ideal(L) # needs sage.rings.finite_rings - sage: I.degree_of_semi_regularity() # needs sage.rings.finite_rings + sage: I = Ideal(L) + sage: I.degree_of_semi_regularity() 3 - sage: max(f.degree() for f in I.groebner_basis()) # needs sage.rings.finite_rings + sage: max(f.degree() for f in I.groebner_basis()) 3 The degree of regularity approaches 2 for quadratic systems as the number of polynomials approaches `n^2`:: - sage: for i in range((n-4) * n): # needs sage.rings.finite_rings + sage: for i in range((n-4) * n): ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) - sage: I = Ideal(L) # needs sage.rings.finite_rings - sage: I.degree_of_semi_regularity() # needs sage.rings.finite_rings + sage: I = Ideal(L) + sage: I.degree_of_semi_regularity() 2 - sage: max(f.degree() for f in I.groebner_basis()) # needs sage.rings.finite_rings + sage: max(f.degree() for f in I.groebner_basis()) 2 .. NOTE:: @@ -5122,7 +5134,7 @@ def degree_of_semi_regularity(self): semi-regular sequences. For more details about semi-regular sequences see [BFS2004]_. """ - degs = [f.degree() for f in self.gens() if f!=0] # we ignore zeroes + degs = [f.degree() for f in self.gens() if f!=0] # we ignore zeroes m, n = self.ngens(), len(set(sum([f.variables() for f in self.gens()],()))) if m <= n: raise ValueError("This function requires an overdefined system of polynomials.") @@ -5278,7 +5290,6 @@ def random_element(self, degree, compute_gb=False, *args, **kwds): We compute a uniformly random element up to the provided degree. :: - sage: # needs sage.rings.finite_rings sage: P. = GF(127)[] sage: I = sage.rings.ideal.Katsura(P) sage: f = I.random_element(degree=4, compute_gb=True, terms=infinity) @@ -5292,26 +5303,26 @@ def random_element(self, degree, compute_gb=False, *args, **kwds): basis if we can sample uniformly at random from an ideal:: sage: n = 3; d = 4 - sage: P = PolynomialRing(GF(127), n, 'x') # needs sage.rings.finite_rings - sage: I = sage.rings.ideal.Cyclic(P) # needs sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), n, 'x') + sage: I = sage.rings.ideal.Cyclic(P) 1. We sample `n^d` uniformly random elements in the ideal:: - sage: F = Sequence(I.random_element(degree=d, compute_gb=True, # needs sage.rings.finite_rings + sage: F = Sequence(I.random_element(degree=d, compute_gb=True, ....: terms=infinity) ....: for _ in range(n^d)) 2. We linearize and compute the echelon form:: - sage: A, v = F.coefficient_matrix() # needs sage.rings.finite_rings - sage: A.echelonize() # needs sage.rings.finite_rings + sage: A, v = F.coefficient_matrix() + sage: A.echelonize() 3. The result is the desired Gröbner basis:: - sage: G = Sequence((A * v).list()) # needs sage.rings.finite_rings - sage: G.is_groebner() # needs sage.rings.finite_rings + sage: G = Sequence((A * v).list()) + sage: G.is_groebner() True - sage: Ideal(G) == I # needs sage.rings.finite_rings + sage: Ideal(G) == I True We return some element in the ideal with no guarantee on the distribution:: @@ -5410,8 +5421,7 @@ def weil_restriction(self): sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal sage: J.variety() [{y1: 1, y0: 0, x1: 1, x0: 1}] - - sage: J.weil_restriction() # returns J # needs sage.rings.finite_rings + sage: J.weil_restriction() # returns J Ideal (x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + x0, x1^2 + x1, y0^2 + y0, y1^2 + y1) of Multivariate Polynomial Ring in x0, x1, y0, y1 over Finite Field of size 2 @@ -5424,8 +5434,7 @@ def weil_restriction(self): 0 sage: I.variety() [{z: 0, y: 0, x: 1}] - - sage: J = I.weil_restriction(); J # needs sage.rings.finite_rings + sage: J = I.weil_restriction(); J Ideal (x0 - y0 - z0 - 1, x1 - y1 - z1, x2 - y2 - z2, x3 - y3 - z3, x4 - y4 - z4, x0^2 + x2*x3 + x1*x4 - y0^2 - y2*y3 - y1*y4 - z0^2 - z2*z3 - z1*z4 - x0, @@ -5450,9 +5459,9 @@ def weil_restriction(self): - y4*z0 - y3*z1 - y2*z2 - y1*z3 - y0*z4 - y4*z4 - y4) of Multivariate Polynomial Ring in x0, x1, x2, x3, x4, y0, y1, y2, y3, y4, z0, z1, z2, z3, z4 over Finite Field of size 3 - sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal # needs sage.rings.finite_rings + sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal sage: from sage.doctest.fixtures import reproducible_repr - sage: print(reproducible_repr(J.variety())) # needs sage.rings.finite_rings + sage: print(reproducible_repr(J.variety())) [{x0: 1, x1: 0, x2: 0, x3: 0, x4: 0, y0: 0, y1: 0, y2: 0, y3: 0, y4: 0, z0: 0, z1: 0, z2: 0, z3: 0, z4: 0}] @@ -5489,8 +5498,7 @@ def weil_restriction(self): So we compute its Weil restriction:: - sage: J = I.weil_restriction() # needs sage.rings.number_field - sage: J # needs sage.rings.number_field + sage: J = I.weil_restriction(); J # needs sage.rings.number_field Ideal (-x0^3 - x0*x1^2 - 2*x0^2*z0 - 2/3*x1^2*z0 + x0*y0*z0 + y0^2*z0 + 1/3*x1*y1*z0 + 1/3*y1^2*z0 - 4*x0*z0^2 + 3*y0*z0^2 - 5*z0^3 - 4/3*x0*x1*z1 + 1/3*x1*y0*z1 + 1/3*x0*y1*z1 + 2/3*y0*y1*z1 @@ -5509,13 +5517,14 @@ def weil_restriction(self): Example for relative number fields:: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^5 - 2) # needs sage.rings.number_field - sage: R. = K[] # needs sage.rings.number_field - sage: L. = K.extension(x^2 + 1) # needs sage.rings.number_field - sage: S. = L[] # needs sage.rings.number_field - sage: I = S.ideal([y^2 - x^3 - 1]) # needs sage.rings.number_field - sage: I.weil_restriction() # needs sage.rings.number_field + sage: K. = NumberField(x^5 - 2) + sage: R. = K[] + sage: L. = K.extension(x^2 + 1) + sage: S. = L[] + sage: I = S.ideal([y^2 - x^3 - 1]) + sage: I.weil_restriction() Ideal (-x0^3 + 3*x0*x1^2 + y0^2 - y1^2 - 1, -3*x0^2*x1 + x1^3 + 2*y0*y1) of Multivariate Polynomial Ring in x0, x1, y0, y1 over Number Field in w with defining polynomial x^5 - 2 diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 45e14eb320d..4392ae438be 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -30,21 +30,18 @@ We show how to construct various multivariate polynomial rings:: sage: P.term_order() Degree reverse lexicographic term order - sage: P = PolynomialRing(GF(127),3,names='abc', order='lex') - sage: P + sage: P = PolynomialRing(GF(127), 3, names='abc', order='lex'); P Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1; f 57*a^2*b + 43*c + 1 - sage: P.term_order() Lexicographic term order sage: z = QQ['z'].0 - sage: K. = NumberField(z^2 - 2) - sage: P. = PolynomialRing(K, 2) - sage: 1/2*s*x^2 + 3/4*s + sage: K. = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P. = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: 1/2*s*x^2 + 3/4*s # needs sage.rings.number_field (1/2*s)*x^2 + (3/4*s) sage: P. = ZZ[]; P @@ -57,7 +54,8 @@ We show how to construct various multivariate polynomial rings:: Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 59049 sage: P. = Zmod(2^100)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1267650600228229401496703205376 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 1267650600228229401496703205376 sage: P. = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 @@ -75,9 +73,9 @@ We construct the Frobenius morphism on `\GF{5}[x,y,z]` over `\GF{5}`:: sage: frob = R.hom([x^5, y^5, z^5]) sage: frob(x^2 + 2*y - z^4) -z^20 + x^10 + 2*y^5 - sage: frob((x + 2*y)^3) + sage: frob((x + 2*y)^3) # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 - sage: (x^5 + 2*y^5)^3 + sage: (x^5 + 2*y^5)^3 # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 We make a polynomial ring in one variable over a polynomial ring in @@ -95,7 +93,7 @@ TESTS:: True sage: loads(dumps(x)) == x True - sage: P. = GF(2^8,'a')[] + sage: P. = GF(2^8,'a')[] # needs sage.rings.finite_rings sage: loads(dumps(P)) == P True sage: loads(dumps(x)) == x @@ -120,9 +118,9 @@ TESTS:: Check if :trac:`6160` is fixed:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x - 1728) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: b - j*c # optional - sage.rings.number_field + sage: K. = NumberField(x - 1728) # needs sage.rings.number_field + sage: R. = K[] # needs sage.rings.number_field + sage: b - j*c # needs sage.rings.number_field b - 1728*c .. TODO:: @@ -297,31 +295,25 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: - sage: P. = QQ[] - sage: P + sage: P. = QQ[]; P Multivariate Polynomial Ring in x, y, z over Rational Field - sage: f = 27/113 * x^2 + y*z + 1/2; f 27/113*x^2 + y*z + 1/2 - sage: P.term_order() Degree reverse lexicographic term order - sage: P = PolynomialRing(GF(127),3,names='abc', order='lex') - sage: P + sage: P = PolynomialRing(GF(127), 3, names='abc', order='lex'); P Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1; f 57*a^2*b + 43*c + 1 - sage: P.term_order() Lexicographic term order sage: z = QQ['z'].0 - sage: K. = NumberField(z^2 - 2) - sage: P. = PolynomialRing(K, 2) - sage: 1/2*s*x^2 + 3/4*s + sage: K. = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P. = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: 1/2*s*x^2 + 3/4*s # needs sage.rings.number_field (1/2*s)*x^2 + (3/4*s) sage: P. = ZZ[]; P @@ -334,7 +326,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 59049 sage: P. = Zmod(2^100)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1267650600228229401496703205376 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 1267650600228229401496703205376 sage: P. = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 @@ -342,11 +335,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P. = Zmod(25213521351515232)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 25213521351515232 sage: type(P) - sage: P. = PolynomialRing(Integers(2^32),order='lex') + sage: P. = PolynomialRing(Integers(2^32), order='lex') sage: P(2^32-1) 4294967295 @@ -368,7 +362,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Traceback (most recent call last): ... NotImplementedError: polynomials over Ring of integers modulo 1 are not supported in Singular - sage: MPolynomialRing_libsingular(SR, 1, ["x"], "lex") # optional - sage.symbolic + sage: MPolynomialRing_libsingular(SR, 1, ["x"], "lex") # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: polynomials over Symbolic Ring are not supported in Singular @@ -403,9 +397,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: import gc sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - sage: R1 = MPolynomialRing_libsingular(GF(5), 2, ('x', 'y'), TermOrder('degrevlex', 2)) - sage: R2 = MPolynomialRing_libsingular(GF(11), 2, ('x', 'y'), TermOrder('degrevlex', 2)) - sage: R3 = MPolynomialRing_libsingular(GF(13), 2, ('x', 'y'), TermOrder('degrevlex', 2)) + sage: R1 = MPolynomialRing_libsingular(GF(5), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) + sage: R2 = MPolynomialRing_libsingular(GF(11), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) + sage: R3 = MPolynomialRing_libsingular(GF(13), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) sage: _ = gc.collect() sage: foo = R1.gen(0) sage: del foo @@ -427,23 +424,24 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): TESTS:: + sage: # needs sage.rings.function_field sage: import gc sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular sage: from sage.libs.singular.ring import ring_refcount_dict sage: gc.collect() # random output sage: n = len(ring_refcount_dict) - sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), TermOrder('degrevlex', 2)) + sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) sage: len(ring_refcount_dict) == n + 1 True - sage: Q = copy(R) # indirect doctest - sage: p = R.gen(0) ^2+R.gen(1)^2 + sage: p = R.gen(0)^2 + R.gen(1)^2 sage: q = copy(p) sage: del R sage: del Q sage: del p sage: del q - sage: gc.collect() # random output + sage: gc.collect() # random output sage: len(ring_refcount_dict) == n False """ @@ -458,7 +456,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): TESTS:: sage: R. = GF(547)[] - sage: R is deepcopy(R) # indirect doctest + sage: R is deepcopy(R) True """ memo[id(self)] = self @@ -559,15 +557,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.coerce(int(1)) 1 - sage: k. = GF(2^8) - sage: P. = PolynomialRing(k,2) - sage: P.coerce(a) + sage: k. = GF(2^8) # needs sage.rings.finite_rings + sage: P. = PolynomialRing(k,2) # needs sage.rings.finite_rings + sage: P.coerce(a) # needs sage.rings.finite_rings a sage: z = QQ['z'].0 - sage: K. = NumberField(z^2 - 2) - sage: P. = PolynomialRing(K, 2) - sage: P.coerce(1/2*s) + sage: K. = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P. = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: P.coerce(1/2*s) # needs sage.rings.number_field (1/2*s) TESTS:: @@ -583,16 +581,16 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Check if :trac:`7582` is fixed:: - sage: R. = PolynomialRing(CyclotomicField(2),3) - sage: R.coerce(1) + sage: R. = PolynomialRing(CyclotomicField(2), 3) # needs sage.rings.number_field + sage: R.coerce(1) # needs sage.rings.number_field 1 Check if :trac:`6160` is fixed:: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x - 1728) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: R.coerce(1) # optional - sage.rings.number_field + sage: K. = NumberField(x - 1728) # needs sage.rings.number_field + sage: R. = K[] # needs sage.rings.number_field + sage: R.coerce(1) # needs sage.rings.number_field 1 Check if coercion from zero variable polynomial rings work @@ -624,15 +622,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: P._singular_().set_ring() - sage: P(singular('x + 3/4')) + sage: P(singular('x + 3/4')) # needs sage.rings.function_field x + 3/4 Coercion from symbolic variables:: sage: R = QQ['x,y,z'] - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: R(x) + sage: R(x) # needs sage.symbolic x Coercion from 'similar' rings, which maps by index:: @@ -652,9 +650,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Coercion from PARI objects:: sage: P. = QQ[] - sage: P(pari('x^2 + y')) + sage: P(pari('x^2 + y')) # needs sage.libs.pari x^2 + y - sage: P(pari('x*y')) + sage: P(pari('x*y')) # needs sage.libs.pari x*y Coercion from boolean polynomials, also by index:: @@ -667,7 +665,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): If everything else fails, we try to convert to the base ring:: sage: R. = GF(3)[] - sage: R(1/2) + sage: R(1/2) # needs sage.rings.finite_rings -1 Finally, conversions from other polynomial rings which are not @@ -677,7 +675,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): preserving conversion:: sage: P. = GF(3)[] - sage: Q = GF(3)['y_4', 'y_3', 'y_2', 'y_1', 'z_5', 'z_4', 'z_3', 'z_2', 'z_1'] + sage: Q = GF(3)['y_4', 'y_3', 'y_2', 'y_1', + ....: 'z_5', 'z_4', 'z_3', 'z_2', 'z_1'] sage: Q(y_1*z_2^2*z_1) y_1*z_2^2*z_1 @@ -687,7 +686,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P. = GF(2)[] sage: Q = GF(2)['c','b','d','e'] sage: f = Q.convert_map_from(P) - sage: f(a), f(b), f(c) + sage: f(a), f(b), f(c) # needs sage.rings.finite_rings (c, b, d) :: @@ -703,14 +702,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P. = GF(2)[] sage: Q = GF(2)['c','d','e'] sage: f = Q.convert_map_from(P) - sage: f(a) + sage: f(a) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: Could not find a mapping of the passed element to this ring. Coerce in a polydict where a coefficient reduces to 0 but isn't 0. :: - sage: R. = QQ[]; S. = GF(5)[]; S( (5*x*y + x + 17*y)._mpoly_dict_recursive() ) + sage: R. = QQ[]; S. = GF(5)[] + sage: S((5*x*y + x + 17*y)._mpoly_dict_recursive()) xx + 2*yy Coerce in a polynomial one of whose coefficients reduces to 0. :: @@ -721,7 +721,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Some other examples that illustrate the same coercion idea:: sage: R. = ZZ[] - sage: S. = GF(25,'a')[] + sage: S. = GF(25,'a')[] # needs sage.rings.finite_rings sage: S(5*x*y + x + 17*y) xx + 2*yy @@ -747,11 +747,11 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): And :trac:`7597` is fixed if this does not segfault:: sage: F2 = GF(2) - sage: F. = GF(2^8) + sage: F. = GF(2^8) # needs sage.rings.finite_rings sage: R4. = PolynomialRing(F) sage: R. = PolynomialRing(F2) sage: P = a - sage: (P(0,0).polynomial()[0])*u + sage: (P(0,0).polynomial()[0])*u # needs sage.rings.finite_rings 0 sage: P(a,b) a @@ -764,6 +764,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Check that :trac:`17964` is fixed:: + sage: # needs sage.rings.number_field sage: K. = QuadraticField(17) sage: Q. = K[] sage: f = (-3*a)*y + (5*a) @@ -1031,9 +1032,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.ngens() 2 - sage: k. = GF(2^16) - sage: P = PolynomialRing(k,1000,'x') - sage: P.ngens() + sage: k. = GF(2^16) # needs sage.rings.finite_rings + sage: P = PolynomialRing(k, 1000, 'x') # needs sage.rings.finite_rings + sage: P.ngens() # needs sage.rings.finite_rings 1000 """ return int(self.__ngens) @@ -1050,10 +1051,10 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: sage: P. = QQ[] - sage: P.gen(),P.gen(1) + sage: P.gen(), P.gen(1) (x, y) - sage: P = PolynomialRing(GF(127),1000,'x') + sage: P = PolynomialRing(GF(127), 1000, 'x') sage: P.gen(500) x500 @@ -1089,11 +1090,13 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: sage: P. = QQ[] - sage: sage.rings.ideal.Katsura(P) - Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: sage.rings.ideal.Katsura(P) # needs sage.rings.function_field + Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) + of Multivariate Polynomial Ring in x, y, z over Rational Field sage: P.ideal([x + 2*y + 2*z-1, 2*x*y + 2*y*z-y, x^2 + 2*y^2 + 2*z^2-x]) - Ideal (x + 2*y + 2*z - 1, 2*x*y + 2*y*z - y, x^2 + 2*y^2 + 2*z^2 - x) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 2*y + 2*z - 1, 2*x*y + 2*y*z - y, x^2 + 2*y^2 + 2*z^2 - x) + of Multivariate Polynomial Ring in x, y, z over Rational Field """ coerce = kwds.get('coerce', True) if len(gens) == 1: @@ -1136,7 +1139,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): QQ[x...y] sage: R. = GF(17)[] - sage: macaulay2(R) # optional - macaulay2 + sage: macaulay2(R) # optional - macaulay2 # needs sage.rings.finite_rings ZZ --[x...y] 17 @@ -1191,9 +1194,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P._singular_().name() == P._singular_().name() True - sage: k. = GF(3^3) - sage: P. = PolynomialRing(k,3) - sage: P._singular_() + sage: k. = GF(3^3) # needs sage.rings.finite_rings + sage: P. = PolynomialRing(k, 3) # needs sage.rings.finite_rings + sage: P._singular_() # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/3[a]/(a^3-a+1) // number of vars : 3 @@ -1201,10 +1204,10 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // : names x y z // block 2 : ordering C - sage: P._singular_() is P._singular_() + sage: P._singular_() is P._singular_() # needs sage.rings.finite_rings True - sage: P._singular_().name() == P._singular_().name() + sage: P._singular_().name() == P._singular_().name() # needs sage.rings.finite_rings True TESTS:: @@ -1266,8 +1269,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): False sage: w = polygen(ZZ, 'w') - sage: R. = PolynomialRing(NumberField(w^2 + 1,'s')) # optional - sage.rings.number_field - sage: singular(R) # optional - sage.rings.number_field + sage: R. = PolynomialRing(NumberField(w^2 + 1,'s')) # needs sage.rings.number_field + sage: singular(R) # needs sage.rings.number_field polynomial ring, over a field, global ordering // coefficients: QQ[s]/(s^2+1) // number of vars : 2 @@ -1275,8 +1278,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // : names x y // block 2 : ordering C - sage: R = PolynomialRing(GF(2**8,'a'),10,'x', order='invlex') - sage: singular(R) + sage: R = PolynomialRing(GF(2**8,'a'),10,'x', order='invlex') # needs sage.rings.finite_rings + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/2[a]/(a^8+a^4+a^3+a^2+1) // number of vars : 10 @@ -1285,7 +1288,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(GF(127),2,'x', order='invlex') - sage: singular(R) + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 2 @@ -1294,7 +1297,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(QQ,2,'x', order='invlex') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 @@ -1303,7 +1306,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(QQ,2,'x', order='degneglex') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 @@ -1315,7 +1318,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 3 : ordering C sage: R = PolynomialRing(QQ,'x') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -1324,7 +1327,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(GF(127),'x') - sage: singular(R) + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -1333,7 +1336,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = ZZ['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 2 @@ -1342,7 +1345,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = IntegerModRing(1024)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/(2^10) // number of vars : 2 @@ -1351,7 +1354,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = IntegerModRing(15)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/...(15) // number of vars : 2 @@ -1430,7 +1433,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P == R False - sage: R. = PolynomialRing(QQ,order='invlex') + sage: R. = PolynomialRing(QQ, order='invlex') sage: P == R False @@ -1476,16 +1479,16 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P == loads(dumps(P)) True - sage: P = PolynomialRing(GF(2^8,'F'), names='abc') + sage: P = PolynomialRing(GF(2^8,'F'), names='abc') # needs sage.rings.finite_rings sage: P == loads(dumps(P)) True - sage: P = PolynomialRing(GF(2^16,'B'), names='abc') + sage: P = PolynomialRing(GF(2^16,'B'), names='abc') # needs sage.rings.finite_rings sage: P == loads(dumps(P)) True sage: z = QQ['z'].0 - sage: P = PolynomialRing(NumberField(z^2 + 3,'B'), names='abc') - sage: P == loads(dumps(P)) + sage: P = PolynomialRing(NumberField(z^2 + 3, 'B'), names='abc') # needs sage.rings.number_field + sage: P == loads(dumps(P)) # needs sage.rings.number_field True """ return unpickle_MPolynomialRing_libsingular, \ @@ -1904,8 +1907,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular - sage: P = PolynomialRing(GF(32003),3,'x') - sage: MPolynomial_libsingular(P) + sage: P = PolynomialRing(GF(32003), 3, 'x') # needs sage.rings.finite_rings + sage: MPolynomial_libsingular(P) # needs sage.rings.finite_rings 0 """ self._poly = NULL @@ -1932,6 +1935,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F. = GF(7^2) sage: R. = F[] sage: p = a*x^2 + y + a^3; p @@ -2038,11 +2042,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): See :trac:`8502`:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K. = NumberField(x^2+47) + sage: K. = NumberField(x^2 + 47) sage: R. = K[] - sage: f = X+Y+Z - sage: a = f(t,t,t); a + sage: f = X + Y + Z + sage: a = f(t, t, t); a 3*t sage: a.parent() is K True @@ -2056,6 +2061,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): See :trac:`33373`:: + sage: # needs sage.rings.finite_rings sage: k. = GF(2^4) sage: R. = PolynomialRing(k, 1) sage: f = R(1) @@ -2775,12 +2781,11 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): INPUT: - ``degrees`` - Can be any of: - - a dictionary of degree restrictions - - a list of degree restrictions (with None in the unrestricted variables) - - a monomial (very fast, but not as flexible) + - a dictionary of degree restrictions + - a list of degree restrictions (with ``None`` in the unrestricted variables) + - a monomial (very fast, but not as flexible) - OUTPUT: - element of the parent of this element. + OUTPUT: element of the parent of this element. .. NOTE:: @@ -2818,8 +2823,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f.coefficient(x^0) # outputs the full polynomial x^2*y^2 + x^2*y + x*y^2 + x^2 + x*y + y^2 + x + y + 1 sage: R. = GF(389)[] - sage: f=x*y+5 - sage: c=f.coefficient({x:0,y:0}); c + sage: f = x*y + 5 + sage: c = f.coefficient({x:0, y:0}); c 5 sage: parent(c) Multivariate Polynomial Ring in x, y over Finite Field of size 389 @@ -3408,12 +3413,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f = x^2 + y + x^2*y^2 + 5 sage: f(5,y) 25*y^2 + y + 30 - sage: f.subs({x:5}) + sage: f.subs({x: 5}) 25*y^2 + y + 30 sage: f.subs(x=5) 25*y^2 + y + 30 - sage: P. = PolynomialRing(GF(2),3) + sage: P. = PolynomialRing(GF(2), 3) sage: f = x + y + 1 sage: f.subs({x:y+1}) 0 @@ -3421,14 +3426,14 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): 1 sage: f.subs(x=x) x + y + 1 - sage: f.subs({x:z}) + sage: f.subs({x: z}) y + z + 1 - sage: f.subs(x=z+1) + sage: f.subs(x=z + 1) y + z sage: f.subs(x=1/y) (y^2 + y + 1)/y - sage: f.subs({x:1/y}) + sage: f.subs({x: 1/y}) (y^2 + y + 1)/y The parameters are substituted in order and without side effects:: @@ -3459,8 +3464,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): We test that we change the ring even if there is nothing to do:: sage: P = QQ['x,y'] - sage: x = var('x') - sage: parent(P.zero().subs(x=x)) + sage: x = var('x') # needs sage.symbolic + sage: parent(P.zero().subs(x=x)) # needs sage.symbolic Symbolic Ring We are catching overflows:: @@ -3794,8 +3799,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): def is_univariate(self): """ - Return ``True`` if self is a univariate polynomial, that is if - self contains only one variable. + Return ``True`` if ``self`` is a univariate polynomial, that is if + ``self`` contains only one variable. EXAMPLES:: @@ -3814,13 +3819,13 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): def _variable_indices_(self, sort=True): """ - Return the indices of all variables occurring in self. This + Return the indices of all variables occurring in ``self``. This index is the index as Sage uses them (starting at zero), not as SINGULAR uses them (starting at one). INPUT: - - ``sort`` - specifies whether the indices shall be sorted + - ``sort`` -- specifies whether the indices shall be sorted EXAMPLES:: @@ -3847,7 +3852,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): def variables(self): """ - Return a tuple of all variables occurring in self. + Return a tuple of all variables occurring in ``self``. EXAMPLES:: @@ -3878,8 +3883,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): def variable(self, i=0): """ - - Return the i-th variable occurring in self. The index i is the + Return the `i`-th variable occurring in ``self``. The index `i` is the index in ``self.variables()``. EXAMPLES:: @@ -3925,13 +3929,13 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): def lm(MPolynomial_libsingular self): """ - Returns the lead monomial of self with respect to the term + Returns the lead monomial of ``self`` with respect to the term order of ``self.parent()``. In Sage a monomial is a product of variables in some power without a coefficient. EXAMPLES:: - sage: R.=PolynomialRing(GF(7),3,order='lex') + sage: R. = PolynomialRing(GF(7), 3, order='lex') sage: f = x^1*y^2 + y^3*z^4 sage: f.lm() x*y^2 @@ -3939,7 +3943,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f.lm() x^3*y^2*z^4 - sage: R.=PolynomialRing(QQ,3,order='deglex') + sage: R.=PolynomialRing(QQ, 3, order='deglex') sage: f = x^1*y^2*z^3 + x^3*y^2*z^0 sage: f.lm() x*y^2*z^3 @@ -3947,7 +3951,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f.lm() x*y^2*z^4 - sage: R.=PolynomialRing(GF(127),3,order='degrevlex') + sage: R.=PolynomialRing(GF(127), 3, order='degrevlex') sage: f = x^1*y^5*z^2 + x^4*y^1*z^3 sage: f.lm() x*y^5*z^2 @@ -3972,7 +3976,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: - sage: R.=PolynomialRing(GF(7),3,order='lex') + sage: R. = PolynomialRing(GF(7), 3, order='lex') sage: f = 3*x^1*y^2 + 2*y^3*z^4 sage: f.lc() 3 @@ -4006,7 +4010,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: - sage: R.=PolynomialRing(GF(7),3,order='lex') + sage: R. = PolynomialRing(GF(7), 3, order='lex') sage: f = 3*x^1*y^2 + 2*y^3*z^4 sage: f.lt() 3*x*y^2 @@ -4028,7 +4032,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: P. = PolynomialRing(QQ) sage: x.is_zero() False - sage: (x-x).is_zero() + sage: (x - x).is_zero() True """ if self._poly is NULL: @@ -4062,6 +4066,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R. = GF(32003)[] sage: f = y*x^2 + x + 1 sage: f//x @@ -4156,15 +4161,14 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): INPUT: - - ``proof`` - ignored. + - ``proof`` -- ignored. EXAMPLES:: sage: R. = QQ[] sage: f = (x^3 + 2*y^2*x) * (x^2 + x + 1); f x^5 + 2*x^3*y^2 + x^4 + 2*x^2*y^2 + x^3 + 2*x*y^2 - sage: F = f.factor() - sage: F + sage: F = f.factor(); F x * (x^2 + x + 1) * (x^2 + 2*y^2) Next we factor the same polynomial, but over the finite field @@ -4174,27 +4178,28 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f = (x^3 + 2*y^2*x) * (x^2 + x + 1); f x^5 - x^3*y^2 + x^4 - x^2*y^2 + x^3 - x*y^2 sage: F = f.factor() - sage: F # order is somewhat random + sage: F # order is somewhat random (-1) * x * (-x + y) * (x + y) * (x - 1)^2 Next we factor a polynomial, but over a finite field of order 9.:: + sage: # needs sage.rings.finite_rings sage: K. = GF(3^2) sage: R. = K[] sage: f = (x^3 + 2*a*y^2*x) * (x^2 + x + 1); f x^5 + (-a)*x^3*y^2 + x^4 + (-a)*x^2*y^2 + x^3 + (-a)*x*y^2 - sage: F = f.factor() - sage: F + sage: F = f.factor(); F ((-a)) * x * (x - 1)^2 * ((-a + 1)*x^2 + y^2) sage: f - F 0 Next we factor a polynomial over a number field.:: + sage: # needs sage.rings.number_field sage: p = polygen(ZZ, 'p') - sage: K. = NumberField(p^3 - 2) # optional - sage.rings.number_field - sage: KXY. = K[] # optional - sage.rings.number_field - sage: factor(x^3 - 2*y^3) # optional - sage.rings.number_field + sage: K. = NumberField(p^3 - 2) + sage: KXY. = K[] + sage: factor(x^3 - 2*y^3) (x + (-s)*y) * (x^2 + s*x*y + (s^2)*y^2) sage: k = (x^3-2*y^3)^5*(x+s*y)^2*(2/3 + s^2) sage: k.factor() @@ -4203,18 +4208,19 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): This shows that issue :trac:`2780` is fixed, i.e. that the unit part of the factorization is set correctly:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - sage: f = 2*y^2 + 2*z^2 # optional - sage.rings.number_field - sage: F = f.factor(); F.unit() # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: R. = PolynomialRing(K) + sage: f = 2*y^2 + 2*z^2 + sage: F = f.factor(); F.unit() 2 Another example:: - sage: R. = GF(32003)[] - sage: f = 9*(x-1)^2*(y+z) - sage: f.factor() + sage: R. = GF(32003)[] # needs sage.rings.finite_rings + sage: f = 9*(x-1)^2*(y+z) # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings (9) * (y + z) * (x - 1)^2 sage: R. = QQ['x','w','v','u'] @@ -4243,12 +4249,13 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): `> 2^{29}` is not supported :: sage: q = 1073741789 - sage: T. = PolynomialRing(GF(q)) - sage: f = aa^2 + 12124343*bb*aa + 32434598*bb^2 - sage: f.factor() + sage: T. = PolynomialRing(GF(q)) # needs sage.rings.finite_rings + sage: f = aa^2 + 12124343*bb*aa + 32434598*bb^2 # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over prime fields with characteristic > 2^29 is not implemented. Factorization over the integers is now supported, see :trac:`17840`:: @@ -4269,7 +4276,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: f.factor() Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over Ring of integers modulo 4 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over Ring of integers modulo 4 is not implemented. TESTS: @@ -4282,6 +4290,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): This checks that :trac:`11838` is fixed:: + sage: # needs sage.rings.finite_rings sage: K = GF(4,'a') sage: a = K.gens()[0] sage: R. = K[] @@ -4308,8 +4317,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): :: sage: R. = GF(2)[] - sage: p=x^8 + y^8; q=x^2*y^4 + x - sage: f=p*q + sage: p = x^8 + y^8; q=x^2*y^4 + x + sage: f = p*q sage: lf = f.factor() sage: f-lf 0 @@ -4330,18 +4339,18 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): :: sage: R. = GF(5)[] - sage: p=x^27*y^9 + x^32*y^3 + 2*x^20*y^10 - x^4*y^24 - 2*x^17*y - sage: q=-2*x^10*y^24 + x^9*y^24 - 2*x^3*y^30 - sage: f=p*q; f-f.factor() + sage: p = x^27*y^9 + x^32*y^3 + 2*x^20*y^10 - x^4*y^24 - 2*x^17*y + sage: q = -2*x^10*y^24 + x^9*y^24 - 2*x^3*y^30 + sage: f = p*q; f - f.factor() 0 :: sage: R. = GF(7)[] - sage: p=-3*x^47*y^24 - sage: q=-3*x^47*y^37 - 3*x^24*y^49 + 2*x^56*y^8 + 3*x^29*y^15 - x^2*y^33 - sage: f=p*q - sage: f-f.factor() + sage: p = -3*x^47*y^24 + sage: q = -3*x^47*y^37 - 3*x^24*y^49 + 2*x^56*y^8 + 3*x^29*y^15 - x^2*y^33 + sage: f = p*q + sage: f - f.factor() 0 The following examples used to give a Segmentation Fault, see @@ -4368,13 +4377,14 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: U. = GF(2)[] sage: f = y*t^8 + y^5*t^2 + y*t^6 + t^7 + y^6 + y^5*t + y^2*t^4 + y^2*t^2 + y^2*t + t^3 + y^2 + t^2 sage: l = f.factor() - sage: l[0][0]==t^2 + y + t + 1 or l[1][0]==t^2 + y + t + 1 + sage: l[0][0] == t^2 + y + t + 1 or l[1][0] == t^2 + y + t + 1 True The following used to sometimes take a very long time or get stuck, see :trac:`12846`. These 100 iterations should take less than 1 second:: + sage: # needs sage.rings.finite_rings sage: K. = GF(4) sage: R. = K[] sage: f = (a + 1)*x^145*y^84 + (a + 1)*x^205*y^17 + x^32*y^112 + x^92*y^45 @@ -4384,7 +4394,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): Test for :trac:`20435`:: sage: x,y = polygen(ZZ,'x,y') - sage: p = x**2-y**2 + sage: p = x**2 - y**2 sage: z = factor(p); z (x - y) * (x + y) sage: z[0][0].parent() @@ -4718,11 +4728,11 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): INPUT: - - ``right`` - polynomial + - ``right`` -- polynomial - ``algorithm`` - - ``ezgcd`` - EZGCD algorithm - - ``modular`` - multi-modular algorithm (default) - - ``**kwds`` - ignored + - ``'ezgcd'`` -- EZGCD algorithm + - ``'modular'`` -- multi-modular algorithm (default) + - ``**kwds`` -- ignored EXAMPLES:: @@ -4742,6 +4752,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): We compute a gcd over a finite field:: + sage: # needs sage.rings.finite_rings sage: F. = GF(31^2) sage: R. = F[] sage: p = x^3 + (1+u)*y^3 + z^3 @@ -4753,6 +4764,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): We compute a gcd over a number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: F. = NumberField(x^3 - 2) sage: R. = F[] @@ -4770,10 +4782,11 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: x.gcd(1) 1 + sage: # needs sage.rings.finite_rings sage: k. = GF(9) sage: R. = PolynomialRing(k) sage: f = R.change_ring(GF(3)).gen() - sage: g = x+y + sage: g = x + y sage: g.gcd(f) 1 sage: x.gcd(R.change_ring(GF(3)).gen()) @@ -4844,17 +4857,19 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: lcm(p,q) 6*x*y*z^4 + 6*y^2*z^4 + 6*x*z^5 + 6*y*z^5 + 12*x*y + 12*y^2 + 12*x*z + 12*y*z + sage: # needs sage.rings.finite_rings sage: r. = PolynomialRing(GF(2**8, 'a'), 2) sage: a = r.base_ring().0 sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5 sage: f.lcm(x^4) (a^2 + a)*x^6*y + (a^4 + a^3 + a)*x^4*y + (a^5)*x^4 + sage: # needs sage.rings.number_field sage: w = polygen(ZZ, 'w') - sage: r. = PolynomialRing(NumberField(w^4 + 1, 'a'), 2) # optional - sage.rings.number_field - sage: a = r.base_ring().0 # optional - sage.rings.number_field - sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5 # optional - sage.rings.number_field - sage: f.lcm(x^4) # optional - sage.rings.number_field + sage: r. = PolynomialRing(NumberField(w^4 + 1, 'a'), 2) + sage: a = r.base_ring().0 + sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5 + sage: f.lcm(x^4) (a^2 + a)*x^6*y + (a^3 + a - 1)*x^4*y + (-a)*x^4 TESTS:: @@ -4920,7 +4935,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): @coerce_binop def quo_rem(self, MPolynomial_libsingular right): """ - Returns quotient and remainder of self and right. + Return quotient and remainder of ``self`` and ``right``. EXAMPLES:: @@ -4989,15 +5004,15 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: - sage: P. = PolynomialRing(GF(127),3) - sage: x._singular_init_() + sage: P. = PolynomialRing(GF(127), 3) + sage: x._singular_init_() # needs sage.libs.singular 'x' - sage: (x^2+37*y+128)._singular_init_() + sage: (x^2+37*y+128)._singular_init_() # needs sage.libs.singular 'x2+37y+1' TESTS:: - sage: P(0)._singular_init_() + sage: P(0)._singular_init_() # needs sage.libs.singular '0' """ if singular is None: @@ -5017,17 +5032,17 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: - sage: P.=PolynomialRing(QQ,3) - sage: x.sub_m_mul_q(y,z) + sage: P. = PolynomialRing(QQ,3) + sage: x.sub_m_mul_q(y, z) -y*z + x TESTS:: - sage: Q.=PolynomialRing(QQ,3) - sage: P.=PolynomialRing(QQ,3) - sage: P(0).sub_m_mul_q(P(0),P(1)) + sage: Q. = PolynomialRing(QQ,3) + sage: P. = PolynomialRing(QQ,3) + sage: P(0).sub_m_mul_q(P(0), P(1)) 0 - sage: x.sub_m_mul_q(Q.gen(1),Q.gen(2)) + sage: x.sub_m_mul_q(Q.gen(1), Q.gen(2)) -y*z + x """ cdef ring *r = self._parent_ring @@ -5063,21 +5078,21 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: + sage: # optional - macaulay2 sage: R. = PolynomialRing(GF(7), 2) sage: f = (x^3 + 2*y^2*x)^7; f # indirect doctest x^21 + 2*x^7*y^14 - - sage: h = macaulay2(f); h # optional - macaulay2 + sage: h = macaulay2(f); h 21 7 14 x + 2x y - sage: k = macaulay2(x+y); k # optional - macaulay2 + sage: k = macaulay2(x+y); k x + y - sage: k + h # optional - macaulay2 + sage: k + h 21 7 14 x + 2x y + x + y - sage: R(h) # optional - macaulay2 + sage: R(h) x^21 + 2*x^7*y^14 - sage: R(h^20) == f^20 # optional - macaulay2 + sage: R(h^20) == f^20 True TESTS: @@ -5102,12 +5117,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): INPUT: - - ``m`` - a monomial - - ``q`` - a polynomial + - ``m`` -- a monomial + - ``q`` -- a polynomial EXAMPLES:: - sage: P.=PolynomialRing(QQ,3) + sage: P. = PolynomialRing(QQ,3) sage: x.add_m_mul_q(y,z) y*z + x @@ -5146,12 +5161,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: - sage: P. = PolynomialRing(QQ,3, order='degrevlex') + sage: P. = PolynomialRing(QQ, 3, order='degrevlex') sage: f = 27/113 * x^2 + y*z + 1/2 sage: f == loads(dumps(f)) True - sage: P = PolynomialRing(GF(127),3,names='abc') + sage: P = PolynomialRing(GF(127), 3, names='abc') sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1 sage: f == loads(dumps(f)) @@ -5191,6 +5206,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): You can specify a map on the base ring:: + sage: # needs sage.rings.number_field sage: Zx. = ZZ[] sage: K. = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -5235,9 +5251,9 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): The derivative is also defined over finite fields:: - sage: R. = PolynomialRing(GF(2**8, 'a'),2) + sage: R. = PolynomialRing(GF(2**8, 'a'), 2) # needs sage.rings.finite_rings sage: f = x^3*y^2 + y^2 + x + 2 - sage: f._derivative(x) + sage: f._derivative(x) # needs sage.rings.finite_rings x^2*y^2 + 1 """ @@ -5375,16 +5391,16 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): The SINGULAR example:: - sage: R. = PolynomialRing(GF(32003),3) + sage: R. = PolynomialRing(GF(32003), 3) # needs sage.rings.finite_rings sage: f = 3 * (x+2)^3 + y - sage: g = x+y+z - sage: f.resultant(g,x) + sage: g = x + y + z # needs sage.rings.finite_rings + sage: f.resultant(g, x) # needs sage.rings.finite_rings 3*y^3 + 9*y^2*z + 9*y*z^2 + 3*z^3 - 18*y^2 - 36*y*z - 18*z^2 + 35*y + 36*z - 24 Resultants are also supported over the Integers:: - sage: R.=PolynomialRing(ZZ, 5, order='lex') - sage: r = (x^4*y^2+x^2*y-y).resultant(x*y-y*a-x*b+a*b+u,x) + sage: R. = PolynomialRing(ZZ, 5, order='lex') + sage: r = (x^4*y^2 + x^2*y - y).resultant(x*y - y*a - x*b + a*b + u, x) sage: r y^6*a^4 - 4*y^5*a^4*b - 4*y^5*a^3*u + y^5*a^2 - y^5 + 6*y^4*a^4*b^2 + 12*y^4*a^3*b*u - 4*y^4*a^2*b + 6*y^4*a^2*u^2 - 2*y^4*a*u + 4*y^4*b - 4*y^3*a^4*b^3 - 12*y^3*a^3*b^2*u + 6*y^3*a^2*b^2 - 12*y^3*a^2*b*u^2 + 6*y^3*a*b*u - 4*y^3*a*u^3 - 6*y^3*b^2 + y^3*u^2 + y^2*a^4*b^4 + 4*y^2*a^3*b^3*u - 4*y^2*a^2*b^3 + 6*y^2*a^2*b^2*u^2 - 6*y^2*a*b^2*u + 4*y^2*a*b*u^3 + 4*y^2*b^3 - 2*y^2*b*u^2 + y^2*u^4 + y*a^2*b^4 + 2*y*a*b^3*u - y*b^4 + y*b^2*u^2 @@ -5479,21 +5495,20 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): INPUT: - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R. = PolynomialRing(QQ) sage: f = 3*x^3 + 2*x*y^2 - sage: exp(f.global_height()) + sage: exp(f.global_height()) # needs sage.symbolic 3.00000000000000 :: + sage: # needs sage.rings.number_field sage: K. = CyclotomicField(3) sage: R. = PolynomialRing(K, sparse=True) sage: f = k*x*y + 1 @@ -5504,10 +5519,10 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: R. = PolynomialRing(QQ) sage: f = 1/25*x^2 + 25/3*x*y + y^2 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 sage: g = 100 * f - sage: g.global_height() + sage: g.global_height() # needs sage.symbolic 6.43775164973640 :: @@ -5516,14 +5531,14 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: K. = NumberField(x^2 + 5) sage: T. = PolynomialRing(K) sage: f = 1/1331 * t^2 + 5 * w + 7 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 9.13959596745043 :: sage: R. = QQ[] sage: f = 1/123*x*y + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: @@ -5559,11 +5574,9 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): - ``v`` -- a prime or prime ideal of the base ring. - ``prec`` -- desired floating point precision (default: - default RealField precision). - - OUTPUT: + default :class:`RealField` precision). - - a real number. + OUTPUT: a real number. EXAMPLES:: @@ -5574,6 +5587,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): :: + sage: # needs sage.rings.number_field sage: R. = QQ[] sage: K. = NumberField(x^2 - 5) sage: T. = K[] @@ -5608,11 +5622,9 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): - ``i`` -- an integer. - ``prec`` -- desired floating point precision (default: - default RealField precision). - - OUTPUT: + default :class:`RealField` precision). - - a real number. + OUTPUT: a real number. EXAMPLES:: @@ -5623,6 +5635,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): :: + sage: # needs sage.rings.number_field sage: R. = QQ[] sage: K. = NumberField(x^2 - 5) sage: T. = K[] diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index acf72a9e175..f61d3103fa8 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -27,13 +27,13 @@ We construct the Frobenius morphism on `\GF{5}[x,y,z]` over `\GF{5}`:: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: frob = R.hom([x^5, y^5, z^5]) # optional - sage.rings.finite_rings - sage: frob(x^2 + 2*y - z^4) # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: frob = R.hom([x^5, y^5, z^5]) + sage: frob(x^2 + 2*y - z^4) -z^20 + x^10 + 2*y^5 - sage: frob((x + 2*y)^3) # optional - sage.rings.finite_rings + sage: frob((x + 2*y)^3) # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 - sage: (x^5 + 2*y^5)^3 # optional - sage.rings.finite_rings + sage: (x^5 + 2*y^5)^3 # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 We make a polynomial ring in one variable over a polynomial ring in @@ -46,7 +46,7 @@ TESTS:: - sage: PolynomialRing(GF(5), 3, 'xyz').objgens() # optional - sage.rings.finite_rings + sage: PolynomialRing(GF(5), 3, 'xyz').objgens() (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5, (x, y, z)) """ @@ -63,8 +63,6 @@ from sage.rings.ring import IntegralDomain import sage.rings.fraction_field_element as fraction_field_element -import sage.rings.polynomial.multi_polynomial_ideal as multi_polynomial_ideal - from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base, is_MPolynomialRing from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polydict import PolyDict, ETuple @@ -72,7 +70,10 @@ import sage.interfaces.abc -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () from sage.structure.element import Element @@ -203,7 +204,7 @@ def __call__(self, x=0, check=True): sage: R. = QQ[] sage: S. = ZZ[] - sage: T. = GF(7)[] # optional - sage.rings.finite_rings + sage: T. = GF(7)[] We convert from integer polynomials to rational polynomials, and back:: @@ -219,9 +220,9 @@ def __call__(self, x=0, check=True): :: - sage: f = R(T.0^2 - 4*T.1^3); f # optional - sage.rings.finite_rings + sage: f = R(T.0^2 - 4*T.1^3); f 3*y^3 + x^2 - sage: parent(f) # optional - sage.rings.finite_rings + sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field We dump and load the polynomial ring S:: @@ -241,24 +242,25 @@ def __call__(self, x=0, check=True): variable names:: sage: R. = PolynomialRing(QQ,2) - sage: S. = PolynomialRing(GF(7),2) # optional - sage.rings.finite_rings + sage: S. = PolynomialRing(GF(7),2) sage: f = x^2 + 2/3*y^3 - sage: S(f) # optional - sage.rings.finite_rings + sage: S(f) 3*b^3 + a^2 Conversion from symbolic variables:: - sage: x,y,z = var('x,y,z') # optional - sage.symbolic - sage: R = QQ['x,y,z'] # optional - sage.symbolic - sage: type(x) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: x,y,z = var('x,y,z') + sage: R = QQ['x,y,z'] + sage: type(x) - sage: type(R(x)) # optional - sage.symbolic + sage: type(R(x)) - sage: f = R(x^3 + y^3 - z^3); f # optional - sage.symbolic + sage: f = R(x^3 + y^3 - z^3); f x^3 + y^3 - z^3 - sage: type(f) # optional - sage.symbolic + sage: type(f) - sage: parent(f) # optional - sage.symbolic + sage: parent(f) Multivariate Polynomial Ring in x, y, z over Rational Field A more complicated symbolic and computational mix. Behind the @@ -266,12 +268,13 @@ def __call__(self, x=0, check=True): :: + sage: # needs sage.symbolic sage: R = QQ['x,y,z'] - sage: f = (x^3 + y^3 - z^3)^10; f # optional - sage.symbolic + sage: f = (x^3 + y^3 - z^3)^10; f (x^3 + y^3 - z^3)^10 - sage: g = R(f); parent(g) # optional - sage.symbolic + sage: g = R(f); parent(g) Multivariate Polynomial Ring in x, y, z over Rational Field - sage: (f - g).expand() # optional - sage.symbolic + sage: (f - g).expand() 0 It intelligently handles conversions from polynomial rings in a subset @@ -279,12 +282,12 @@ def __call__(self, x=0, check=True): :: - sage: R = GF(5)['x,y,z'] # optional - sage.rings.finite_rings + sage: R = GF(5)['x,y,z'] sage: S = ZZ['y'] - sage: R(7*S.0) # optional - sage.rings.finite_rings + sage: R(7*S.0) 2*y sage: T = ZZ['x,z'] - sage: R(2*T.0 + 6*T.1 + T.0*T.1^2) # optional - sage.rings.finite_rings + sage: R(2*T.0 + 6*T.1 + T.0*T.1^2) x*z^2 + 2*x + z :: @@ -375,16 +378,16 @@ def __call__(self, x=0, check=True): sage: A. = PolynomialRing(QQ) sage: B. = PolynomialRing(A) - sage: f = pari(a*d) + sage: f = pari(a*d) # needs sage.libs.pari sage: B(f) a*d - sage: f = pari(a*d - (a+1)*d*e^3 + a*d^2) + sage: f = pari(a*d - (a+1)*d*e^3 + a*d^2) # needs sage.libs.pari sage: B(f) (-a - 1)*d*e^3 + a*d^2 + a*d sage: A. = PolynomialRing(QQ) sage: B. = PolynomialRing(A) - sage: f = pari(a*d) + sage: f = pari(a*d) # needs sage.libs.pari sage: B(f) a*d @@ -402,7 +405,7 @@ def __call__(self, x=0, check=True): Check that :trac:`21999` is fixed:: - sage: R = QQbar['s,t'] + sage: R = QQbar['s,t'] # needs sage.rings.number_field sage: type(R({(1,2): 3}).coefficients()[0]) """ @@ -950,6 +953,9 @@ def ideal(self, *gens, **kwds): if not self._has_singular: # pass through MPolynomialRing_base.ideal(self, gens, **kwds) + + from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal + if isinstance(gens, (sage.interfaces.abc.SingularElement, sage.interfaces.abc.Macaulay2Element)): gens = list(gens) do_coerce = True @@ -957,4 +963,4 @@ def ideal(self, *gens, **kwds): gens = [gens] if ('coerce' in kwds and kwds['coerce']) or do_coerce: gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly! - return multi_polynomial_ideal.MPolynomialIdeal(self, gens, **kwds) + return MPolynomialIdeal(self, gens, **kwds) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 41b2e4c50ee..1d3fbc60944 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -3,8 +3,6 @@ Base class for multivariate polynomial rings """ import itertools from collections.abc import Iterable -from sage.matrix.constructor import matrix -from sage.modules.free_module_element import vector import sage.misc.latex from sage.misc.cachefunc import cached_method @@ -22,12 +20,9 @@ _CommutativeRings = CommutativeRings() from sage.arith.misc import binomial -from sage.combinat.integer_vector import IntegerVectors - from sage.rings.integer_ring import ZZ -from . import (multi_polynomial_ideal, - polynomial_ring) +from . import polynomial_ring from .term_order import TermOrder from .polynomial_ring_constructor import (PolynomialRing, polynomial_default_category) @@ -71,10 +66,10 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Check that :trac:`26958` is fixed:: - sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular # optional - sage.libs.singular - sage: class Foo(MPolynomialRing_libsingular): # optional - sage.libs.singular + sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular # needs sage.libs.singular + sage: class Foo(MPolynomialRing_libsingular): # needs sage.libs.singular ....: pass - sage: Foo(QQ, 2, ['x','y'], 'degrevlex') # optional - sage.libs.singular + sage: Foo(QQ, 2, ['x','y'], 'degrevlex') # needs sage.libs.singular Multivariate Polynomial Ring in x, y over Rational Field """ if base_ring not in _CommutativeRings: @@ -223,9 +218,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: P. = PolynomialRing(ZZ) - sage: P.completion(prec=oo) + sage: P.completion(prec=oo) # needs sage.combinat Multivariate Lazy Taylor Series Ring in x, y, z, w over Integer Ring - sage: P.completion((w,x,y), prec=oo) + sage: P.completion((w,x,y), prec=oo) # needs sage.combinat Multivariate Lazy Taylor Series Ring in w, x, y over Univariate Polynomial Ring in z over Integer Ring @@ -234,7 +229,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: P. = PolynomialRing(ZZ) sage: P.completion([]) is P True - sage: P.completion(SR.var('x')) # optional - sage.symbolic + sage: P.completion(SR.var('x')) # needs sage.symbolic Traceback (most recent call last): ... TypeError: x is not an element of Multivariate Polynomial Ring @@ -395,14 +390,14 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: return a^3*b + b + c^2 + 25 ....: sage: R. = PolynomialRing(QQ) - sage: R.interpolation(4, F) # optional - sage.modules + sage: R.interpolation(4, F) # needs sage.modules x^3*y + z^2 + y + 25 sage: def F(a,b,c): ....: return a^3*b + b + c^2 + 25 ....: sage: R. = PolynomialRing(QQ) - sage: R.interpolation([3,1,2], F) # optional - sage.modules + sage: R.interpolation([3,1,2], F) # needs sage.modules x^3*y + z^2 + y + 25 sage: def F(a,b,c): @@ -413,7 +408,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: (2,7,0),(1,10,13),(0,0,1),(-1,1,0),(2,5,3),(1,1,1),(7,4,11), ....: (12,1,9),(1,1,3),(4,-1,2),(0,1,5),(5,1,3),(3,1,-2),(2,11,3), ....: (4,12,19),(3,1,1),(5,2,-3),(12,1,1),(2,3,4)] - sage: R.interpolation([3,1,2], points, [F(*x) for x in points]) # optional - sage.modules + sage: R.interpolation([3,1,2], points, [F(*x) for x in points]) # needs sage.modules x^3*y + z^2 + y + 25 ALGORITHM: @@ -447,13 +442,16 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: return a^3*b + b + c^2 + 25 ....: sage: R. = PolynomialRing(QQ) - sage: R.interpolation(3, F) # optional - sage.modules + sage: R.interpolation(3, F) # needs sage.modules 1/2*x^3 + x*y + z^2 - 1/2*x + y + 25 .. SEEALSO:: :meth:`lagrange_polynomial` """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + # get ring and number of variables R = self.base_ring() n = self.ngens() @@ -576,14 +574,15 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): This fairly complicated code (from Michel Vandenbergh) ends up implicitly calling ``_coerce_c_impl``:: + sage: # needs sage.rings.number_field sage: z = polygen(QQ, 'z') - sage: W. = NumberField(z^2 + 1) # optional - sage.rings.number_field - sage: Q. = W[] # optional - sage.rings.number_field - sage: W1 = FractionField(Q) # optional - sage.rings.number_field - sage: S. = W1[] # optional - sage.rings.number_field - sage: u + x # optional - sage.rings.number_field + sage: W. = NumberField(z^2 + 1) + sage: Q. = W[] + sage: W1 = FractionField(Q) + sage: S. = W1[] + sage: u + x x + u - sage: x + 1/u # optional - sage.rings.number_field + sage: x + 1/u x + 1/u """ try: @@ -706,19 +705,21 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): return "%s[%s]" % (sage.misc.latex.latex(self.base_ring()), vars) def _ideal_class_(self, n=0): - return multi_polynomial_ideal.MPolynomialIdeal + from .multi_polynomial_ideal import MPolynomialIdeal + return MPolynomialIdeal def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: T. = ZZ[] - sage: K. = NumberField(t^2 + 1) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() # optional - sage.rings.number_field - sage: R._is_valid_homomorphism_(Q5, [Q5.teichmuller(2), Q5(6).log()]) # no coercion # optional - sage.rings.number_field + sage: K. = NumberField(t^2 + 1) + sage: R. = K[] + sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() + sage: R._is_valid_homomorphism_(Q5, [Q5.teichmuller(2), Q5(6).log()]) # no coercion False - sage: R._is_valid_homomorphism_(Q5, [Q5.teichmuller(2), Q5(6).log()], base_map=K.hom([i5])) # optional - sage.rings.number_field + sage: R._is_valid_homomorphism_(Q5, [Q5.teichmuller(2), Q5(6).log()], base_map=K.hom([i5])) True """ if base_map is None: @@ -735,38 +736,39 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: - sage: R. = PolynomialRing(GF(127),10) # optional - sage.rings.finite_rings - sage: R._magma_init_(magma) # optional - magma # optional - sage.rings.finite_rings + sage: # optional - magma + sage: R. = PolynomialRing(GF(127),10) + sage: R._magma_init_(magma) 'SageCreateWithNames(PolynomialRing(_sage_ref...,10,"grevlex"),["a","b","c","d","e","f","g","h","i","j"])' - sage: R. = PolynomialRing(QQ, 3) # optional - sage.rings.finite_rings - sage: magma(R) # optional - magma # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(QQ, 3) + sage: magma(R) Polynomial ring of rank 3 over Rational Field Order: Graded Reverse Lexicographical Variables: y, z, w A complicated nested example:: - sage: R. = PolynomialRing(GF(9,'a')); S. = R[]; S # optional - sage.rings.finite_rings + sage: # optional - magma, needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(9,'a')); S. = R[]; S Multivariate Polynomial Ring in T, W over Multivariate Polynomial Ring in a, b, c over Finite Field in a of size 3^2 - sage: magma(S) # optional - magma # optional - sage.rings.finite_rings + sage: magma(S) Polynomial ring of rank 2 over Polynomial ring of rank 3 over GF(3^2) Order: Graded Reverse Lexicographical Variables: T, W - sage: magma(PolynomialRing(GF(7),4, 'x')) # optional - magma # optional - sage.rings.finite_rings + sage: # optional - magma + sage: magma(PolynomialRing(GF(7),4, 'x')) Polynomial ring of rank 4 over GF(7) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3 - - sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) # optional - magma # optional - sage.rings.finite_rings + sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) # needs sage.rings.finite_rings Polynomial ring of rank 10 over GF(7^2) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 - - sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) # optional - magma + sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) Polynomial ring of rank 3 over Polynomial ring of rank 3 over Integer Ring Order: Graded Reverse Lexicographical @@ -795,11 +797,12 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: - sage: F = CyclotomicField(8) # optional - sage.rings.number_field - sage: P. = F[] # optional - sage.rings.number_field - sage: gap(P) # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: F = CyclotomicField(8) + sage: P. = F[] + sage: gap(P) # indirect doctest PolynomialRing( CF(8), ["x", "y"] ) - sage: libgap(P) # optional - sage.rings.number_field + sage: libgap(P) [x,y] """ L = ['"%s"' % t for t in self.variable_names()] @@ -857,8 +860,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: R = PolynomialRing(QQ, 'x', 3) sage: R.characteristic() 0 - sage: R = PolynomialRing(GF(7), 'x', 20) # optional - sage.rings.finite_rings - sage: R.characteristic() # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(7), 'x', 20) + sage: R.characteristic() 7 """ return self.base_ring().characteristic() @@ -1052,7 +1055,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: return 1.0/(8*total) sage: more_samples() - sage: while any(abs(prob(i) - dic[i]/counter) > 0.01 for i in dic): + sage: while any(abs(prob(i) - dic[i]/counter) > 0.01 for i in dic): # needs sage.symbolic ....: more_samples() """ # bug: doesn't handle n=1 @@ -1175,12 +1178,12 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Default values apply if no degree and/or number of terms is provided:: + sage: # needs sage.modules sage: M = random_matrix(QQ['x,y,z'], 2, 2) sage: all(a.degree() <= 2 for a in M.list()) True sage: all(len(list(a)) <= 5 for a in M.list()) True - sage: M = random_matrix(QQ['x,y,z'], 2, 2, terms=1, degree=2) sage: all(a.degree() <= 2 for a in M.list()) True @@ -1340,11 +1343,11 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: - sage: P. = PolynomialRing(GF(127), 3, order='lex') # optional - sage.rings.finite_rings - sage: x > y^2 # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127), 3, order='lex') + sage: x > y^2 True - sage: Q. = P.change_ring(order='degrevlex') # optional - sage.rings.finite_rings - sage: x > y^2 # optional - sage.rings.finite_rings + sage: Q. = P.change_ring(order='degrevlex') + sage: x > y^2 False """ if base_ring is None: @@ -1382,6 +1385,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: + sage: # needs sage.combinat sage: R. = ZZ[] sage: mons = R.monomials_of_degree(2) sage: mons @@ -1399,7 +1403,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): The number of such monomials equals `\binom{n+k-1}{k}` where `n` is the number of variables and `k` the degree:: - sage: len(mons) == binomial(3 + 2 - 1, 2) + sage: len(mons) == binomial(3 + 2 - 1, 2) # needs sage.combinat True """ deg_of_gens = [x.degree() for x in self.gens()] @@ -1500,6 +1504,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Polynomial Ring in u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11 over Integer Ring) """ + from sage.combinat.integer_vector import IntegerVectors + n = len(dlist) - 1 number_of_coeffs = sum([binomial(n + di, di) for di in dlist]) U = PolynomialRing(ZZ, 'u', number_of_coeffs) @@ -1565,7 +1571,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): The number of polynomials has to match the number of variables:: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant([y, x + z]) # optional - sage.modules + sage: R.macaulay_resultant([y, x + z]) # needs sage.modules Traceback (most recent call last): ... TypeError: number of polynomials(= 2) must equal number of variables (= 3) @@ -1573,7 +1579,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): The polynomials need to be all homogeneous:: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant([y, x + z, z + x^3]) # optional - sage.modules + sage: R.macaulay_resultant([y, x + z, z + x^3]) # needs sage.modules Traceback (most recent call last): ... TypeError: resultant for non-homogeneous polynomials is not supported @@ -1582,7 +1588,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: S. = PolynomialRing(QQ, 2) sage: R. = PolynomialRing(QQ,3) - sage: S.macaulay_resultant([y, z+x]) # optional - sage.modules + sage: S.macaulay_resultant([y, z+x]) # needs sage.modules Traceback (most recent call last): ... TypeError: not all inputs are polynomials in the calling ring @@ -1591,7 +1597,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: K. = PolynomialRing(ZZ, 2) sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,2]) - sage: R.macaulay_resultant(flist) # optional - sage.modules + sage: R.macaulay_resultant(flist) # needs sage.modules u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7 + u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8 + u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - @@ -1604,7 +1610,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: K. = PolynomialRing(ZZ, 2) sage: flist,R = K._macaulay_resultant_universal_polynomials([1,1,1]) - sage: R.macaulay_resultant(flist) # optional - sage.modules + sage: R.macaulay_resultant(flist) # needs sage.modules -u2*u4*u6 + u1*u5*u6 + u2*u3*u7 - u0*u5*u7 - u1*u3*u8 + u0*u4*u8 The following example is by Patrick Ingram (:arxiv:`1310.4114`):: @@ -1615,38 +1621,38 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: f1 = y1*x2^2 - x1^2 + 2*x0*x2 sage: f2 = x0*x1 - x2^2 sage: flist = [f0,f1,f2] - sage: R.macaulay_resultant([f0,f1,f2]) # optional - sage.modules + sage: R.macaulay_resultant([f0,f1,f2]) # needs sage.modules y0^2*y1^2 - 4*y0^3 - 4*y1^3 + 18*y0*y1 - 27 A simple example with constant rational coefficients:: sage: R. = PolynomialRing(QQ, 4) - sage: R.macaulay_resultant([w, z, y, x]) # optional - sage.modules + sage: R.macaulay_resultant([w, z, y, x]) # needs sage.modules 1 An example where the resultant vanishes:: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant([x + y, y^2, x]) # optional - sage.modules + sage: R.macaulay_resultant([x + y, y^2, x]) # needs sage.modules 0 An example of bad reduction at a prime `p = 5`:: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant([y, x^3 + 25*y^2*x, 5*z]) # optional - sage.modules + sage: R.macaulay_resultant([y, x^3 + 25*y^2*x, 5*z]) # needs sage.libs.pari sage.modules 125 The input can given as an unpacked list of polynomials:: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant(y, x^3 + 25*y^2*x, 5*z) # optional - sage.modules + sage: R.macaulay_resultant(y, x^3 + 25*y^2*x, 5*z) # needs sage.libs.pari sage.modules 125 An example when the coefficients live in a finite field:: - sage: F = FiniteField(11) # optional - sage.rings.finite_rings - sage: R. = PolynomialRing(F, 4) # optional - sage.rings.finite_rings - sage: R.macaulay_resultant([z, x^3, 5*y, w]) # optional - sage.modules sage.rings.finite_rings + sage: F = FiniteField(11) + sage: R. = PolynomialRing(F, 4) + sage: R.macaulay_resultant([z, x^3, 5*y, w]) # needs sage.modules sage.rings.finite_rings 4 Example when the denominator in the algorithm vanishes(in this case @@ -1654,7 +1660,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): char polynomials of numerator/denominator):: sage: R. = PolynomialRing(QQ, 3) - sage: R.macaulay_resultant([y, x + z, z^2]) # optional - sage.modules + sage: R.macaulay_resultant([y, x + z, z^2]) # needs sage.libs.pari sage.modules -1 When there are only 2 polynomials, the Macaulay resultant degenerates @@ -1665,12 +1671,13 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: fh = f.homogenize() sage: gh = g.homogenize() sage: RH = fh.parent() - sage: f.resultant(g) == RH.macaulay_resultant([fh, gh]) # optional - sage.modules + sage: f.resultant(g) == RH.macaulay_resultant([fh, gh]) # needs sage.modules True """ from sage.matrix.constructor import matrix from sage.matrix.constructor import zero_matrix + from sage.combinat.integer_vector import IntegerVectors if len(args) == 1 and isinstance(args[0], list): flist = args[0] @@ -1744,9 +1751,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: sage: R = QQ['x,y,z'] - sage: W = R.weyl_algebra(); W # optional - sage.combinat sage.modules + sage: W = R.weyl_algebra(); W # needs sage.modules Differential Weyl algebra of polynomials in x, y, z over Rational Field - sage: W.polynomial_ring() == R # optional - sage.combinat sage.modules + sage: W.polynomial_ring() == R # needs sage.modules True """ from sage.algebras.weyl_algebra import DifferentialWeylAlgebra @@ -1763,8 +1770,8 @@ cdef class BooleanPolynomialRing_base(MPolynomialRing_base): EXAMPLES:: sage: from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: isinstance(R, BooleanPolynomialRing_base) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: isinstance(R, BooleanPolynomialRing_base) # needs sage.rings.polynomial.pbori True By design, there is only one direct implementation subclass:: diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index 8168439c2df..22c92ba44d6 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -23,24 +23,24 @@ As an example consider a small scale variant of the AES:: - sage: sr = mq.SR(2, 1, 2, 4, gf2=True, polybori=True) # optional - sage.rings.polynomial.pbori - sage: sr # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(2, 1, 2, 4, gf2=True, polybori=True) # needs sage.rings.polynomial.pbori + sage: sr # needs sage.rings.polynomial.pbori SR(2,1,2,4) We can construct a polynomial sequence for a random plaintext-ciphertext pair and study it:: - sage: set_random_seed(1) # optional - sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.polynomial.pbori + sage: set_random_seed(1) + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: F # optional - sage.rings.polynomial.pbori + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 112 Polynomials in 64 Variables - sage: r2 = F.part(2); r2 # optional - sage.rings.polynomial.pbori + sage: r2 = F.part(2); r2 # needs sage.rings.polynomial.pbori (w200 + k100 + x100 + x102 + x103, w201 + k101 + x100 + x101 + x103 + 1, w202 + k102 + x100 + x101 + x102 + 1, @@ -76,7 +76,7 @@ We separate the system in independent subsystems:: - sage: C = Sequence(r2).connected_components(); C # optional - sage.rings.polynomial.pbori + sage: C = Sequence(r2).connected_components(); C # needs sage.rings.polynomial.pbori [[w200 + k100 + x100 + x102 + x103, w201 + k101 + x100 + x101 + x103 + 1, w202 + k102 + x100 + x101 + x102 + 1, @@ -109,37 +109,38 @@ x110*w110 + x110*w111 + x110*w112 + x111*w112 + x112*w110 + x112*w111 + x112*w113 + x113*w111 + w112, x110*w111 + x111*w110 + x111*w112 + x112*w110 + x113*w111 + x113*w113 + w113, x110*w112 + x111*w111 + x112*w110 + x113*w113 + 1]] - sage: C[0].groebner_basis() # optional - sage.rings.polynomial.pbori + sage: C[0].groebner_basis() # needs sage.rings.polynomial.pbori Polynomial Sequence with 30 Polynomials in 16 Variables and compute the coefficient matrix:: - sage: A,v = Sequence(r2).coefficient_matrix() # optional - sage.rings.polynomial.pbori - sage: A.rank() # optional - sage.rings.polynomial.pbori + sage: A,v = Sequence(r2).coefficient_matrix() # needs sage.rings.polynomial.pbori + sage: A.rank() # needs sage.rings.polynomial.pbori 32 Using these building blocks we can implement a simple XL algorithm easily:: - sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True, order='lex') # optional - sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True, order='lex') # needs sage.rings.polynomial.pbori + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: monomials = [a*b for a in F.variables() for b in F.variables() if a < b] # optional - sage.rings.polynomial.pbori - sage: len(monomials) # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: monomials = [a*b for a in F.variables() for b in F.variables() if a < b] + sage: len(monomials) 190 - sage: F2 = Sequence(map(mul, cartesian_product_iterator((monomials, F)))) # optional - sage.rings.polynomial.pbori - sage: A, v = F2.coefficient_matrix(sparse=False) # optional - sage.rings.polynomial.pbori - sage: A.echelonize() # optional - sage.rings.polynomial.pbori - sage: A # optional - sage.rings.polynomial.pbori + sage: F2 = Sequence(map(mul, cartesian_product_iterator((monomials, F)))) + sage: A, v = F2.coefficient_matrix(sparse=False) + sage: A.echelonize() + sage: A 6840 x 4474 dense matrix over Finite Field of size 2... - sage: A.rank() # optional - sage.rings.polynomial.pbori + sage: A.rank() 4056 - sage: A[4055] * v # optional - sage.rings.polynomial.pbori + sage: A[4055] * v (k001*k003) TESTS:: @@ -161,22 +162,25 @@ """ from sage.misc.cachefunc import cached_method - from sage.misc.converting_dict import KeyConvertingDict - -from sage.structure.sequence import Sequence_generic - -from sage.rings.infinity import Infinity -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.misc.method_decorator import MethodDecorator from sage.rings.finite_rings.finite_field_base import FiniteField -from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing -from sage.rings.quotient_ring import is_QuotientRing +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.infinity import Infinity from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal +from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.quotient_ring import is_QuotientRing +from sage.structure.sequence import Sequence_generic + + +try: + from sage.interfaces.singular import singular, singular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options +except ImportError: + singular = None + singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator -from sage.interfaces.singular import singular_gb_standard_options -from sage.libs.singular.standard_options import libsingular_gb_standard_options -from sage.interfaces.singular import singular def is_PolynomialSequence(F): """ @@ -220,12 +224,12 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): EXAMPLES:: - sage: P. = PolynomialRing(GF(127), 4) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127), 4) + sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular If a list of tuples is provided, those form the parts:: - sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest # optional - sage.rings.finite_rings + sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -234,12 +238,12 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F.nparts() # optional - sage.rings.finite_rings + sage: F.nparts() # needs sage.libs.singular 2 If an ideal is provided, the generators are used:: - sage: Sequence(I) # optional - sage.rings.finite_rings + sage: Sequence(I) # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -247,22 +251,22 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): If a list of polynomials is provided, the system has only one part:: - sage: F = Sequence(I.gens(), I.ring()); F # optional - sage.rings.finite_rings + sage: F = Sequence(I.gens(), I.ring()); F # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F.nparts() # optional - sage.rings.finite_rings + sage: F.nparts() # needs sage.libs.singular 1 We test that the ring is inferred correctly:: - sage: P. = GF(2)[] # optional - sage.rings.finite_rings + sage: P. = GF(2)[] sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence - sage: PolynomialSequence([1,x,y]).ring() # optional - sage.rings.finite_rings + sage: PolynomialSequence([1,x,y]).ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 - sage: PolynomialSequence([[1,x,y], [0]]).ring() # optional - sage.rings.finite_rings + sage: PolynomialSequence([[1,x,y], [0]]).ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 TESTS: @@ -271,10 +275,10 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): characteristic 2 (see :trac:`19452`):: sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence - sage: F = GF(2) # optional - sage.rings.finite_rings - sage: L. = PowerSeriesRing(F,'t') # optional - sage.rings.finite_rings - sage: R. = PolynomialRing(L,'x,y') # optional - sage.rings.finite_rings - sage: PolynomialSequence([0], R) # optional - sage.rings.finite_rings + sage: F = GF(2) + sage: L. = PowerSeriesRing(F,'t') + sage: R. = PolynomialRing(L,'x,y') + sage: PolynomialSequence([0], R) [0] A PolynomialSequence can be created from an iterator (see :trac:`25989`):: @@ -288,7 +292,10 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): [x, y, z] """ from sage.structure.element import is_Matrix - from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid + try: + from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid + except ImportError: + BooleanMonomialMonoid = () is_ring = lambda r: is_MPolynomialRing(r) or isinstance(r, BooleanMonomialMonoid) or (is_QuotientRing(r) and is_MPolynomialRing(r.cover_ring())) @@ -386,23 +393,23 @@ def __init__(self, parts, ring, immutable=False, cr=False, cr_str=None): EXAMPLES:: - sage: P. = PolynomialRing(GF(127), 4) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127), 4) + sage: I = sage.rings.ideal.Katsura(P) # needs sage.rings.finite_rings - sage: Sequence([I.gens()], I.ring()) # indirect doctest # optional - sage.rings.finite_rings + sage: Sequence([I.gens()], I.ring()) # indirect doctest # needs sage.rings.finite_rings [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If an ideal is provided, the generators are used.:: - sage: Sequence(I) # optional - sage.rings.finite_rings + sage: Sequence(I) # needs sage.rings.finite_rings [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If a list of polynomials is provided, the system has only one part.:: - sage: Sequence(I.gens(), I.ring()) # optional - sage.rings.finite_rings + sage: Sequence(I.gens(), I.ring()) # needs sage.rings.finite_rings [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] """ @@ -418,11 +425,12 @@ def __copy__(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: copy(F) # indirect doctest # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) + sage: F,s = sr.polynomial_system() + sage: copy(F) # indirect doctest Polynomial Sequence with 40 Polynomials in 20 Variables - sage: type(F) == type(copy(F)) # optional - sage.rings.polynomial.pbori + sage: type(F) == type(copy(F)) True """ return self.__class__(self._parts, self._ring, immutable=self.is_immutable()) @@ -433,9 +441,9 @@ def ring(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True, gf2=True, order='block') # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: print(F.ring().repr_long()) # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True, order='block') # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: print(F.ring().repr_long()) # needs sage.rings.polynomial.pbori Polynomial Ring Base Ring : Finite Field of size 2 Size : 20 Variables @@ -454,9 +462,9 @@ def nparts(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: F.nparts() # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nparts() # needs sage.rings.polynomial.pbori 4 """ return len(self._parts) @@ -467,10 +475,11 @@ def parts(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: l = F.parts() # optional - sage.rings.polynomial.pbori - sage: len(l) # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) + sage: F, s = sr.polynomial_system() + sage: l = F.parts() + sage: len(l) 4 """ return tuple(self._parts) @@ -481,10 +490,11 @@ def part(self, i): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: R0 = F.part(1) # optional - sage.rings.polynomial.pbori - sage: R0 # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) + sage: F, s = sr.polynomial_system() + sage: R0 = F.part(1) + sage: R0 (k000^2 + k001, k001^2 + k002, k002^2 + k003, k003^2 + k000) """ return self._parts[i] @@ -495,14 +505,15 @@ def ideal(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: P = F.ring() # optional - sage.rings.polynomial.pbori - sage: I = F.ideal() # optional - sage.rings.polynomial.pbori - sage: J = I.elimination_ideal(P.gens()[4:-4]) # optional - sage.rings.polynomial.pbori - sage: J <= I # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) + sage: F, s = sr.polynomial_system() + sage: P = F.ring() + sage: I = F.ideal() + sage: J = I.elimination_ideal(P.gens()[4:-4]) + sage: J <= I True - sage: set(J.gens().variables()).issubset(P.gens()[:4] + P.gens()[-4:]) # optional - sage.rings.polynomial.pbori + sage: set(J.gens().variables()).issubset(P.gens()[:4] + P.gens()[-4:]) True """ return self._ring.ideal(tuple(self)) @@ -522,10 +533,11 @@ def groebner_basis(self, *args, **kwargs): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: gb = F.groebner_basis() # optional - sage.rings.polynomial.pbori - sage: Ideal(gb).basis_is_groebner() # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) + sage: F, s = sr.polynomial_system() + sage: gb = F.groebner_basis() + sage: Ideal(gb).basis_is_groebner() True TESTS: @@ -533,12 +545,13 @@ def groebner_basis(self, *args, **kwargs): Check that this method also works for boolean polynomials (:trac:`10680`):: - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: F0 = Sequence(map(lambda f: f.lm(), [a,b,c,d])) # optional - sage.rings.polynomial.pbori - sage: F0.groebner_basis() # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() + sage: F0 = Sequence(map(lambda f: f.lm(), [a,b,c,d])) + sage: F0.groebner_basis() [a, b, c, d] - sage: F1 = Sequence([a,b,c*d,d^2]) # optional - sage.rings.polynomial.pbori - sage: F1.groebner_basis() # optional - sage.rings.polynomial.pbori + sage: F1 = Sequence([a,b,c*d,d^2]) + sage: F1.groebner_basis() [a, b, d] """ return self.ideal().groebner_basis(*args, **kwargs) @@ -549,9 +562,9 @@ def monomials(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: len(F.monomials()) # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: len(F.monomials()) # needs sage.rings.polynomial.pbori 49 """ M = set() @@ -566,9 +579,9 @@ def nmonomials(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: F.nmonomials() # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nmonomials() # needs sage.rings.polynomial.pbori 49 """ return len(self.monomials()) @@ -580,9 +593,9 @@ def variables(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: F.variables()[:10] # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.variables()[:10] # needs sage.rings.polynomial.pbori (k003, k002, k001, k000, s003, s002, s001, s000, w103, w102) """ V = set() @@ -597,9 +610,9 @@ def nvariables(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: F.nvariables() # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nvariables() # needs sage.rings.polynomial.pbori 20 """ return len(self.variables()) @@ -640,13 +653,13 @@ def algebraic_dependence(self): :: - sage: R. = PolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) # optional - sage.rings.finite_rings - sage: I = S.algebraic_dependence(); I # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(7)) + sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) + sage: I = S.algebraic_dependence(); I # needs sage.rings.finite_rings Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7 - sage: [F(S) for F in I.gens()] # optional - sage.rings.finite_rings + sage: [F(S) for F in I.gens()] # needs sage.rings.finite_rings [0] .. NOTE:: @@ -707,23 +720,22 @@ def coefficient_matrix(self, sparse=True): EXAMPLES:: - sage: P. = PolynomialRing(GF(127), 4) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings - sage: I.gens() # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(127), 4) + sage: I = sage.rings.ideal.Katsura(P) + sage: I.gens() [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - - sage: F = Sequence(I) # optional - sage.rings.finite_rings - sage: A,v = F.coefficient_matrix() # optional - sage.rings.finite_rings - sage: A # optional - sage.rings.finite_rings + sage: F = Sequence(I) + sage: A,v = F.coefficient_matrix() + sage: A [ 0 0 0 0 0 0 0 0 0 1 2 2 2 126] [ 1 0 2 0 0 2 0 0 2 126 0 0 0 0] [ 0 2 0 0 2 0 0 2 0 0 126 0 0 0] [ 0 0 1 2 0 0 2 0 0 0 0 126 0 0] - - sage: v # optional - sage.rings.finite_rings + sage: v [a^2] [a*b] [b^2] @@ -738,8 +750,7 @@ def coefficient_matrix(self, sparse=True): [ c] [ d] [ 1] - - sage: A*v # optional - sage.rings.finite_rings + sage: A*v [ a + 2*b + 2*c + 2*d - 1] [a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a] [ 2*a*b + 2*b*c + 2*c*d - b] @@ -779,10 +790,10 @@ def subs(self, *args, **kwargs): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) # optional - sage.rings.polynomial.pbori - sage: F, s = sr.polynomial_system(); F # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 40 Polynomials in 20 Variables - sage: F = F.subs(s); F # optional - sage.rings.polynomial.pbori + sage: F = F.subs(s); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 40 Polynomials in 16 Variables """ return PolynomialSequence(self._ring, [tuple([f.subs(*args,**kwargs) for f in r]) for r in self._parts]) @@ -793,14 +804,15 @@ def _singular_(self): EXAMPLES:: - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings - sage: F = Sequence(I); F # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(127)) + sage: I = sage.rings.ideal.Katsura(P) + sage: F = Sequence(I); F [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F._singular_() # optional - sage.rings.finite_rings + sage: F._singular_() a+2*b+2*c+2*d-1, a^2+2*b^2+2*c^2+2*d^2-a, 2*a*b+2*b*c+2*c*d-b, @@ -815,10 +827,11 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system() # optional - sage.rings.polynomial.pbori - sage: F.set_immutable() # optional - sage.rings.polynomial.pbori - sage: magma(F) # indirect doctest; optional - magma # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) + sage: F,s = sr.polynomial_system() + sage: F.set_immutable() + sage: magma(F) # optional - magma Ideal of Boolean polynomial ring of rank 20 over GF(2) Order: Graded Lexicographical (bit vector word) Variables: k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003, k000, k001, k002, k003 @@ -837,9 +850,10 @@ def _repr_(self): EXAMPLES:: - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings - sage: F = Sequence(I); F # indirect doctest # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(127)) + sage: I = sage.rings.ideal.Katsura(P) + sage: F = Sequence(I); F # indirect doctest [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -848,8 +862,8 @@ def _repr_(self): If the system contains 20 or more polynomials, a short summary is printed:: - sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # optional - sage.rings.polynomial.pbori - sage: F,s = sr.polynomial_system(); F # optional - sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables """ @@ -865,24 +879,23 @@ def __add__(self, right): EXAMPLES:: - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings - sage: F = Sequence(I) # optional - sage.rings.finite_rings - sage: F + [a^127 + a] # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(127)) + sage: I = sage.rings.ideal.Katsura(P) + sage: F = Sequence(I) + sage: F + [a^127 + a] [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a^127 + a] - - sage: F + P.ideal([a^127 + a]) # optional - sage.rings.finite_rings + sage: F + P.ideal([a^127 + a]) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a^127 + a] - - sage: F + Sequence([a^127 + a], P) # optional - sage.rings.finite_rings + sage: F + Sequence([a^127 + a], P) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -909,35 +922,37 @@ def connection_graph(self): EXAMPLES:: - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: F = Sequence([x*y + y + 1, z + 1]) # optional - sage.rings.polynomial.pbori - sage: G = F.connection_graph(); G # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() + sage: F = Sequence([x*y + y + 1, z + 1]) + sage: G = F.connection_graph(); G Graph on 3 vertices - sage: G.is_connected() # optional - sage.rings.polynomial.pbori + sage: G.is_connected() False - sage: F = Sequence([x]) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([x]) + sage: F.connection_graph() Graph on 1 vertex TESTS:: - sage: F = Sequence([], B) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph() # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: F = Sequence([], B) + sage: F.connection_graph() Graph on 0 vertices - sage: F = Sequence([1], B) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([1], B) + sage: F.connection_graph() Graph on 0 vertices - sage: F = Sequence([x]) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([x]) + sage: F.connection_graph() Graph on 1 vertex - sage: F = Sequence([x, y]) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([x, y]) + sage: F.connection_graph() Graph on 2 vertices - sage: F = Sequence([x*y*z]) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph().is_clique() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([x*y*z]) + sage: F.connection_graph().is_clique() True - sage: F = Sequence([x*y, y*z]) # optional - sage.rings.polynomial.pbori - sage: F.connection_graph().is_clique() # optional - sage.rings.polynomial.pbori + sage: F = Sequence([x*y, y*z]) + sage: F.connection_graph().is_clique() False """ from sage.graphs.graph import Graph @@ -956,15 +971,16 @@ def connected_components(self): As an example consider one part of AES, which naturally splits into four subsystems which are independent:: - sage: sr = mq.SR(2, 4, 4, 8, gf2=True, polybori=True) # optional - sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(2, 4, 4, 8, gf2=True, polybori=True) + sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: Fz = Sequence(F.part(2)) # optional - sage.rings.polynomial.pbori - sage: Fz.connected_components() # optional - sage.rings.polynomial.pbori + sage: Fz = Sequence(F.part(2)) + sage: Fz.connected_components() [Polynomial Sequence with 128 Polynomials in 128 Variables, Polynomial Sequence with 128 Polynomials in 128 Variables, Polynomial Sequence with 128 Polynomials in 128 Variables, @@ -1010,9 +1026,9 @@ def _groebner_strategy(self): EXAMPLES:: - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: F = Sequence([x*y + z, y + z + 1]) # optional - sage.rings.finite_rings - sage: F._groebner_strategy() # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127)) + sage: F = Sequence([x*y + z, y + z + 1]) + sage: F._groebner_strategy() # needs sage.libs.singular Groebner Strategy for ideal generated by 2 elements over Multivariate Polynomial Ring in x, y, z over Finite Field of size 127 """ @@ -1025,13 +1041,13 @@ def maximal_degree(self): EXAMPLES:: - sage: P. = PolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: F = Sequence([x*y + x, x]) # optional - sage.rings.finite_rings - sage: F.maximal_degree() # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(7)) + sage: F = Sequence([x*y + x, x]) + sage: F.maximal_degree() 2 - sage: P. = PolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: F = Sequence([], universe=P) # optional - sage.rings.finite_rings - sage: F.maximal_degree() # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(7)) + sage: F = Sequence([], universe=P) + sage: F.maximal_degree() -1 """ @@ -1044,15 +1060,15 @@ def __reduce__(self): """ TESTS:: - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: F = Sequence([x*y + z, y + z + 1]) # optional - sage.rings.finite_rings - sage: loads(dumps(F)) == F # indirect doctest # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127)) + sage: F = Sequence([x*y + z, y + z + 1]) + sage: loads(dumps(F)) == F True We check that :trac:`26354` is fixed:: - sage: f = P.hom([y,z,x]) # optional - sage.rings.finite_rings - sage: hash(f) == hash(loads(dumps(f))) # optional - sage.rings.finite_rings + sage: f = P.hom([y,z,x]) + sage: hash(f) == hash(loads(dumps(f))) True """ @@ -1124,7 +1140,7 @@ def reduced(self): Check that :trac:`26952` is fixed:: sage: Qp = pAdicField(2) - sage: R. = PolynomialRing(Qp, implementation="generic") + sage: R. = PolynomialRing(Qp, implementation="generic") # needs sage.rings.padics sage: F = Sequence([z*x+y^3,z+y^3,3*z+x*y]) sage: F.reduced() [y^3 + z, x*y + (1 + 2 + O(2^20))*z, x*z - z] @@ -1171,12 +1187,12 @@ def is_groebner(self, singular=singular): EXAMPLES:: - sage: R. = PolynomialRing(GF(127), 10) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Cyclic(R, 4) # optional - sage.rings.finite_rings - sage: I.basis.is_groebner() # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R, 4) + sage: I.basis.is_groebner() False - sage: I2 = Ideal(I.groebner_basis()) # optional - sage.rings.finite_rings - sage: I2.basis.is_groebner() # optional - sage.rings.finite_rings + sage: I2 = Ideal(I.groebner_basis()) + sage: I2.basis.is_groebner() True """ @@ -1235,37 +1251,38 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc EXAMPLES:: - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) # optional - sage.rings.polynomial.pbori - sage: F.eliminate_linear_variables() # everything vanishes # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() + sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) + sage: F.eliminate_linear_variables() # everything vanishes [] - sage: F.eliminate_linear_variables(maxlength=2) # optional - sage.rings.polynomial.pbori + sage: F.eliminate_linear_variables(maxlength=2) [b + c + d + 1, b*c + b*d + c, b*c*d + c] - sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') # optional - sage.rings.polynomial.pbori + sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] The list of reductors can be requested by setting ``return_reductors`` to ``True``:: - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: F = Sequence([a + b + d, a + b + c]) # optional - sage.rings.polynomial.pbori - sage: F, R = F.eliminate_linear_variables(return_reductors=True) # optional - sage.rings.polynomial.pbori - sage: F # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() + sage: F = Sequence([a + b + d, a + b + c]) + sage: F, R = F.eliminate_linear_variables(return_reductors=True) + sage: F [] - sage: R # optional - sage.rings.polynomial.pbori + sage: R [a + b + d, c + d] If the input system is detected to be inconsistent then ``[1]`` is returned, and the list of reductors is empty:: - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # optional - sage.rings.polynomial.pbori - sage: S.eliminate_linear_variables() # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables() # needs sage.rings.polynomial.pbori [1] - - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # optional - sage.rings.polynomial.pbori - sage: S.eliminate_linear_variables(return_reductors=True) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori ([1], []) @@ -1273,30 +1290,29 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc The function should really dispose of linear equations (:trac:`13968`):: - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x + y + z + 1, y + z]) # optional - sage.rings.polynomial.pbori - sage: S.eliminate_linear_variables(return_reductors=True) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x + y + z + 1, y + z]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori ([], [x + 1, y + z]) The function should take care of linear variables created by previous substitution of linear variables :: - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y]) # optional - sage.rings.polynomial.pbori - sage: S.eliminate_linear_variables(return_reductors=True) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori ([], [x + y, z + 1]) We test a case which would increase the degree with ``polybori=True``:: - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: f = a*d + a + b*d + c*d + 1 # optional - sage.rings.polynomial.pbori - sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables() # optional - sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: f = a*d + a + b*d + c*d + 1 # needs sage.rings.polynomial.pbori + sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables() # needs sage.rings.polynomial.pbori [a*d + a + b*d + c*d + 1, a + b*c + c + d + 1] - - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: f = a*d + a + b*d + c*d + 1 # optional - sage.rings.polynomial.pbori - sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables(use_polybori=True) # optional - sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: f = a*d + a + b*d + c*d + 1 # needs sage.rings.polynomial.pbori + sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables(use_polybori=True) # needs sage.rings.polynomial.pbori [b*c*d + b*c + b*d + c + d] .. NOTE:: @@ -1377,15 +1393,16 @@ def _groebner_strategy(self): EXAMPLES:: - sage: P. = PolynomialRing(GF(2)) # optional - sage.rings.finite_rings - sage: F = Sequence([x*y + z, y + z + 1]) # optional - sage.rings.finite_rings - sage: F._groebner_strategy() # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(2)) + sage: F = Sequence([x*y + z, y + z + 1]) + sage: F._groebner_strategy() Groebner Strategy for ideal generated by 2 elements over Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 - sage: P. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: F = Sequence([x*y + z, y + z + 1]) # optional - sage.rings.polynomial.pbori - sage: F._groebner_strategy() # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: P. = BooleanPolynomialRing() + sage: F = Sequence([x*y + z, y + z + 1]) + sage: F._groebner_strategy() """ from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base @@ -1440,64 +1457,66 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver Without argument, a single arbitrary solution is returned:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.doctest.fixtures import reproducible_repr - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) # optional - sage.rings.polynomial.pbori - sage: sol = S.solve() # optional - sage.rings.polynomial.pbori - sage: print(reproducible_repr(sol)) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() + sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) + sage: sol = S.solve() + sage: print(reproducible_repr(sol)) [{x: 0, y: 1, z: 0}] We check that it is actually a solution:: - sage: S.subs(sol[0]) # optional - sage.rings.polynomial.pbori + sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori [0, 0, 0] We obtain all solutions:: - sage: sols = S.solve(n=Infinity) # optional - sage.rings.polynomial.pbori - sage: print(reproducible_repr(sols)) # optional - sage.rings.polynomial.pbori + sage: sols = S.solve(n=Infinity) # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sols)) # needs sage.rings.polynomial.pbori [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] - sage: [S.subs(x) for x in sols] # optional - sage.rings.polynomial.pbori + sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori [[0, 0, 0], [0, 0, 0]] We can force the use of exhaustive search if the optional package ``FES`` is present:: - sage: sol = S.solve(algorithm='exhaustive_search') # optional - FES # optional - sage.rings.polynomial.pbori - sage: print(reproducible_repr(sol)) # optional - FES # optional - sage.rings.polynomial.pbori + sage: sol = S.solve(algorithm='exhaustive_search') # optional - fes # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sol)) # optional - fes # needs sage.rings.polynomial.pbori [{x: 1, y: 1, z: 1}] - sage: S.subs(sol[0]) # optional - FES # optional - sage.rings.polynomial.pbori + sage: S.subs(sol[0]) # optional - fes # needs sage.rings.polynomial.pbori [0, 0, 0] And we may use SAT-solvers if they are available:: - sage: sol = S.solve(algorithm='sat') # optional - pycryptosat # optional - sage.rings.polynomial.pbori - sage: print(reproducible_repr(sol)) # optional - pycryptosat # optional - sage.rings.polynomial.pbori + sage: sol = S.solve(algorithm='sat') # optional - pycryptosat # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sol)) # optional - pycryptosat # needs sage.rings.polynomial.pbori [{x: 0, y: 1, z: 0}] - sage: S.subs(sol[0]) # optional - sage.rings.polynomial.pbori + sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori [0, 0, 0] TESTS: Make sure that variables not occurring in the equations are no problem:: - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) # optional - sage.rings.polynomial.pbori - sage: sols = S.solve(n=Infinity) # optional - sage.rings.polynomial.pbori - sage: [S.subs(x) for x in sols] # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() + sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) + sage: sols = S.solve(n=Infinity) + sage: [S.subs(x) for x in sols] [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] Not eliminating linear variables:: - sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) # optional - sage.rings.polynomial.pbori - sage: [S.subs(x) for x in sols] # optional - sage.rings.polynomial.pbori + sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) # needs sage.rings.polynomial.pbori + sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] A tricky case where the linear equations are insatisfiable:: - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # optional - sage.rings.polynomial.pbori - sage: S.solve() # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # needs sage.rings.polynomial.pbori + sage: S.solve() # needs sage.rings.polynomial.pbori [] """ @@ -1575,17 +1594,18 @@ def reduced(self): EXAMPLES:: - sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # optional - sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) + sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: g = F.reduced() # optional - sage.rings.polynomial.pbori - sage: len(g) == len(set(gi.lt() for gi in g)) # optional - sage.rings.polynomial.pbori + sage: g = F.reduced() + sage: len(g) == len(set(gi.lt() for gi in g)) True - sage: for i in range(len(g)): # optional - sage.rings.polynomial.pbori + sage: for i in range(len(g)): ....: for j in range(len(g)): ....: if i == j: ....: continue @@ -1623,27 +1643,29 @@ def weil_restriction(self): EXAMPLES:: - sage: k. = GF(2^2) # optional - sage.rings.finite_rings - sage: P. = PolynomialRing(k, 2) # optional - sage.rings.finite_rings - sage: a = P.base_ring().gen() # optional - sage.rings.finite_rings - sage: F = Sequence([x*y + 1, a*x + 1], P) # optional - sage.rings.finite_rings - sage: F2 = F.weil_restriction() # optional - sage.rings.finite_rings - sage: F2 # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(2^2) + sage: P. = PolynomialRing(k, 2) + sage: a = P.base_ring().gen() + sage: F = Sequence([x*y + 1, a*x + 1], P) + sage: F2 = F.weil_restriction() + sage: F2 [x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + x0, x1^2 + x1, y0^2 + y0, y1^2 + y1] Another bigger example for a small scale AES:: - sage: sr = mq.SR(1, 1, 1, 4, gf2=False) # optional - sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(1, 1, 1, 4, gf2=False) + sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: F # optional - sage.rings.polynomial.pbori + sage: F Polynomial Sequence with 40 Polynomials in 20 Variables - sage: F2 = F.weil_restriction(); F2 # optional - sage.rings.polynomial.pbori + sage: F2 = F.weil_restriction(); F2 Polynomial Sequence with 240 Polynomials in 80 Variables """ from sage.rings.ideal import FieldIdeal diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index f2ab5232b2e..5f5dfb441e7 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -877,6 +877,7 @@ def _Omega_factors_denominator_(x, y): :: + sage: # needs sage.rings.number_field sage: B. = ZZ.extension(cyclotomic_polynomial(3)) sage: L. = LaurentPolynomialRing(B) sage: _Omega_factors_denominator_(((x, -x),), ((y,),)) diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 5b19d50dc3d..d67c63b6be8 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -161,48 +161,50 @@ cdef class OrePolynomial(AlgebraElement): Here is another example over a finite field:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = x^4 + (4*t + 1)*x^3 + (t^2 + 3*t + 3)*x^2 + (3*t^2 + 2*t + 2)*x + (3*t^2 + 3*t + 1) # optional - sage.rings.finite_rings - sage: b = (2*t^2 + 3)*x^2 + (3*t^2 + 1)*x + 4*t + 2 # optional - sage.rings.finite_rings - sage: q, r = a.left_quo_rem(b) # optional - sage.rings.finite_rings - sage: q # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^4 + (4*t + 1)*x^3 + (t^2 + 3*t + 3)*x^2 + (3*t^2 + 2*t + 2)*x + (3*t^2 + 3*t + 1) + sage: b = (2*t^2 + 3)*x^2 + (3*t^2 + 1)*x + 4*t + 2 + sage: q, r = a.left_quo_rem(b) + sage: q (4*t^2 + t + 1)*x^2 + (2*t^2 + 2*t + 2)*x + 2*t^2 + 4*t + 3 - sage: r # optional - sage.rings.finite_rings + sage: r (t + 2)*x + 3*t^2 + 2*t + 4 - sage: a == b*q + r # optional - sage.rings.finite_rings + sage: a == b*q + r True Once we have Euclidean divisions, we have for free gcd and lcm (at least if the base ring is a field):: - sage: a = (x + t) * (x + t^2)^2 # optional - sage.rings.finite_rings - sage: b = (x + t) * (t*x + t + 1) * (x + t^2) # optional - sage.rings.finite_rings - sage: a.right_gcd(b) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: a = (x + t) * (x + t^2)^2 + sage: b = (x + t) * (t*x + t + 1) * (x + t^2) + sage: a.right_gcd(b) x + t^2 - sage: a.left_gcd(b) # optional - sage.rings.finite_rings + sage: a.left_gcd(b) x + t The left lcm has the following meaning: given Ore polynomials `a` and `b`, their left lcm is the least degree polynomial `c = ua = vb` for some Ore polynomials `u, v`. Such a `c` always exist if the base ring is a field:: - sage: c = a.left_lcm(b); c # optional - sage.rings.finite_rings + sage: c = a.left_lcm(b); c # needs sage.rings.finite_rings x^5 + (4*t^2 + t + 3)*x^4 + (3*t^2 + 4*t)*x^3 + 2*t^2*x^2 + (2*t^2 + t)*x + 4*t^2 + 4 - sage: c.is_right_divisible_by(a) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(a) # needs sage.rings.finite_rings True - sage: c.is_right_divisible_by(b) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(b) # needs sage.rings.finite_rings True The right lcm is defined similarly as the least degree polynomial `c = au = bv` for some `u,v`:: - sage: d = a.right_lcm(b); d # optional - sage.rings.finite_rings + sage: d = a.right_lcm(b); d # needs sage.rings.finite_rings x^5 + (t^2 + 1)*x^4 + (3*t^2 + 3*t + 3)*x^3 + (3*t^2 + t + 2)*x^2 + (4*t^2 + 3*t)*x + 4*t + 4 - sage: d.is_left_divisible_by(a) # optional - sage.rings.finite_rings + sage: d.is_left_divisible_by(a) # needs sage.rings.finite_rings True - sage: d.is_left_divisible_by(b) # optional - sage.rings.finite_rings + sage: d.is_left_divisible_by(b) # needs sage.rings.finite_rings True .. SEEALSO:: @@ -287,11 +289,12 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: OrePolynomialBaseringInjection(k, k['x', Frob]) #indirect doctest # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: OrePolynomialBaseringInjection(k, k['x', Frob]) #indirect doctest Ore Polynomial base injection morphism: From: Finite Field in t of size 5^3 To: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 @@ -309,11 +312,12 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k. = GF(5^3) - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = x + t # optional - sage.rings.finite_rings - sage: a[1] = t + 1 # optional - sage.rings.finite_rings + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x + t + sage: a[1] = t + 1 Traceback (most recent call last): ... IndexError: Ore polynomials are immutable @@ -481,26 +485,28 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 # optional - sage.rings.finite_rings - sage: b = a.left_monic(); b # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 + sage: b = a.left_monic(); b x^3 + (4*t^2 + 3*t)*x^2 + (4*t + 2)*x + 2*t^2 + 4*t + 3 Check list:: - sage: b.degree() == a.degree() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: b.degree() == a.degree() True - sage: a.is_left_divisible_by(b) # optional - sage.rings.finite_rings + sage: a.is_left_divisible_by(b) True - sage: twist = S.twisting_morphism(-a.degree()) # optional - sage.rings.finite_rings - sage: a == b * twist(a.leading_coefficient()) # optional - sage.rings.finite_rings + sage: twist = S.twisting_morphism(-a.degree()) + sage: a == b * twist(a.leading_coefficient()) True Note that `b` does not divide `a` on the right:: - sage: a.is_right_divisible_by(b) # optional - sage.rings.finite_rings + sage: a.is_right_divisible_by(b) # needs sage.rings.finite_rings False This function does not work if the leading coefficient is not a @@ -534,25 +540,26 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 # optional - sage.rings.finite_rings - sage: b = a.right_monic(); b # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 + sage: b = a.right_monic(); b x^3 + (2*t^2 + 3*t + 4)*x^2 + (3*t^2 + 4*t + 1)*x + 2*t^2 + 4*t + 3 Check list:: - sage: b.degree() == a.degree() # optional - sage.rings.finite_rings + sage: b.degree() == a.degree() # needs sage.rings.finite_rings True - sage: a.is_right_divisible_by(b) # optional - sage.rings.finite_rings + sage: a.is_right_divisible_by(b) # needs sage.rings.finite_rings True - sage: a == a.leading_coefficient() * b # optional - sage.rings.finite_rings + sage: a == a.leading_coefficient() * b # needs sage.rings.finite_rings True Note that `b` does not divide `a` on the right:: - sage: a.is_left_divisible_by(b) # optional - sage.rings.finite_rings + sage: a.is_left_divisible_by(b) # needs sage.rings.finite_rings False This function does not work if the leading coefficient is not a @@ -632,13 +639,14 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: R. = GF(11)[] # optional - sage.rings.finite_rings - sage: der = R.derivation() # optional - sage.rings.finite_rings - sage: S. = R['x', der] # optional - sage.rings.finite_rings - sage: f = t/x # optional - sage.rings.finite_rings - sage: f # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(11)[] + sage: der = R.derivation() + sage: S. = R['x', der] + sage: f = t/x + sage: f (x + 10/t)^(-1) * t - sage: f.parent() # optional - sage.rings.finite_rings + sage: f.parent() Ore Function Field in x over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 11 twisted by d/dt """ @@ -694,20 +702,21 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = x^2 + t*x + t^2 + 3 # optional - sage.rings.finite_rings - sage: b = x^3 + (t + 1)*x^2 + 1 # optional - sage.rings.finite_rings - sage: c = a*b # optional - sage.rings.finite_rings - sage: c.is_right_divisible_by(a) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^2 + t*x + t^2 + 3 + sage: b = x^3 + (t + 1)*x^2 + 1 + sage: c = a*b + sage: c.is_right_divisible_by(a) False - sage: c.is_right_divisible_by(b) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(b) True Divisibility by `0` does not make sense:: - sage: c.is_right_divisible_by(S(0)) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(S(0)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -743,20 +752,21 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = x^2 + t*x + t^2 + 3 # optional - sage.rings.finite_rings - sage: b = x^3 + (t + 1)*x^2 + 1 # optional - sage.rings.finite_rings - sage: c = a * b # optional - sage.rings.finite_rings - sage: a.left_divides(c) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^2 + t*x + t^2 + 3 + sage: b = x^3 + (t + 1)*x^2 + 1 + sage: c = a * b + sage: a.left_divides(c) True - sage: b.left_divides(c) # optional - sage.rings.finite_rings + sage: b.left_divides(c) False Divisibility by `0` does not make sense:: - sage: S(0).left_divides(c) # optional - sage.rings.finite_rings + sage: S(0).left_divides(c) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -778,20 +788,21 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = x^2 + t*x + t^2 + 3 # optional - sage.rings.finite_rings - sage: b = x^3 + (t + 1)*x^2 + 1 # optional - sage.rings.finite_rings - sage: c = a * b # optional - sage.rings.finite_rings - sage: a.right_divides(c) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^2 + t*x + t^2 + 3 + sage: b = x^3 + (t + 1)*x^2 + 1 + sage: c = a * b + sage: a.right_divides(c) False - sage: b.right_divides(c) # optional - sage.rings.finite_rings + sage: b.right_divides(c) True Divisibility by `0` does not make sense:: - sage: S(0).right_divides(c) # optional - sage.rings.finite_rings + sage: S(0).right_divides(c) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -856,21 +867,22 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x + t) * (x^2 + t*x + 1) # optional - sage.rings.finite_rings - sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) # optional - sage.rings.finite_rings - sage: g,u,v = a.left_xgcd(b); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x + t) * (x^2 + t*x + 1) + sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) + sage: g,u,v = a.left_xgcd(b); g x + t - sage: a*u + b*v == g # optional - sage.rings.finite_rings + sage: a*u + b*v == g True Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: g,u,v = a.left_xgcd(b, monic=False); g # optional - sage.rings.finite_rings + sage: g,u,v = a.left_xgcd(b, monic=False); g # needs sage.rings.finite_rings 2*t*x + 4*t + 2 - sage: a*u + b*v == g # optional - sage.rings.finite_rings + sage: a*u + b*v == g # needs sage.rings.finite_rings True The base ring must be a field:: @@ -959,13 +971,14 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 # optional - sage.rings.finite_rings - sage: b = (3*t^2 + 4*t + 2)*x^2 + (2*t^2 + 4*t + 3)*x + 2*t^2 + t + 1 # optional - sage.rings.finite_rings - sage: q,r = a.left_quo_rem(b) # optional - sage.rings.finite_rings - sage: a == b*q + r # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 + sage: b = (3*t^2 + 4*t + 2)*x^2 + (2*t^2 + 4*t + 3)*x + 2*t^2 + t + 1 + sage: q,r = a.left_quo_rem(b) + sage: a == b*q + r True In the following example, Sage does not know the inverse @@ -1088,21 +1101,22 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x^2 + t*x + 1) * (x + t) # optional - sage.rings.finite_rings - sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) # optional - sage.rings.finite_rings - sage: g,u,v = a.right_xgcd(b); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x^2 + t*x + 1) * (x + t) + sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) + sage: g,u,v = a.right_xgcd(b); g x + t - sage: u*a + v*b == g # optional - sage.rings.finite_rings + sage: u*a + v*b == g True Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: g,u,v = a.right_xgcd(b, monic=False); g # optional - sage.rings.finite_rings + sage: g,u,v = a.right_xgcd(b, monic=False); g # needs sage.rings.finite_rings (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3 - sage: u*a + v*b == g # optional - sage.rings.finite_rings + sage: u*a + v*b == g # needs sage.rings.finite_rings True The base ring must be a field:: @@ -1171,17 +1185,18 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x^2 + t*x + 1) * (x + t) # optional - sage.rings.finite_rings - sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) # optional - sage.rings.finite_rings - sage: a.right_gcd(b) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x^2 + t*x + 1) * (x + t) + sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) + sage: a.right_gcd(b) x + t Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.right_gcd(b,monic=False) # optional - sage.rings.finite_rings + sage: a.right_gcd(b,monic=False) # needs sage.rings.finite_rings (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3 The base ring need to be a field:: @@ -1238,23 +1253,25 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x + t) * (x^2 + t*x + 1) # optional - sage.rings.finite_rings - sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) # optional - sage.rings.finite_rings - sage: a.left_gcd(b) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x + t) * (x^2 + t*x + 1) + sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) + sage: a.left_gcd(b) x + t Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.left_gcd(b,monic=False) # optional - sage.rings.finite_rings + sage: a.left_gcd(b,monic=False) # needs sage.rings.finite_rings 2*t*x + 4*t + 2 The base ring needs to be a field:: - sage: R. = QQ[] # optional - sage.rings.finite_rings - sage: sigma = R.hom([t+1]) + sage: # needs sage.rings.finite_rings + sage: R. = QQ[] + sage: sigma = R.hom([t + 1]) sage: S. = R['x',sigma] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) @@ -1265,6 +1282,7 @@ cdef class OrePolynomial(AlgebraElement): And the twisting morphism needs to be bijective:: + sage: # needs sage.rings.finite_rings sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) sage: S. = FR['x',f] @@ -1273,7 +1291,8 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_gcd(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism + of Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in _Fields: @@ -1299,23 +1318,22 @@ cdef class OrePolynomial(AlgebraElement): TESTS:: - sage: cython( # optional - sage.misc.cython + sage: # needs sage.misc.cython sage.rings.finite_rings + sage: cython( ....: ''' ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def left_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._left_lcm_cofactor(Q) ....: ''') - - sage: k. = GF(7^5) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism(3) # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - - sage: D = S.random_element(degree=2) # optional - sage.rings.finite_rings - sage: P = S.random_element(degree=2) * D # optional - sage.rings.finite_rings - sage: Q = S.random_element(degree=2) * D # optional - sage.rings.finite_rings - sage: L = P.left_lcm(Q) # optional - sage.rings.finite_rings - sage: U = left_lcm_cofactor(P, Q) # optional - sage.misc.cython sage.rings.finite_rings - sage: (U*P).right_monic() == L # optional - sage.misc.cython sage.rings.finite_rings + sage: k. = GF(7^5) + sage: Frob = k.frobenius_endomorphism(3) + sage: S. = k['x', Frob] + sage: D = S.random_element(degree=2) + sage: P = S.random_element(degree=2) * D + sage: Q = S.random_element(degree=2) * D + sage: L = P.left_lcm(Q) + sage: U = left_lcm_cofactor(P, Q) + sage: (U*P).right_monic() == L True """ cdef OrePolynomial Q, R, T @@ -1342,18 +1360,19 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: P = (x + t^2) * (x + t) # optional - sage.rings.finite_rings - sage: Q = 2 * (x^2 + t + 1) * (x * t) # optional - sage.rings.finite_rings - sage: L, U, V = P.left_xlcm(Q) # optional - sage.rings.finite_rings - sage: L # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: P = (x + t^2) * (x + t) + sage: Q = 2 * (x^2 + t + 1) * (x * t) + sage: L, U, V = P.left_xlcm(Q) + sage: L x^5 + (2*t^2 + t + 4)*x^4 + (3*t^2 + 4)*x^3 + (3*t^2 + 3*t + 2)*x^2 + (t^2 + t + 2)*x - sage: U * P == L # optional - sage.rings.finite_rings + sage: U * P == L # needs sage.rings.finite_rings True - sage: V * Q == L # optional - sage.rings.finite_rings + sage: V * Q == L # needs sage.rings.finite_rings True """ if self.base_ring() not in _Fields: @@ -1377,23 +1396,22 @@ cdef class OrePolynomial(AlgebraElement): TESTS:: - sage: cython( # optional - sage.misc.cython + sage: # needs sage.misc.cython sage.rings.finite_rings + sage: cython( ....: ''' ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def right_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._right_lcm_cofactor(Q) ....: ''') - - sage: k. = GF(7^5) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism(3) # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - - sage: D = S.random_element(degree=2) # optional - sage.rings.finite_rings - sage: P = D * S.random_element(degree=2) # optional - sage.rings.finite_rings - sage: Q = D * S.random_element(degree=2) # optional - sage.rings.finite_rings - sage: L = P.right_lcm(Q) # optional - sage.rings.finite_rings - sage: U = right_lcm_cofactor(P, Q) # optional - sage.misc.cython sage.rings.finite_rings - sage: (P*U).left_monic() == L # optional - sage.misc.cython sage.rings.finite_rings + sage: k. = GF(7^5) + sage: Frob = k.frobenius_endomorphism(3) + sage: S. = k['x', Frob] + sage: D = S.random_element(degree=2) + sage: P = D * S.random_element(degree=2) + sage: Q = D * S.random_element(degree=2) + sage: L = P.right_lcm(Q) + sage: U = right_lcm_cofactor(P, Q) + sage: (P*U).left_monic() == L True """ cdef OrePolynomial Q, R, T @@ -1427,17 +1445,18 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: P = (x + t) * (x + t^2) # optional - sage.rings.finite_rings - sage: Q = 2 * (x + t) * (x^2 + t + 1) # optional - sage.rings.finite_rings - sage: L, U, V = P.right_xlcm(Q) # optional - sage.rings.finite_rings - sage: L # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: P = (x + t) * (x + t^2) + sage: Q = 2 * (x + t) * (x^2 + t + 1) + sage: L, U, V = P.right_xlcm(Q) + sage: L x^4 + (2*t^2 + t + 2)*x^3 + (3*t^2 + 4*t + 1)*x^2 + (3*t^2 + 4*t + 1)*x + t^2 + 4 - sage: P * U == L # optional - sage.rings.finite_rings + sage: P * U == L True - sage: Q * V == L # optional - sage.rings.finite_rings + sage: Q * V == L True """ if self.base_ring() not in _Fields: @@ -1481,23 +1500,24 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x + t^2) * (x + t) # optional - sage.rings.finite_rings - sage: b = 2 * (x^2 + t + 1) * (x * t) # optional - sage.rings.finite_rings - sage: c = a.left_lcm(b); c # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x + t^2) * (x + t) + sage: b = 2 * (x^2 + t + 1) * (x * t) + sage: c = a.left_lcm(b); c x^5 + (2*t^2 + t + 4)*x^4 + (3*t^2 + 4)*x^3 + (3*t^2 + 3*t + 2)*x^2 + (t^2 + t + 2)*x - sage: c.is_right_divisible_by(a) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(a) True - sage: c.is_right_divisible_by(b) # optional - sage.rings.finite_rings + sage: c.is_right_divisible_by(b) True - sage: a.degree() + b.degree() == c.degree() + a.right_gcd(b).degree() # optional - sage.rings.finite_rings + sage: a.degree() + b.degree() == c.degree() + a.right_gcd(b).degree() True Specifying ``monic=False``, we *can* get a nonmonic lcm:: - sage: a.left_lcm(b,monic=False) # optional - sage.rings.finite_rings + sage: a.left_lcm(b,monic=False) # needs sage.rings.finite_rings (t^2 + t)*x^5 + (4*t^2 + 4*t + 1)*x^4 + (t + 1)*x^3 + (t^2 + 2)*x^2 + (3*t + 4)*x The base ring needs to be a field:: @@ -1550,23 +1570,24 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = (x + t) * (x + t^2) # optional - sage.rings.finite_rings - sage: b = 2 * (x + t) * (x^2 + t + 1) # optional - sage.rings.finite_rings - sage: c = a.right_lcm(b); c # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (x + t) * (x + t^2) + sage: b = 2 * (x + t) * (x^2 + t + 1) + sage: c = a.right_lcm(b); c x^4 + (2*t^2 + t + 2)*x^3 + (3*t^2 + 4*t + 1)*x^2 + (3*t^2 + 4*t + 1)*x + t^2 + 4 - sage: c.is_left_divisible_by(a) # optional - sage.rings.finite_rings + sage: c.is_left_divisible_by(a) True - sage: c.is_left_divisible_by(b) # optional - sage.rings.finite_rings + sage: c.is_left_divisible_by(b) True - sage: a.degree() + b.degree() == c.degree() + a.left_gcd(b).degree() # optional - sage.rings.finite_rings + sage: a.degree() + b.degree() == c.degree() + a.left_gcd(b).degree() True Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.right_lcm(b,monic=False) # optional - sage.rings.finite_rings + sage: a.right_lcm(b,monic=False) # needs sage.rings.finite_rings 2*t*x^4 + (3*t + 1)*x^3 + (4*t^2 + 4*t + 3)*x^2 + (3*t^2 + 4*t + 2)*x + 3*t^2 + 2*t + 3 @@ -1592,7 +1613,8 @@ cdef class OrePolynomial(AlgebraElement): sage: a.right_lcm(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism of + Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in _Fields: @@ -2048,12 +2070,13 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: a = 1 + t*x^2 # optional - sage.rings.finite_rings - sage: b = x + 1 # optional - sage.rings.finite_rings - sage: a.left_mod(b) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = 1 + t*x^2 + sage: b = x + 1 + sage: a.left_mod(b) 2*t^2 + 4*t """ _, r = self.left_quo_rem(other) @@ -2866,55 +2889,56 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): EXAMPLES:: - sage: R. = GF(7)[] # optional - sage.rings.finite_rings - sage: der = R.derivation() # optional - sage.rings.finite_rings - sage: A. = R['d', der] # optional - sage.rings.finite_rings + sage: R. = GF(7)[] + sage: der = R.derivation() + sage: A. = R['d', der] - sage: L = d^3 + t*d^2 # optional - sage.rings.finite_rings - sage: L.hilbert_shift(t) # optional - sage.rings.finite_rings + sage: L = d^3 + t*d^2 + sage: L.hilbert_shift(t) d^3 + 4*t*d^2 + (5*t^2 + 3)*d + 2*t^3 + 4*t - sage: (d+t)^3 + t*(d+t)^2 # optional - sage.rings.finite_rings + sage: (d+t)^3 + t*(d+t)^2 d^3 + 4*t*d^2 + (5*t^2 + 3)*d + 2*t^3 + 4*t One can specify another variable name:: - sage: L.hilbert_shift(t, var='x') # optional - sage.rings.finite_rings + sage: L.hilbert_shift(t, var='x') x^3 + 4*t*x^2 + (5*t^2 + 3)*x + 2*t^3 + 4*t When the twisting morphism is not trivial, the output lies in a different Ore polynomial ring:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - - sage: P = x^2 + a*x + a^2 # optional - sage.rings.finite_rings - sage: Q = P.hilbert_shift(a); Q # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: P = x^2 + a*x + a^2 + sage: Q = P.hilbert_shift(a); Q x^2 + (2*a^2 + a + 4)*x + a^2 + 3*a + 4 - - sage: Q.parent() # optional - sage.rings.finite_rings + sage: Q.parent() Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 and a*([a |--> a^5] - id) - sage: Q.parent() is S # optional - sage.rings.finite_rings + sage: Q.parent() is S False This behavior ensures that the Hilbert shift by a fixed element defines an homomorphism of rings:: - sage: U = S.random_element(degree=5) # optional - sage.rings.finite_rings - sage: V = S.random_element(degree=5) # optional - sage.rings.finite_rings - sage: s = k.random_element() # optional - sage.rings.finite_rings - sage: (U+V).hilbert_shift(s) == U.hilbert_shift(s) + V.hilbert_shift(s) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: U = S.random_element(degree=5) + sage: V = S.random_element(degree=5) + sage: s = k.random_element() + sage: (U+V).hilbert_shift(s) == U.hilbert_shift(s) + V.hilbert_shift(s) True - sage: (U*V).hilbert_shift(s) == U.hilbert_shift(s) * V.hilbert_shift(s) # optional - sage.rings.finite_rings + sage: (U*V).hilbert_shift(s) == U.hilbert_shift(s) * V.hilbert_shift(s) True We check that shifting by an element and then by its opposite gives back the initial Ore polynomial:: - sage: P = S.random_element(degree=10) # optional - sage.rings.finite_rings - sage: s = k.random_element() # optional - sage.rings.finite_rings - sage: P.hilbert_shift(s).hilbert_shift(-s) == P # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P = S.random_element(degree=10) + sage: s = k.random_element() + sage: P.hilbert_shift(s).hilbert_shift(-s) == P True """ from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing @@ -2960,7 +2984,8 @@ cdef class ConstantOrePolynomialSection(Map): sage: S. = R['x',sigma] sage: m = ConstantOrePolynomialSection(S, R); m Generic map: - From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t + over Rational Field twisted by t |--> t + 1 To: Univariate Polynomial Ring in t over Rational Field """ cpdef Element _call_(self, x): @@ -3032,11 +3057,12 @@ cdef class OrePolynomialBaseringInjection(Morphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: OrePolynomialBaseringInjection(k, k['x', Frob]) # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: OrePolynomialBaseringInjection(k, k['x', Frob]) Ore Polynomial base injection morphism: From: Finite Field in t of size 5^3 To: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 @@ -3059,12 +3085,13 @@ cdef class OrePolynomialBaseringInjection(Morphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) # optional - sage.rings.finite_rings - sage: m.an_element() # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) + sage: m.an_element() x """ return self._an_element @@ -3084,14 +3111,15 @@ cdef class OrePolynomialBaseringInjection(Morphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) # optional - sage.rings.finite_rings - sage: m(4) # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) + sage: m(4) 4 - sage: parent(m(4)) # optional - sage.rings.finite_rings + sage: parent(m(4)) Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ try: @@ -3106,14 +3134,16 @@ cdef class OrePolynomialBaseringInjection(Morphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) # optional - sage.rings.finite_rings - sage: m.section() # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) + sage: m.section() Generic map: - From: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - To: Finite Field in t of size 5^3 + From: Ore Polynomial Ring in x over Finite Field in t of size 5^3 + twisted by t |--> t^5 + To: Finite Field in t of size 5^3 """ return ConstantOrePolynomialSection(self._codomain, self.domain()) diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index f7eacf3112a..88db16fd111 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -23,6 +23,7 @@ from sage.misc.prandom import randint from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity from sage.structure.category_object import normalize_names @@ -36,11 +37,12 @@ from sage.rings.ring import _Fields from sage.categories.morphism import Morphism -from sage.rings.derivation import RingDerivation from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection +lazy_import('sage.rings.derivation', 'RingDerivation') + WORKING_CENTER_MAX_TRIES = 1000 diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 38d52a6273d..07cc696477a 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -3719,7 +3719,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: g = R(1) sage: h = g.univariate_polynomial(); h 1 - sage: h.parent() + sage: h.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) """ if not self.is_univariate(): @@ -3915,9 +3915,9 @@ cdef class BooleanPolynomial(MPolynomial): Evaluation of polynomials can be used fully symbolic:: - sage: f(x=var('a'),y=var('b'),z=var('c')) + sage: f(x=var('a'), y=var('b'), z=var('c')) # needs sage.symbolic a*b + c + 1 - sage: f(var('a'),var('b'),1) + sage: f(var('a'), var('b'), 1) # needs sage.symbolic a*b """ P = self._parent @@ -3996,9 +3996,9 @@ cdef class BooleanPolynomial(MPolynomial): This method can work fully symbolic:: - sage: f.subs(x=var('a'),y=var('b'),z=var('c')) + sage: f.subs(x=var('a'), y=var('b'), z=var('c')) # needs sage.symbolic a*b + b*c + c + 1 - sage: f.subs({'x':var('a'),'y':var('b'),'z':var('c')}) + sage: f.subs({'x': var('a'), 'y': var('b'), 'z': var('c')}) # needs sage.symbolic a*b + b*c + c + 1 """ P = self._parent diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index ebc17a01e50..9f93b79e3ee 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -2523,7 +2523,8 @@ cdef class NCPolynomial_plural(RingElement): Check if :trac:`7152` is fixed:: - sage: x=var('x') + sage: # needs sage.symbolic + sage: x = var('x') sage: K. = NumberField(x**2 + 1) sage: R. = QQ[] sage: p = rho*x diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index a0040f43e6b..0c847d125a4 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -133,7 +133,7 @@ cdef class PolyDict: sage: PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 0} - sage: PolyDict({(0, 0): RIF(-1,1)}) + sage: PolyDict({(0, 0): RIF(-1,1)}) # needs sage.rings.real_interval_field PolyDict with representation {(0, 0): 0.?} TESTS:: @@ -781,7 +781,7 @@ cdef class PolyDict: Check that :trac:`29604` is fixed:: - sage: PolyDict({(1, 0): GF(2)(1)}).latex(['x', 'y']) # optional - sage.rings.finite_rings + sage: PolyDict({(1, 0): GF(2)(1)}).latex(['x', 'y']) 'x' """ if not self: @@ -869,15 +869,15 @@ cdef class PolyDict: We make sure that intervals are correctly represented. :: - sage: f = PolyDict({(2, 3): RIF(1/2,3/2), (1, 2): RIF(-1,1)}) - sage: f.poly_repr(['x', 'y']) + sage: f = PolyDict({(2, 3): RIF(1/2,3/2), (1, 2): RIF(-1,1)}) # needs sage.rings.real_interval_field + sage: f.poly_repr(['x', 'y']) # needs sage.rings.real_interval_field '1.?*x^2*y^3 + 0.?*x*y^2' TESTS: Check that :trac:`29604` is fixed:: - sage: PolyDict({(1, 0): GF(4)(1)}).poly_repr(['x', 'y']) + sage: PolyDict({(1, 0): GF(4)(1)}).poly_repr(['x', 'y']) # needs sage.rings.finite_rings 'x' sage: P. = LaurentPolynomialRing(GF(2), 2) sage: P.gens() @@ -1001,9 +1001,9 @@ cdef class PolyDict: sage: f + g PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4, (2, 3): 0} - sage: K = GF(2) # optional - sage.rings.finite_rings - sage: f = PolyDict({(1, 1): K(1)}) # optional - sage.rings.finite_rings - sage: f + f # optional - sage.rings.finite_rings + sage: K = GF(2) + sage: f = PolyDict({(1, 1): K(1)}) + sage: f + f PolyDict with representation {(1, 1): 0} """ cdef dict D = self.__repn @@ -1071,14 +1071,16 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # optional - sage.groups - sage: f = PolyDict({(2, 3): x}) # optional - sage.groups - sage: f.scalar_rmult(y) # optional - sage.groups + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.scalar_rmult(y) # needs sage.combinat PolyDict with representation {(2, 3): x*y} + sage: f = PolyDict({(2,3):2, (1, 2): 3, (2, 1): 4}) sage: f.scalar_rmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} - sage: f.scalar_rmult(RIF(-1,1)) + sage: f.scalar_rmult(RIF(-1,1)) # needs sage.rings.real_interval_field PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ cdef dict v = {} @@ -1093,14 +1095,16 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # optional - sage.groups - sage: f = PolyDict({(2,3):x}) # optional - sage.groups - sage: f.scalar_lmult(y) # optional - sage.groups + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2,3):x}) # needs sage.combinat + sage: f.scalar_lmult(y) # needs sage.combinat PolyDict with representation {(2, 3): y*x} + sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.scalar_lmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} - sage: f.scalar_lmult(RIF(-1,1)) + sage: f.scalar_lmult(RIF(-1,1)) # needs sage.rings.real_interval_field PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ cdef dict v = {} @@ -1122,9 +1126,10 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple, PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # optional - sage.groups - sage: f = PolyDict({(2, 3): x}) # optional - sage.groups - sage: f.term_lmult(ETuple((1, 2)), y) # optional - sage.groups + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.term_lmult(ETuple((1, 2)), y) # needs sage.combinat PolyDict with representation {(3, 5): y*x} sage: f = PolyDict({(2,3): 2, (1,2): 3, (2,1): 4}) @@ -1151,9 +1156,10 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple, PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # optional - sage.groups - sage: f = PolyDict({(2, 3): x}) # optional - sage.groups - sage: f.term_rmult(ETuple((1, 2)), y) # optional - sage.groups + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.term_rmult(ETuple((1, 2)), y) # needs sage.combinat PolyDict with representation {(3, 5): x*y} sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) @@ -1981,6 +1987,7 @@ cdef class ETuple: Verify that :trac:`6428` has been addressed:: + sage: # needs sage.libs.singular sage: R. = Frac(QQ['x'])[] sage: type(y) diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 5fc4ff1f6af..e51268b4b54 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -47,7 +47,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: type(x) - sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) + sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) # needs sage.symbolic (0, 1.000000000000000, 2.000000000000000*x^2 + x, @@ -125,9 +125,9 @@ cdef class Polynomial_complex_arb(Polynomial): x + 2.000000000000000 sage: Polynomial_complex_arb(Pol, QQ['x'](0)) 0 - sage: Polynomial_complex_arb(Pol, {10: pi}) + sage: Polynomial_complex_arb(Pol, {10: pi}) # needs sage.symbolic ([3.141592653589793 +/- ...e-16])*x^10 - sage: Polynomial_complex_arb(Pol, pi) + sage: Polynomial_complex_arb(Pol, pi) # needs sage.symbolic [3.141592653589793 +/- ...e-16] """ cdef ComplexBall ball @@ -383,8 +383,11 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol. = CBF[] - sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) - (([0.1428571428571428 +/- ...e-17])*x^2 + ([-0.448798950512828 +/- ...e-16])*x + [1.409943485869908 +/- ...e-16], [-4.42946809718569 +/- ...e-15] - I) + sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) # needs sage.symbolic + (([0.1428571428571428 +/- ...e-17])*x^2 + + ([-0.448798950512828 +/- ...e-16])*x + + [1.409943485869908 +/- ...e-16], + [-4.42946809718569 +/- ...e-15] - I) sage: Pol(0).quo_rem(x + 1) (0, 0) @@ -661,7 +664,7 @@ cdef class Polynomial_complex_arb(Polynomial): 0.5000000000000000*x^2 + x + 1.000000000000000 sage: (1 + x/3)._log_series(3)._exp_series(3) ([+/- ...e-17])*x^2 + ([0.3333333333333333 +/- ...e-17])*x + 1.000000000000000 - sage: (CBF(0, pi) + x)._exp_series(4) + sage: (CBF(0, pi) + x)._exp_series(4) # needs sage.symbolic ([-0.166...] + [+/- ...]*I)*x^3 + ([-0.500...] + [+/- ...]*I)*x^2 + ([-1.000...] + [+/- ...]*I)*x + [-1.000...] + [+/- ...]*I """ @@ -911,7 +914,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol. = CBF[] sage: pol = x^2 - 1 - sage: pol(CBF(pi)) + sage: pol(CBF(pi)) # needs sage.symbolic [8.86960440108936 +/- ...e-15] sage: pol(x^3 + 1) x^6 + 2.000000000000000*x^3 diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index fcf63acf7fa..4d4b9dd10f5 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -72,7 +72,6 @@ import sage.rings.rational import sage.rings.integer import sage.rings.integer_ring import sage.rings.rational_field -import sage.rings.finite_rings.integer_mod_ring import sage.rings.fraction_field_element import sage.rings.infinity as infinity from sage.misc.latex import latex @@ -84,16 +83,18 @@ from sage.structure.factorization import Factorization from sage.structure.richcmp cimport (richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn) -from sage.libs.pari.all import pari, pari_gen, PariError +try: + from sage.libs.pari.all import pari, pari_gen, PariError +except ImportError: + pari_gen = () + pari = None -cimport sage.rings.abc -from sage.rings.real_mpfr import RealField, RR + class PariError(Exception): + pass -from sage.rings.complex_mpfr import ComplexField -from sage.rings.cc import CC +cimport sage.rings.abc from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF import sage.rings.abc import sage.interfaces.abc @@ -120,7 +121,6 @@ from sage.arith.functions import lcm from . import polynomial_fateman from sage.rings.ideal import is_Ideal -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.multi_polynomial cimport MPolynomial @@ -168,11 +168,13 @@ cpdef is_Polynomial(f): y^3 + x*y - 3*x sage: is_Polynomial(f) False - sage: var('x,y') # optional - sage.symbolic + + sage: # needs sage.symbolic + sage: var('x,y') (x, y) - sage: f = y^3 + x*y - 3*x; f # optional - sage.symbolic + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x - sage: is_Polynomial(f) # optional - sage.symbolic + sage: is_Polynomial(f) False """ from sage.misc.superseded import deprecation @@ -294,12 +296,12 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R = GF(2)['x']['y'] # optional - sage.rings.finite_rings - sage: R([0,1]).is_zero() # optional - sage.rings.finite_rings + sage: R = GF(2)['x']['y'] + sage: R([0,1]).is_zero() False - sage: R([0]).is_zero() # optional - sage.rings.finite_rings + sage: R([0]).is_zero() True - sage: R([-1]).is_zero() # optional - sage.rings.finite_rings + sage: R([-1]).is_zero() False """ return self.degree() < 0 @@ -344,11 +346,11 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: x = polygen(GF(389)) # optional - sage.rings.finite_rings - sage: plot(x^2 + 1, rgbcolor=(0,0,1)) # optional - sage.rings.finite_rings sage.plot + sage: x = polygen(GF(389)) + sage: plot(x^2 + 1, rgbcolor=(0,0,1)) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: x = polygen(QQ) - sage: plot(x^2 + 1, rgbcolor=(1,0,0)) # optional - sage.plot + sage: plot(x^2 + 1, rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive """ R = self.base_ring() @@ -484,12 +486,13 @@ cdef class Polynomial(CommutativePolynomial): We evaluate a polynomial over a quaternion algebra:: - sage: A. = QuaternionAlgebra(QQ, -1, -1) # optional - sage.combinat sage.modules - sage: R. = PolynomialRing(A, sparse=True) # optional - sage.combinat sage.modules - sage: f = i*j*w^5 - 13*i*w^2 + (i+j)*w + i # optional - sage.combinat sage.modules - sage: f(i+j+1) # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: A. = QuaternionAlgebra(QQ, -1, -1) + sage: R. = PolynomialRing(A, sparse=True) + sage: f = i*j*w^5 - 13*i*w^2 + (i+j)*w + i + sage: f(i+j+1) 24 + 26*i - 10*j - 25*k - sage: w = i+j+1; i*j*w^5 - 13*i*w^2 + (i+j)*w + i # optional - sage.combinat sage.modules + sage: w = i+j+1; i*j*w^5 - 13*i*w^2 + (i+j)*w + i 24 + 26*i - 10*j - 25*k The parent ring of the answer always "starts" with the parent of @@ -498,50 +501,51 @@ cdef class Polynomial(CommutativePolynomial): of that matrix may change depending on the base of the polynomial ring. :: + sage: # needs sage.combinat sage.modules sage: R. = QQ[] sage: f = R(2/3) - sage: a = matrix(ZZ, 2) # optional - sage.combinat sage.modules - sage: b = f(a); b # optional - sage.combinat sage.modules + sage: a = matrix(ZZ, 2) + sage: b = f(a); b [2/3 0] [ 0 2/3] - sage: b.parent() # optional - sage.combinat sage.modules + sage: b.parent() Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: f = R(1) - sage: b = f(a); b # optional - sage.combinat sage.modules + sage: b = f(a); b [1 0] [0 1] - sage: b.parent() # optional - sage.combinat sage.modules + sage: b.parent() Full MatrixSpace of 2 by 2 dense matrices over Rational Field :: - sage: R. = GF(17)[] # optional - sage.rings.finite_rings - sage: f = w^3 + 3*w +2 # optional - sage.rings.finite_rings - sage: f(5) # optional - sage.rings.finite_rings + sage: R. = GF(17)[] + sage: f = w^3 + 3*w +2 + sage: f(5) 6 - sage: f(w=5) # optional - sage.rings.finite_rings + sage: f(w=5) 6 - sage: f(x=10) # x isn't mentioned # optional - sage.rings.finite_rings + sage: f(x=10) # x isn't mentioned w^3 + 3*w + 2 Nested polynomial ring elements can be called like multivariate polynomials. Note the order of the arguments:: sage: R. = QQ[]; S. = R[] - sage: f = x+y*x+y^2 + sage: f = x + y*x + y^2 sage: f.parent() Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: f(2) 3*x + 4 sage: f(2,4) 16 - sage: f(y=2,x=4) + sage: f(y=2, x=4) 16 - sage: f(2,x=4) + sage: f(2, x=4) 16 - sage: f(2,x=4,z=5) + sage: f(2, x=4, z=5) 16 - sage: f(2,4, z=10) + sage: f(2, 4, z=10) 16 sage: f(y=x) 2*x^2 + x @@ -561,16 +565,16 @@ cdef class Polynomial(CommutativePolynomial): tuple containing the values to be substituted, though it is perhaps more natural to just unpack the list:: - sage: f([2]) # calling with a list + sage: f([2]) # calling with a list 3*x + 4 - sage: f((2,)) # calling with a tuple + sage: f((2,)) # calling with a tuple 3*x + 4 - sage: f(*[2]) # unpacking the list to call normally + sage: f(*[2]) # unpacking the list to call normally 3*x + 4 The following results in an element of the symbolic ring. :: - sage: f(x=sqrt(2)) # optional - sage.symbolic + sage: f(x=sqrt(2)) # needs sage.symbolic y^2 + sqrt(2)*y + sqrt(2) :: @@ -596,7 +600,7 @@ cdef class Polynomial(CommutativePolynomial): 3 sage: parent(f(0)) Rational Field - sage: parent(f(Qp(5)(0))) # optional - sage.rings.padics + sage: parent(f(Qp(5)(0))) # needs sage.rings.padics 5-adic Field with capped relative precision 20 TESTS: @@ -624,6 +628,7 @@ cdef class Polynomial(CommutativePolynomial): The following test came up in :trac:`9051`:: + sage: # needs sage.rings.complex_interval_field sage: Cif = ComplexIntervalField(64) sage: R. = Cif[] sage: f = 2*x-1 @@ -661,8 +666,8 @@ cdef class Polynomial(CommutativePolynomial): Univariate Polynomial Ring in x over Rational Field sage: zero = QQ['x'](0) - sage: a = matrix(ZZ, [[1]]) - sage: zero(a).parent() + sage: a = matrix(ZZ, [[1]]) # needs sage.modules + sage: zero(a).parent() # needs sage.modules Full MatrixSpace of 1 by 1 dense matrices over Rational Field sage: pol(y, x).parent() is pol(x, y).parent() is pol(y, y).parent() is Pol_xy @@ -672,11 +677,11 @@ cdef class Polynomial(CommutativePolynomial): Univariate Polynomial Ring in x over Rational Field sage: one = Pol_xy(1) - sage: one(1, 1.).parent() + sage: one(1, 1.).parent() # needs sage.rings.real_mpfr Real Field with 53 bits of precision - sage: zero = GF(2)['x'](0) # optional - sage.rings.finite_rings - sage: zero(1.).parent() # should raise an error # optional - sage.rings.finite_rings + sage: zero = GF(2)['x'](0) + sage: zero(1.).parent() # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -705,37 +710,40 @@ cdef class Polynomial(CommutativePolynomial): These were drastically slower prior to :trac:`33165`:: - sage: R. = GF(31337)[] # optional - sage.rings.finite_rings - sage: f = R(list(range(100, 201))) # optional - sage.rings.finite_rings - sage: g = R(list(range(1, 1001))) # optional - sage.rings.finite_rings - sage: S. = R.quotient(f) # optional - sage.rings.finite_rings - sage: g(y) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(31337)[] + sage: f = R(list(range(100, 201))) + sage: g = R(list(range(1, 1001))) + sage: S. = R.quotient(f) + sage: g(y) 22537*y^99 + 4686*y^98 + 13285*y^97 + 4216*y^96 + ... + 6389*y^3 + 30062*y^2 + 13755*y + 11875 :: - sage: T. = GF(31337)[] # optional - sage.rings.finite_rings - sage: g(z) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: T. = GF(31337)[] + sage: g(z) 1000*z^999 + 999*z^998 + 998*z^997 + 997*z^996 + ... + 5*z^4 + 4*z^3 + 3*z^2 + 2*z + 1 - sage: g(z^2) # optional - sage.rings.finite_rings + sage: g(z^2) 1000*z^1998 + 999*z^1996 + 998*z^1994 + 997*z^1992 + ... + 5*z^8 + 4*z^6 + 3*z^4 + 2*z^2 + 1 - sage: g(T([0, 1])) # optional - sage.rings.finite_rings + sage: g(T([0, 1])) 1000*z^999 + 999*z^998 + 998*z^997 + 997*z^996 + ... + 5*z^4 + 4*z^3 + 3*z^2 + 2*z + 1 - sage: g(T.zero()) # optional - sage.rings.finite_rings + sage: g(T.zero()) 1 - sage: g(T(2)) # optional - sage.rings.finite_rings + sage: g(T(2)) 23069 :: - sage: U. = GF(31337)[] # optional - sage.rings.finite_rings - sage: g(u) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: U. = GF(31337)[] + sage: g(u) 1000*u^999 + 999*u^998 + 998*u^997 + 997*u^996 + ... + 5*u^4 + 4*u^3 + 3*u^2 + 2*u + 1 - sage: g(u*v^2) # optional - sage.rings.finite_rings + sage: g(u*v^2) 1000*u^999*v^1998 + 999*u^998*v^1996 + 998*u^997*v^1994 + ... + 4*u^3*v^6 + 3*u^2*v^4 + 2*u*v^2 + 1 - sage: g(U.zero()) # optional - sage.rings.finite_rings + sage: g(U.zero()) 1 - sage: g(U(2)) # optional - sage.rings.finite_rings + sage: g(U(2)) -8268 Sparse tests for :trac:`33165`:: @@ -914,8 +922,8 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: Pol. = CBF[] - sage: (1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120).compose_trunc(1 + x, 2) + sage: Pol. = CBF[] # needs sage.libs.flint + sage: (1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120).compose_trunc(1 + x, 2) # needs sage.libs.flint ([2.708333333333333 +/- ...e-16])*x + [2.71666666666667 +/- ...e-15] sage: Pol. = QQ['y'][] @@ -1022,6 +1030,7 @@ cdef class Polynomial(CommutativePolynomial): Test that comparisons are consistent when using interval coefficients:: + sage: # needs sage.rings.real_interval_field sage: R. = RIF[] sage: a = RIF(0,1) * x sage: b = RIF(1,2) * x @@ -1042,9 +1051,9 @@ cdef class Polynomial(CommutativePolynomial): sage: a != b False - sage: R. = RBF[] - sage: pol = RBF(1.0, 0.1) - sage: pol == pol + sage: R. = RBF[] # needs sage.libs.flint + sage: pol = RBF(1.0, 0.1) # needs sage.libs.flint + sage: pol == pol # needs sage.libs.flint False """ cdef Polynomial pol = other @@ -1187,21 +1196,22 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: K. = Qq(4) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = x # optional - sage.rings.padics - sage: hash(f) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K. = Qq(4) + sage: R. = K[] + sage: f = x + sage: hash(f) Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' - sage: f._cache_key() # optional - sage.rings.padics + sage: f._cache_key() (Univariate Polynomial Ring in x over 2-adic Unramified Extension Field in u defined by x^2 + x + 1, 0, 1 + O(2^20)) sage: @cached_function ....: def foo(t): return t ....: - sage: foo(x) # optional - sage.rings.padics + sage: foo(x) (1 + O(2^20))*x """ return (self._parent,) + tuple(self) @@ -1238,9 +1248,9 @@ cdef class Polynomial(CommutativePolynomial): Verify that :trac:`16251` has been resolved, i.e., polynomials with unhashable coefficients are unhashable:: - sage: K. = Qq(9) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: hash(t) # optional - sage.rings.padics + sage: K. = Qq(9) # needs sage.rings.padics + sage: R. = K[] # needs sage.rings.padics + sage: hash(t) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' @@ -1291,14 +1301,15 @@ cdef class Polynomial(CommutativePolynomial): Defn: x |--> 5 sage: f(x) 5 - sage: f(x^2 + 3) # indirect doctest + sage: f(x^2 + 3) # indirect doctest 28 - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: cc = K.hom([-i]) # optional - sage.rings.number_field - sage: S. = K[] # optional - sage.rings.number_field - sage: phi = S.hom([y^2], base_map=cc) # optional - sage.rings.number_field - sage: phi(i*y) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: cc = K.hom([-i]) + sage: S. = K[] + sage: phi = S.hom([y^2], base_map=cc) + sage: phi(i*y) -i*y^2 """ a = im_gens[0] @@ -1327,21 +1338,21 @@ cdef class Polynomial(CommutativePolynomial): sage: a = QQ['x'](1/5) sage: QQ(a) 1/5 - sage: AA(a) # optional - sage.rings.number_field + sage: AA(a) # needs sage.rings.number_field 1/5 - sage: QQbar(a) # optional - sage.rings.number_field + sage: QQbar(a) # needs sage.rings.number_field 1/5 sage: RDF(a) 0.2 - sage: CDF(a) + sage: CDF(a) # needs sage.rings.complex_double 0.2 sage: RR(a) 0.200000000000000 sage: CC(a) 0.200000000000000 - sage: RBF(a) + sage: RBF(a) # needs sage.libs.flint [0.2000000000000000 +/- 4.45e-17] - sage: CBF(a) + sage: CBF(a) # needs sage.libs.flint [0.2000000000000000 +/- 4.45e-17] sage: RIF(a) 0.2000000000000000? @@ -1352,30 +1363,32 @@ cdef class Polynomial(CommutativePolynomial): sage: complex(a) (0.2+0j) - sage: b = AA['x'](AA(2/3).sqrt()) # optional - sage.rings.number_field - sage: AA(b) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: b = AA['x'](AA(2/3).sqrt()) + sage: AA(b) 0.8164965809277260? - sage: RR(b) # optional - sage.rings.number_field + sage: RR(b) 0.816496580927726 - sage: RBF(b) # optional - sage.rings.number_field + sage: RBF(b) # needs sage.libs.flint [0.816496580927726 +/- 2.44e-16] - sage: RIF(b) # optional - sage.rings.number_field + sage: RIF(b) 0.8164965809277260? - sage: float(b) # optional - sage.rings.number_field + sage: float(b) 0.816496580927726 - sage: c = QQbar['x'](QQbar(-2/5).sqrt()) # optional - sage.rings.number_field - sage: QQbar(c) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: c = QQbar['x'](QQbar(-2/5).sqrt()) + sage: QQbar(c) 0.6324555320336758?*I - sage: CDF(c) # optional - sage.rings.number_field + sage: CDF(c) 0.6324555320336758*I - sage: CC(c) # optional - sage.rings.number_field + sage: CC(c) 0.632455532033676*I - sage: CBF(c) # abs tol 1e-16 # optional - sage.rings.number_field + sage: CBF(c) # abs tol 1e-16 # needs sage.libs.flint [0.6324555320336759 +/- 3.38e-17]*I - sage: CIF(c) # optional - sage.rings.number_field + sage: CIF(c) 0.6324555320336758?*I - sage: complex(c) # optional - sage.rings.number_field + sage: complex(c) 0.6324555320336758j sage: K. = Frac(RR['x']) @@ -1387,8 +1400,8 @@ cdef class Polynomial(CommutativePolynomial): TypeError: cannot convert nonconstant polynomial sage: x = polygen(QQ) - sage: A. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: A(A['x'](u)) # optional - sage.rings.number_field + sage: A. = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: A(A['x'](u)) # needs sage.rings.number_field u """ if self.degree() > 0: @@ -1430,8 +1443,8 @@ cdef class Polynomial(CommutativePolynomial): r""" EXAMPLES:: - sage: p = PolynomialRing(QQbar, 'x')(1+I) # optional - sage.rings.number_field - sage: complex(p) # optional - sage.rings.number_field + sage: p = PolynomialRing(QQbar, 'x')(1+I) # needs sage.rings.number_field + sage: complex(p) # needs sage.rings.number_field (1+1j) """ return self._scalar_conversion(complex) @@ -1454,22 +1467,22 @@ cdef class Polynomial(CommutativePolynomial): """ EXAMPLES:: + sage: # needs sage.symbolic sage: R. = QQ[] sage: f = x^3 + x - sage: g = f._symbolic_(SR); g # optional - sage.symbolic + sage: g = f._symbolic_(SR); g x^3 + x - sage: g(x=2) # optional - sage.symbolic + sage: g(x=2) 10 - - sage: g = SR(f) # optional - sage.symbolic - sage: g(x=2) # optional - sage.symbolic + sage: g = SR(f) + sage: g(x=2) 10 The polynomial has to be over a field of characteristic 0 (see :trac:`24072`):: - sage: R. = GF(7)[] # optional - sage.rings.finite_rings - sage: f = SR(2*w^3 + 1); f # optional - sage.rings.finite_rings sage.symbolic + sage: R. = GF(7)[] + sage: f = SR(2*w^3 + 1); f # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -1556,24 +1569,25 @@ cdef class Polynomial(CommutativePolynomial): error the product may not always exactly equal the constant polynomial 1 and have extra terms with coefficients close to zero. :: + sage: # needs sage.modules sage: R. = RDF[] sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp - sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 # optional - sage.modules + sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 - sage: poly = f * (x^2 + 1) % (x^5 + x + 1) # optional - sage.modules + sage: poly = f * (x^2 + 1) % (x^5 + x + 1) sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c # optional - sage.modules + sage: parent(poly)([0.0 if abs(c) <= epsilon else c ....: for c in poly.coefficients(sparse=False)]) 1.0 - sage: f = inverse_mod(x^3 - x + 1, x - 2); f # optional - sage.modules + sage: f = inverse_mod(x^3 - x + 1, x - 2); f 0.14285714285714285 - sage: f * (x^3 - x + 1) % (x - 2) # optional - sage.modules + sage: f * (x^3 - x + 1) % (x - 2) 1.0 - sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f # optional - sage.modules + sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... - sage: poly = f*g % m # optional - sage.modules + sage: poly = f*g % m sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 # optional - sage.modules + sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 ....: for c in poly.coefficients(sparse=False)]) 1.0000000000000004 @@ -1681,14 +1695,15 @@ cdef class Polynomial(CommutativePolynomial): Even noncommutative ones:: - sage: M = MatrixSpace(ZZ, 2) # optional - sage.modules - sage: x = polygen(M) # optional - sage.modules - sage: p = M([1,2,3,4])*x^3 + M([-1,0,0,1])*x^2 + M([1,3,-1,0])*x + M.one() # optional - sage.modules - sage: q = p.inverse_series_trunc(5) # optional - sage.modules - sage: (p*q).truncate(5) == M.one() # optional - sage.modules + sage: # needs sage.modules + sage: M = MatrixSpace(ZZ, 2) + sage: x = polygen(M) + sage: p = M([1,2,3,4])*x^3 + M([-1,0,0,1])*x^2 + M([1,3,-1,0])*x + M.one() + sage: q = p.inverse_series_trunc(5) + sage: (p*q).truncate(5) == M.one() True - sage: q = p.inverse_series_trunc(13) # optional - sage.modules - sage: (p*q).truncate(13) == M.one() # optional - sage.modules + sage: q = p.inverse_series_trunc(13) + sage: (p*q).truncate(13) == M.one() True TESTS:: @@ -1739,11 +1754,13 @@ cdef class Polynomial(CommutativePolynomial): sage: Pol. = QQ[] sage: (x + x^3/6 + x^5/120).revert_series(6) 3/40*x^5 - 1/6*x^3 + x - sage: Pol. = CBF[] - sage: (x + x^3/6 + x^5/120).revert_series(6) + sage: Pol. = CBF[] # needs sage.libs.flint + sage: (x + x^3/6 + x^5/120).revert_series(6) # needs sage.libs.flint ([0.075000000000000 +/- ...e-17])*x^5 + ([-0.166666666666667 +/- ...e-16])*x^3 + x - sage: Pol. = SR[] # optional - sage.symbolic - sage: x.revert_series(6) # optional - sage.symbolic + + sage: # needs sage.symbolic + sage: Pol. = SR[] + sage: x.revert_series(6) Traceback (most recent call last): ... NotImplementedError: only implemented for certain base rings @@ -1772,20 +1789,21 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: Pol. = MatrixSpace(ZZ, 2)[] # optional - sage.modules - sage: a = matrix([[1,0], [0,0]]) # optional - sage.modules - sage: b = matrix([[1,2], [3,4]]) # optional - sage.modules - sage: list((a*x)*(b*x + 1)) # optional - sage.modules + sage: # needs sage.modules + sage: Pol. = MatrixSpace(ZZ, 2)[] + sage: a = matrix([[1,0], [0,0]]) + sage: b = matrix([[1,2], [3,4]]) + sage: list((a*x)*(b*x + 1)) [ [0 0] [1 0] [1 2] [0 0], [0 0], [0 0] ] - sage: list((b*x + 1)*(a*x)) # optional - sage.modules + sage: list((b*x + 1)*(a*x)) [ [0 0] [1 0] [1 0] [0 0], [0 0], [3 0] ] - sage: list((a*x + 1)*(b*x)) # optional - sage.modules + sage: list((a*x + 1)*(b*x)) [ [0 0] [1 2] [1 2] [0 0], [3 4], [0 0] @@ -1917,11 +1935,11 @@ cdef class Polynomial(CommutativePolynomial): sage: p = 37 * (x - 2/3)^2 sage: p.squarefree_decomposition() (37) * (x - 2/3)^2 - sage: x = polygen(GF(3)) # optional - sage.rings.finite_rings - sage: x.squarefree_decomposition() # optional - sage.rings.finite_rings + sage: x = polygen(GF(3)) + sage: x.squarefree_decomposition() x - sage: f = QQbar['x'](1) # optional - sage.rings.number_field - sage: f.squarefree_decomposition() # optional - sage.rings.number_field + sage: f = QQbar['x'](1) # needs sage.rings.number_field + sage: f.squarefree_decomposition() # needs sage.rings.number_field 1 """ @@ -2035,73 +2053,78 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = GF(11)[] # optional - sage.rings.finite_rings - sage: f = 7*x^7 + 8*x^6 + 4*x^5 + x^4 + 6*x^3 + 10*x^2 + 8*x + 5 # optional - sage.rings.finite_rings - sage: f.any_root() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(11)[] + sage: f = 7*x^7 + 8*x^6 + 4*x^5 + x^4 + 6*x^3 + 10*x^2 + 8*x + 5 + sage: f.any_root() 2 - sage: f.factor() # optional - sage.rings.finite_rings + sage: f.factor() (7) * (x + 9) * (x^6 + 10*x^4 + 6*x^3 + 5*x^2 + 2*x + 2) - sage: f = x^6 + 10*x^4 + 6*x^3 + 5*x^2 + 2*x + 2 # optional - sage.rings.finite_rings - sage: f.any_root(GF(11^6, 'a')) # optional - sage.rings.finite_rings + sage: f = x^6 + 10*x^4 + 6*x^3 + 5*x^2 + 2*x + 2 + sage: f.any_root(GF(11^6, 'a')) a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a - sage: sorted(f.roots(GF(11^6, 'a'))) # optional - sage.rings.finite_rings + sage: sorted(f.roots(GF(11^6, 'a'))) [(10*a^5 + 2*a^4 + 8*a^3 + 9*a^2 + a, 1), (a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a, 1), (9*a^5 + 5*a^4 + 10*a^3 + 8*a^2 + 3*a + 1, 1), (2*a^5 + 8*a^4 + 3*a^3 + 6*a + 2, 1), (a^5 + 3*a^4 + 8*a^3 + 2*a^2 + 3*a + 4, 1), (10*a^5 + 3*a^4 + 8*a^3 + a^2 + 10*a + 4, 1)] - sage: f.any_root(GF(11^6, 'a')) # optional - sage.rings.finite_rings + sage: f.any_root(GF(11^6, 'a')) a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a - sage: g = (x-1)*(x^2 + 3*x + 9) * (x^5 + 5*x^4 + 8*x^3 + 5*x^2 + 3*x + 5) # optional - sage.rings.finite_rings - sage: g.any_root(ring=GF(11^10, 'b'), degree=1) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = (x-1)*(x^2 + 3*x + 9) * (x^5 + 5*x^4 + 8*x^3 + 5*x^2 + 3*x + 5) + sage: g.any_root(ring=GF(11^10, 'b'), degree=1) 1 - sage: g.any_root(ring=GF(11^10, 'b'), degree=2) # optional - sage.rings.finite_rings + sage: g.any_root(ring=GF(11^10, 'b'), degree=2) 5*b^9 + 4*b^7 + 4*b^6 + 8*b^5 + 10*b^2 + 10*b + 5 - sage: g.any_root(ring=GF(11^10, 'b'), degree=5) # optional - sage.rings.finite_rings + sage: g.any_root(ring=GF(11^10, 'b'), degree=5) 5*b^9 + b^8 + 3*b^7 + 2*b^6 + b^5 + 4*b^4 + 3*b^3 + 7*b^2 + 10*b TESTS:: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: K. = GF(5^12) # optional - sage.rings.finite_rings - sage: for _ in range(40): # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: K. = GF(5^12) # needs sage.rings.finite_rings + sage: for _ in range(40): # needs sage.rings.finite_rings ....: f = R.random_element(degree=4) ....: assert f(f.any_root(K)) == 0 Check that our Cantor-Zassenhaus implementation does not loop over finite fields of even characteristic (see :trac:`16162`):: - sage: K. = GF(2**8) # optional - sage.rings.finite_rings - sage: x = polygen(K) # optional - sage.rings.finite_rings - sage: r = (x**2+x+1).any_root() # used to loop # optional - sage.rings.finite_rings - sage: r**2 + r # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(2**8) + sage: x = polygen(K) + sage: r = (x**2+x+1).any_root() # used to loop + sage: r**2 + r 1 - sage: (x**2+a+1).any_root() # optional - sage.rings.finite_rings + sage: (x**2+a+1).any_root() a^7 + a^2 Also check that such computations can be interrupted:: - sage: K. = GF(2^8) # optional - sage.rings.finite_rings - sage: x = polygen(K) # optional - sage.rings.finite_rings - sage: pol = x^1000000 + x + a # optional - sage.rings.finite_rings - sage: alarm(0.5); pol.any_root() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(2^8) + sage: x = polygen(K) + sage: pol = x^1000000 + x + a + sage: alarm(0.5); pol.any_root() Traceback (most recent call last): ... AlarmInterrupt Check root computation over large finite fields:: - sage: K. = GF(2**50) # optional - sage.rings.finite_rings - sage: x = polygen(K) # optional - sage.rings.finite_rings - sage: (x**10+x+a).any_root() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(2**50) + sage: x = polygen(K) + sage: (x**10+x+a).any_root() a^49 + a^47 + a^44 + a^42 + a^41 + a^39 + a^38 + a^37 + a^36 + a^34 + a^33 + a^29 + a^27 + a^26 + a^25 + a^23 + a^18 + a^13 + a^7 + a^5 + a^4 + a^3 + a^2 + a - sage: K. = GF(2**150) # optional - sage.rings.finite_rings - sage: x = polygen(K) # optional - sage.rings.finite_rings - sage: (x**10+x+a).any_root() # optional - sage.rings.finite_rings + sage: K. = GF(2**150) + sage: x = polygen(K) + sage: (x**10+x+a).any_root() a^149 + a^148 + a^146 + a^144 + a^143 + a^140 + a^138 + a^136 + a^134 + a^132 + a^131 + a^130 + a^129 + a^127 + a^123 + a^120 + a^118 + a^114 + a^113 + a^112 + a^111 + a^108 + a^104 + a^103 + a^102 + a^99 + a^98 @@ -2113,11 +2136,12 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`21998` has been resolved:: - sage: K. = GF(2^4) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: f = x^2 + x + a^2 + a # optional - sage.rings.finite_rings - sage: r = f.any_root() # optional - sage.rings.finite_rings - sage: r^2 + r # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(2^4) + sage: R. = K[] + sage: f = x^2 + x + a^2 + a + sage: r = f.any_root() + sage: r^2 + r a^2 + a """ if self.base_ring().is_finite() and self.base_ring().is_field(): @@ -2311,9 +2335,9 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: R. = PolynomialRing(GF(5^2, 'a'), 'x') # optional - sage.rings.finite_rings - sage: f = x^3 + 4*x # optional - sage.rings.finite_rings - sage: f / (x - 1) # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(5^2, 'a'), 'x') # needs sage.rings.finite_rings + sage: f = x^3 + 4*x + sage: f / (x - 1) # needs sage.rings.finite_rings x^2 + x Be careful about coercions (this used to be broken):: @@ -2328,21 +2352,21 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`12217` is fixed:: - sage: P. = GF(5)[] # optional - sage.rings.finite_rings - sage: x/0 # optional - sage.rings.finite_rings + sage: P. = GF(5)[] + sage: x/0 Traceback (most recent call last): ... ZeroDivisionError: inverse of Mod(0, 5) does not exist - sage: P. = GF(25, 'a')[] # optional - sage.rings.finite_rings - sage: x/5 # optional - sage.rings.finite_rings + sage: P. = GF(25, 'a')[] # needs sage.rings.finite_rings + sage: x/5 # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero in finite field Check that :trac:`23611` is fixed:: - sage: int(1) / x # optional - sage.rings.finite_rings + sage: int(1) / x 1/x """ # Same parents => bypass coercion @@ -2375,10 +2399,10 @@ cdef class Polynomial(CommutativePolynomial): sage: f^3 x^3 - 3*x^2 + 3*x - 1 - sage: R = PolynomialRing(GF(2), 'x') # optional - sage.rings.finite_rings - sage: f = R(x^9 + x^7 + x^6 + x^5 + x^4 + x^2 + x) # optional - sage.rings.finite_rings - sage: h = R(x^10 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + 1) # optional - sage.rings.finite_rings - sage: pow(f, 2, h) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(2), 'x') + sage: f = R(x^9 + x^7 + x^6 + x^5 + x^4 + x^2 + x) + sage: h = R(x^10 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + 1) + sage: pow(f, 2, h) x^9 + x^8 + x^7 + x^5 + x^3 TESTS:: @@ -2405,46 +2429,48 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: k = GF(5) # optional - sage.rings.finite_rings - sage: D. = k[] # optional - sage.rings.finite_rings - sage: l. = k.extension(x^2 + 2) # optional - sage.rings.finite_rings - sage: R. = l[] # optional - sage.rings.finite_rings - sage: f = t^4 + (2*x - 1)*t^3 + (2*x + 1)*t^2 + 3 # optional - sage.rings.finite_rings - sage: h = t^4 - x*t^3 + (3*x + 1)*t^2 + 2*t + 2*x - 1 # optional - sage.rings.finite_rings - sage: pow(f, 2, h) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k = GF(5) + sage: D. = k[] + sage: l. = k.extension(x^2 + 2) + sage: R. = l[] + sage: f = t^4 + (2*x - 1)*t^3 + (2*x + 1)*t^2 + 3 + sage: h = t^4 - x*t^3 + (3*x + 1)*t^2 + 2*t + 2*x - 1 + sage: pow(f, 2, h) 3*t^3 + (2*x + 3)*t^2 + (2*x + 2)*t + 2*x + 2 - sage: pow(f, 10**7, h) # optional - sage.rings.finite_rings + sage: pow(f, 10**7, h) 4*x*t^3 + 2*x*t^2 + 4*x*t + 4 Check that :trac:`18457` is fixed:: - sage: R. = PolynomialRing(GF(5), sparse=True) # optional - sage.rings.finite_rings - sage: (1+x)^(5^10) # used to hang forever # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(5), sparse=True) + sage: (1+x)^(5^10) x^9765625 + 1 - sage: S. = GF(3)[] # optional - sage.rings.finite_rings - sage: R1. = PolynomialRing(S, sparse=True) # optional - sage.rings.finite_rings - sage: (1+x+t)^(3^10) # optional - sage.rings.finite_rings + sage: S. = GF(3)[] + sage: R1. = PolynomialRing(S, sparse=True) + sage: (1+x+t)^(3^10) x^59049 + t^59049 + 1 - sage: R2. = PolynomialRing(S, sparse=False) # optional - sage.rings.finite_rings - sage: (1+x+t)^(3^10) # optional - sage.rings.finite_rings + sage: R2. = PolynomialRing(S, sparse=False) + sage: (1+x+t)^(3^10) x^59049 + t^59049 + 1 Check that the algorithm used is indeed correct:: + sage: # needs sage.rings.finite_rings sage: from sage.arith.power import generic_power - sage: R1 = PolynomialRing(GF(8,'a'), 'x') # optional - sage.rings.finite_rings - sage: R2 = PolynomialRing(GF(9,'b'), 'x', sparse=True) # optional - sage.rings.finite_rings - sage: R3 = PolynomialRing(R2, 'y') # optional - sage.rings.finite_rings - sage: R4 = PolynomialRing(R1, 'y', sparse=True) # optional - sage.rings.finite_rings - sage: for d in range(20,40): # long time # optional - sage.rings.finite_rings + sage: R1 = PolynomialRing(GF(8,'a'), 'x') + sage: R2 = PolynomialRing(GF(9,'b'), 'x', sparse=True) + sage: R3 = PolynomialRing(R2, 'y') + sage: R4 = PolynomialRing(R1, 'y', sparse=True) + sage: for d in range(20,40): # long time ....: for R in [R1, R2, R3, R3]: ....: a = R.random_element() ....: assert a^d == generic_power(a, d) Test the powering modulo ``x^n`` (calling :meth:`power_trunc`):: - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: pow(x + 1, 51, x^7) # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: pow(x + 1, 51, x^7) x^6 + 2*x^3 + 1 sage: S. = QQ[] @@ -2455,10 +2481,11 @@ cdef class Polynomial(CommutativePolynomial): Check that fallback method is used when it is not possible to compute the characteristic of the base ring (:trac:`24308`):: - sage: kk. = GF(2)[] # optional - sage.rings.finite_rings - sage: k. = kk.quo(a^2+a+1) # optional - sage.rings.finite_rings - sage: K. = k[] # optional - sage.rings.finite_rings - sage: (T*y)^21 # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: kk. = GF(2)[] + sage: k. = kk.quo(a^2 + a + 1) + sage: K. = k[] + sage: (T*y)^21 T^21 """ if not isinstance(left, Polynomial): @@ -2550,18 +2577,18 @@ cdef class Polynomial(CommutativePolynomial): sage: ((x + y)^5).truncate(5) 5*x*y^4 + 10*x^2*y^3 + 10*x^3*y^2 + 5*x^4*y + x^5 - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: p = x^2 - x + 1 # optional - sage.rings.finite_rings - sage: q = p.power_trunc(80, 20); q # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: p = x^2 - x + 1 + sage: q = p.power_trunc(80, 20); q x^19 + x^18 + ... + 2*x^4 + 2*x^3 + x + 1 - sage: (p^80).truncate(20) == q # optional - sage.rings.finite_rings + sage: (p^80).truncate(20) == q True - sage: R. = GF(7)[] # optional - sage.rings.finite_rings - sage: p = (x^2 + x + 1).power_trunc(2^100, 100); p # optional - sage.rings.finite_rings + sage: R. = GF(7)[] + sage: p = (x^2 + x + 1).power_trunc(2^100, 100); p 2*x^99 + x^98 + x^95 + 2*x^94 + ... + 3*x^2 + 2*x + 1 - sage: for i in range(100): # optional - sage.rings.finite_rings + sage: for i in range(100): ....: q1 = (x^2 + x + 1).power_trunc(2^100 + i, 100) ....: q2 = p * (x^2 + x + 1).power_trunc(i, 100) ....: q2 = q2.truncate(100) @@ -2570,16 +2597,16 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: sage: x = polygen(QQ) - sage: (3*x-5).power_trunc(2^200, 0) + sage: (3*x - 5).power_trunc(2^200, 0) 0 sage: x.power_trunc(-1, 10) Traceback (most recent call last): ... ValueError: n must be a non-negative integer sage: R. = QQ['x'] - sage: y.power_trunc(2**32-1, 2) + sage: y.power_trunc(2**32 - 1, 2) 0 - sage: y.power_trunc(2**64-1, 2) + sage: y.power_trunc(2**64 - 1, 2) 0 """ cdef Integer ZZn = ZZ(n) @@ -2651,10 +2678,10 @@ cdef class Polynomial(CommutativePolynomial): elements in the Sage library yet that do not implement ``__bool__``, so we have to create one artificially.):: - sage: class PatchedAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): # optional - sage.rings.number_field + sage: class PatchedAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): # needs sage.rings.number_field ....: def __bool__(self): raise NotImplementedError() - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: R([PatchedAlgebraicNumber(0), 1]) # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: R([PatchedAlgebraicNumber(0), 1]) # needs sage.rings.number_field x + 0 """ if name is None: @@ -2729,11 +2756,13 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: C3. = CyclotomicField(3) # optional - sage.rings.number_field - sage: R. = C3[] # optional - sage.rings.number_field - sage: f = X^3 - omega*X # optional - sage.rings.number_field - sage: latex(f) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: C3. = CyclotomicField(3) + sage: R. = C3[] + sage: f = X^3 - omega*X + sage: latex(f) X^{3} - \omega X + sage: R. = RDF[] sage: latex(x+2) x + 2.0 @@ -2745,9 +2774,9 @@ cdef class Polynomial(CommutativePolynomial): The following illustrates a (non-intentional) superfluity of parentheses - sage: K. = QuadraticField(-1) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: latex(I*x^2 - I*x) # optional - sage.rings.number_field + sage: K. = QuadraticField(-1) # needs sage.rings.number_field + sage: R. = K[] # needs sage.rings.number_field + sage: latex(I*x^2 - I*x) # needs sage.rings.number_field \left(\sqrt{-1}\right) x^{2} + \left(-\sqrt{-1}\right) x """ s = " " @@ -2816,11 +2845,11 @@ cdef class Polynomial(CommutativePolynomial): R1. = ZZ[] R2. = R1[] y^2 + (2*x + 2)*y + (x^2 + 2*x + 1) - sage: sage_input(RR(pi) * polygen(RR), verify=True) # optional - sage.symbolic + sage: sage_input(RR(pi) * polygen(RR), verify=True) # needs sage.symbolic # Verified R. = RR[] 3.1415926535897931*x - sage: sage_input(polygen(GF(7)) + 12, verify=True) # optional - sage.rings.finite_rings + sage: sage_input(polygen(GF(7)) + 12, verify=True) # Verified R. = GF(7)[] x + 5 @@ -2928,15 +2957,16 @@ cdef class Polynomial(CommutativePolynomial): Check the problem reported at :trac:`12529` is fixed:: + sage: # needs sage.rings.finite_rings sage: gens = 'y a0 a1 a2 b0 b1 b2 c1 c2 d0 d1 d2 d3 d4 d5 d6 d7'.split() - sage: R = PolynomialRing(GF(8), 17, gens) # optional - sage.rings.finite_rings - sage: R.inject_variables(verbose=False) # optional - sage.rings.finite_rings - sage: A, B, C = a0 + a1*y + a2*y^2, b0 + b1*y + b2*y^2, c1*y + c2*y^2 # optional - sage.rings.finite_rings - sage: D = d0 + d1*y + d2*y^2 + d3*y^3 + d4*y^4 + d5*y^5 + d6*y^6 + d7*y^7 # optional - sage.rings.finite_rings - sage: F = D.subs({y: B}) # optional - sage.rings.finite_rings - sage: G = A.subs({y: F}) + C # optional - sage.rings.finite_rings - sage: g = G.mod(y^8 + y) # optional - sage.rings.finite_rings - sage: g.degree(y) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(8), 17, gens) + sage: R.inject_variables(verbose=False) + sage: A, B, C = a0 + a1*y + a2*y^2, b0 + b1*y + b2*y^2, c1*y + c2*y^2 + sage: D = d0 + d1*y + d2*y^2 + d3*y^3 + d4*y^4 + d5*y^5 + d6*y^6 + d7*y^7 + sage: F = D.subs({y: B}) + sage: G = A.subs({y: F}) + C + sage: g = G.mod(y^8 + y) + sage: g.degree(y) 7 """ return self % other @@ -2975,21 +3005,22 @@ cdef class Polynomial(CommutativePolynomial): Show the product in the symbolic ring:: - sage: L = SR['x'] # optional - sage.symbolic - sage: var('a0,a1,b0,b1') # optional - sage.symbolic + sage: L = SR['x'] # needs sage.symbolic + sage: var('a0,a1,b0,b1') # needs sage.symbolic (a0, a1, b0, b1) - sage: L([a0, a1])._mul_generic(L([b0, b1])) # optional - sage.symbolic + sage: L([a0, a1])._mul_generic(L([b0, b1])) # needs sage.symbolic a1*b1*x^2 + (a1*b0 + a0*b1)*x + a0*b0 A non-commutative example:: - sage: A. = QuaternionAlgebra(QQ, -1,-1) # optional - sage.combinat sage.modules - sage: R. = PolynomialRing(A) # optional - sage.combinat sage.modules - sage: f = i*w + j # optional - sage.combinat sage.modules - sage: g = k*w + 1 # optional - sage.combinat sage.modules - sage: f._mul_generic(g) # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: A. = QuaternionAlgebra(QQ, -1,-1) + sage: R. = PolynomialRing(A) + sage: f = i*w + j + sage: g = k*w + 1 + sage: f._mul_generic(g) -j*w^2 + 2*i*w + j - sage: g._mul_generic(f) # optional - sage.combinat sage.modules + sage: g._mul_generic(f) j*w^2 + j @@ -3193,23 +3224,25 @@ cdef class Polynomial(CommutativePolynomial): Show the product in the symbolic ring:: - sage: L = SR['x'] # optional - sage.symbolic - sage: var('a0,a1,b0,b1') # optional - sage.symbolic + sage: # needs sage.symbolic + sage: L = SR['x'] + sage: var('a0,a1,b0,b1') (a0, a1, b0, b1) - sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 0) # optional - sage.symbolic + sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 0) a1*b1*x^2 + ((a0 + a1)*(b0 + b1) - a0*b0 - a1*b1)*x + a0*b0 - sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 2) # optional - sage.symbolic + sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 2) a1*b1*x^2 + (a1*b0 + a0*b1)*x + a0*b0 A noncommutative example:: - sage: A. = QuaternionAlgebra(QQ, -1,-1) # optional - sage.combinat sage.modules - sage: R. = PolynomialRing(A) # optional - sage.combinat sage.modules - sage: f = i*w + j # optional - sage.combinat sage.modules - sage: g = k*w + 1 # optional - sage.combinat sage.modules - sage: f._mul_karatsuba(g,0) # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: A. = QuaternionAlgebra(QQ, -1,-1) + sage: R. = PolynomialRing(A) + sage: f = i*w + j + sage: g = k*w + 1 + sage: f._mul_karatsuba(g,0) -j*w^2 + 2*i*w + j - sage: g._mul_karatsuba(f,0) # optional - sage.combinat sage.modules + sage: g._mul_karatsuba(f,0) j*w^2 + j TESTS:: @@ -3235,28 +3268,30 @@ cdef class Polynomial(CommutativePolynomial): Random tests for noncommutative rings:: - sage: A. = QuaternionAlgebra(QQ, -1,-1) # optional - sage.combinat sage.modules - sage: R. = PolynomialRing(A) # optional - sage.combinat sage.modules - sage: f = R.random_element(randint(10,100)) # optional - sage.combinat sage.modules - sage: g = R.random_element(randint(10,100)) # optional - sage.combinat sage.modules - sage: f._mul_generic(g) == f._mul_karatsuba(g,0) # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: A. = QuaternionAlgebra(QQ, -1,-1) + sage: R. = PolynomialRing(A) + sage: f = R.random_element(randint(10,100)) + sage: g = R.random_element(randint(10,100)) + sage: f._mul_generic(g) == f._mul_karatsuba(g,0) True - sage: f._mul_generic(g) == f._mul_karatsuba(g,16) # optional - sage.combinat sage.modules + sage: f._mul_generic(g) == f._mul_karatsuba(g,16) True - sage: g = R.random_element(0) # optional - sage.combinat sage.modules - sage: f._mul_karatsuba(g,0) == f._mul_generic(g) # optional - sage.combinat sage.modules + sage: g = R.random_element(0) + sage: f._mul_karatsuba(g,0) == f._mul_generic(g) True - sage: g._mul_karatsuba(f,0) == g._mul_generic(f) # optional - sage.combinat sage.modules + sage: g._mul_karatsuba(f,0) == g._mul_generic(f) True Polynomials over matrices:: - sage: K = PolynomialRing(MatrixSpace(QQ, 2), 'x') # optional - sage.modules - sage: f = K.random_element(randint(5, 10)) # optional - sage.modules - sage: g = K.random_element(randint(5, 10)) # optional - sage.modules - sage: h1 = f._mul_generic(g) # optional - sage.modules - sage: h2 = f._mul_karatsuba(g,randint(0, 10)) # optional - sage.modules - sage: h1 == h2 # optional - sage.modules + sage: # needs sage.modules + sage: K = PolynomialRing(MatrixSpace(QQ, 2), 'x') + sage: f = K.random_element(randint(5, 10)) + sage: g = K.random_element(randint(5, 10)) + sage: h1 = f._mul_generic(g) + sage: h2 = f._mul_karatsuba(g,randint(0, 10)) + sage: h1 == h2 True """ if self.is_zero(): @@ -3326,11 +3361,11 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^3 - 17*x + 3 - sage: f.base_extend(GF(7)) # optional - sage.rings.finite_rings + sage: f.base_extend(GF(7)) Traceback (most recent call last): ... TypeError: no such base extension - sage: f.change_ring(GF(7)) # optional - sage.rings.finite_rings + sage: f.change_ring(GF(7)) x^3 + 4*x + 3 """ S = self._parent.base_extend(R) @@ -3349,6 +3384,8 @@ cdef class Polynomial(CommutativePolynomial): sage: f.change_variable_name('theta') -2/7*theta^3 + 2/3*theta - 19/993 """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._parent.base_ring(), names=var) return R(self) @@ -3363,24 +3400,25 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: f = K.defining_polynomial() # optional - sage.rings.number_field - sage: f.change_ring(GF(7)) # optional - sage.rings.finite_rings # optional - sage.rings.number_field + sage: K. = CyclotomicField(3) # needs sage.rings.number_field + sage: f = K.defining_polynomial() # needs sage.rings.number_field + sage: f.change_ring(GF(7)) # needs sage.rings.finite_rings sage.rings.number_field x^2 + x + 1 :: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: f = x^2 + z # optional - sage.rings.number_field - sage: f.change_ring(K.embeddings(CC)[1]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: R. = K[] + sage: f = x^2 + z + sage: f.change_ring(K.embeddings(CC)[1]) # needs sage.rings.real_mpfr x^2 - 0.500000000000000 - 0.866025403784438*I :: sage: R. = QQ[] sage: f = x^2 + 1 - sage: f.change_ring(QQ.embeddings(CC)[0]) + sage: f.change_ring(QQ.embeddings(CC)[0]) # needs sage.rings.real_mpfr x^2 + 1.00000000000000 TESTS: @@ -3388,17 +3426,18 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`25022` is fixed:: sage: K. = ZZ[] - sage: x.change_ring(SR) == SR['x'].gen() # optional - sage.symbolic + sage: x.change_ring(SR) == SR['x'].gen() # needs sage.symbolic True sage: x.change_ring(ZZ['x']) == ZZ['x']['x'].gen() True Check that :trac:`28541` is fixed:: - sage: F. = GF(7^2) # optional - sage.rings.finite_rings - sage: S. = F[] # optional - sage.rings.finite_rings - sage: P = x^2 + a*x + a^2 # optional - sage.rings.finite_rings - sage: P.change_ring(F.frobenius_endomorphism()) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F. = GF(7^2) + sage: S. = F[] + sage: P = x^2 + a*x + a^2 + sage: P.change_ring(F.frobenius_endomorphism()) x^2 + (6*a + 1)*x + 6*a + 5 """ if isinstance(R, Map): @@ -3597,15 +3636,15 @@ cdef class Polynomial(CommutativePolynomial): Check that the denominator is an element over the base whenever the base has no :meth:`denominator` method. This closes :trac:`9063`. :: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: x = R(0) # optional - sage.rings.finite_rings - sage: x.denominator() # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: x = R(0) + sage: x.denominator() 1 - sage: type(x.denominator()) # optional - sage.rings.finite_rings + sage: type(x.denominator()) - sage: isinstance(x.numerator() / x.denominator(), Polynomial) # optional - sage.rings.finite_rings + sage: isinstance(x.numerator() / x.denominator(), Polynomial) True - sage: isinstance(x.numerator() / R(1), Polynomial) # optional - sage.rings.finite_rings + sage: isinstance(x.numerator() / R(1), Polynomial) False TESTS: @@ -3687,10 +3726,12 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['s,t']['x'] # optional - sage.rings.number_field sage.symbolic - sage: f = K.random_element() # optional - sage.rings.number_field sage.symbolic - sage: f.numerator() / f.denominator() == f # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['s,t']['x'] + sage: f = K.random_element() + sage: f.numerator() / f.denominator() == f True + sage: R = RR['x'] sage: f = R.random_element() sage: f.numerator() / f.denominator() == f @@ -3802,17 +3843,19 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`28147` is fixed:: - sage: R. = GF(65537)[] # optional - sage.rings.finite_rings - sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 # optional - sage.rings.finite_rings - sage: p.derivative() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(65537)[] + sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 + sage: p.derivative() 4*x^3 + 65486*x^2 + 4*x + 65536 - sage: R. = GF(19^2)[] # optional - sage.rings.finite_rings - sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 # optional - sage.rings.finite_rings - sage: p.derivative() # optional - sage.rings.finite_rings + sage: R. = GF(19^2)[] + sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 + sage: p.derivative() 4*x^3 + 6*x^2 + 4*x + 18 - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: p = x^4 + x^2 + x # optional - sage.rings.finite_rings - sage: p.derivative() # optional - sage.rings.finite_rings + + sage: R. = GF(2)[] + sage: p = x^4 + x^2 + x + sage: p.derivative() 1 sage: R. = Integers(77)[] @@ -3827,8 +3870,9 @@ cdef class Polynomial(CommutativePolynomial): ... ValueError: cannot differentiate with respect to 2*x - sage: y = var("y") # optional - sage.symbolic - sage: f._derivative(y) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: y = var("y") + sage: f._derivative(y) Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -3836,21 +3880,23 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`26844` is fixed by :trac:`28147`:: - sage: A = PolynomialRing(GF(3), name='t') # optional - sage.rings.finite_rings - sage: K = A.fraction_field() # optional - sage.rings.finite_rings - sage: t = K.gen() # optional - sage.rings.finite_rings - sage: t.derivative(t) # optional - sage.rings.finite_rings + sage: A = PolynomialRing(GF(3), name='t') + sage: K = A.fraction_field() + sage: t = K.gen() + sage: t.derivative(t) 1 Check that :trac:`28187` is fixed:: - sage: R. = GF(65537)[] # optional - sage.rings.finite_rings - sage: x._derivative(2*x) # optional - sage.rings.finite_rings + sage: R. = GF(65537)[] # needs sage.rings.finite_rings + sage: x._derivative(2*x) Traceback (most recent call last): ... ValueError: cannot differentiate with respect to 2*x - sage: y = var('y') # optional - sage.symbolic - sage: R.gen()._derivative(y) # optional - sage.rings.finite_rings sage.symbolic + + sage: # needs sage.symbolic + sage: y = var('y') + sage: R.gen()._derivative(y) Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -3927,16 +3973,18 @@ cdef class Polynomial(CommutativePolynomial): This shows that the issue at :trac:`7711` is resolved:: - sage: P. = PolynomialRing(GF(2147483647)) # optional - sage.rings.finite_rings - sage: Q. = PolynomialRing(P) # optional - sage.rings.finite_rings - sage: p = x + y + z # optional - sage.rings.finite_rings - sage: p.integral() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(2147483647)) + sage: Q. = PolynomialRing(P) + sage: p = x + y + z + sage: p.integral() -1073741823*y^2 + (x + z)*y - sage: P. = PolynomialRing(GF(next_prime(2147483647))) # optional - sage.rings.finite_rings - sage: Q. = PolynomialRing(P) # optional - sage.rings.finite_rings - sage: p = x + y + z # optional - sage.rings.finite_rings - sage: p.integral() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(next_prime(2147483647))) + sage: Q. = PolynomialRing(P) + sage: p = x + y + z + sage: p.integral() 1073741830*y^2 + (x + z)*y A truly convoluted example:: @@ -4069,39 +4117,40 @@ cdef class Polynomial(CommutativePolynomial): sage: x = QQ['x'].0 sage: f = (x^3 - 1)^2 - sage: f.factor() # optional - sage.libs.pari + sage: f.factor() # needs sage.libs.pari (x - 1)^2 * (x^2 + x + 1)^2 Since `\QQ` is a field, the irreducible factors are monic:: sage: f = 10*x^5 - 1 - sage: f.factor() # optional - sage.libs.pari + sage: f.factor() # needs sage.libs.pari (10) * (x^5 - 1/10) sage: f = 10*x^5 - 10 - sage: f.factor() # optional - sage.libs.pari + sage: f.factor() # needs sage.libs.pari (10) * (x - 1) * (x^4 + x^3 + x^2 + x + 1) Over `\ZZ` the irreducible factors need not be monic:: sage: x = ZZ['x'].0 sage: f = 10*x^5 - 1 - sage: f.factor() # optional - sage.libs.pari + sage: f.factor() # needs sage.libs.pari 10*x^5 - 1 We factor a non-monic polynomial over a finite field of 25 elements:: - sage: k. = GF(25) # optional - sage.rings.finite_rings - sage: R. = k[] # optional - sage.rings.finite_rings - sage: f = 2*x^10 + 2*x + 2*a # optional - sage.rings.finite_rings - sage: F = f.factor(); F # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(25) + sage: R. = k[] + sage: f = 2*x^10 + 2*x + 2*a + sage: F = f.factor(); F (2) * (x + a + 2) * (x^2 + 3*x + 4*a + 4) * (x^2 + (a + 1)*x + a + 2) * (x^5 + (3*a + 4)*x^4 + (3*a + 3)*x^3 + 2*a*x^2 + (3*a + 1)*x + 3*a + 1) Notice that the unit factor is included when we multiply `F` back out:: - sage: expand(F) # optional - sage.rings.finite_rings + sage: expand(F) # needs sage.rings.finite_rings sage.symbolic 2*x^10 + 2*x + 2*a A new ring. In the example below, we set the special method @@ -4110,21 +4159,23 @@ cdef class Polynomial(CommutativePolynomial): used to easily extend polynomial factorization to work over new rings you introduce:: - sage: R. = PolynomialRing(IntegerModRing(4), implementation="NTL") # optional - sage.libs.ntl - sage: (x^2).factor() # optional - sage.libs.ntl + sage: # needs sage.libs.ntl + sage: R. = PolynomialRing(IntegerModRing(4), implementation="NTL") + sage: (x^2).factor() Traceback (most recent call last): ... NotImplementedError: factorization of polynomials over rings with composite characteristic is not implemented sage: def my_factor(f): ....: return f.change_ring(ZZ).factor() - sage: R.base_ring()._factor_univariate_polynomial = my_factor # optional - sage.libs.ntl - sage: (x^2).factor() # optional - sage.libs.ntl sage.libs.pari + sage: R.base_ring()._factor_univariate_polynomial = my_factor + sage: (x^2).factor() # needs sage.libs.pari x^2 - sage: del R.base_ring()._factor_univariate_polynomial # clean up # optional - sage.libs.ntl + sage: del R.base_ring()._factor_univariate_polynomial # clean up Arbitrary precision real and complex factorization:: + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: R. = RealField(100)[] sage: F = factor(x^2 - 3); F (x - 1.7320508075688772935274463415) * (x + 1.7320508075688772935274463415) @@ -4133,6 +4184,7 @@ cdef class Polynomial(CommutativePolynomial): sage: factor(x^2 + 1) x^2 + 1.0000000000000000000000000000 + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: R. = ComplexField(100)[] sage: F = factor(x^2 + 3); F (x - 1.7320508075688772935274463415*I) * (x + 1.7320508075688772935274463415*I) @@ -4149,30 +4201,33 @@ cdef class Polynomial(CommutativePolynomial): Over a number field:: - sage: K. = CyclotomicField(15) # optional - sage.rings.number_field - sage: x = polygen(K) # optional - sage.rings.number_field - sage: ((x^3 + z*x + 1)^3 * (x - z)).factor() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(15) + sage: x = polygen(K) + sage: ((x^3 + z*x + 1)^3 * (x - z)).factor() (x - z) * (x^3 + z*x + 1)^3 - sage: cyclotomic_polynomial(12).change_ring(K).factor() # optional - sage.rings.number_field + sage: cyclotomic_polynomial(12).change_ring(K).factor() (x^2 - z^5 - 1) * (x^2 + z^5) - sage: ((x^3 + z*x + 1)^3 * (x/(z+2) - 1/3)).factor() # optional - sage.rings.number_field + sage: ((x^3 + z*x + 1)^3 * (x/(z+2) - 1/3)).factor() (-1/331*z^7 + 3/331*z^6 - 6/331*z^5 + 11/331*z^4 - 21/331*z^3 + 41/331*z^2 - 82/331*z + 165/331) * (x - 1/3*z - 2/3) * (x^3 + z*x + 1)^3 Over a relative number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: L. = K.extension(x^3 - 2) # optional - sage.rings.number_field - sage: t = polygen(L, 't') # optional - sage.rings.number_field - sage: f = (t^3 + t + a) * (t^5 + t + z); f # optional - sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: L. = K.extension(x^3 - 2) + sage: t = polygen(L, 't') + sage: f = (t^3 + t + a) * (t^5 + t + z); f t^8 + t^6 + a*t^5 + t^4 + z*t^3 + t^2 + (a + z)*t + z*a - sage: f.factor() # optional - sage.rings.number_field + sage: f.factor() (t^3 + t + a) * (t^5 + t + z) Over the real double field:: + sage: # needs numpy sage: R. = RDF[] sage: (-2*x^2 - 1).factor() (-2.0) * (x^2 + 0.5000000000000001) @@ -4186,19 +4241,24 @@ cdef class Polynomial(CommutativePolynomial): :meth:`.roots` method, which does not detect that all the roots are real:: - sage: f.roots() # abs tol 2e-5 + sage: f.roots() # abs tol 2e-5 # needs numpy [(1.0000065719436413, 1)] Over the complex double field the factors are approximate and therefore occur with multiplicity 1:: + sage: # needs numpy sage.rings.complex_double sage: R. = CDF[] sage: f = (x^2 + 2*R(I))^3 sage: F = f.factor() sage: F # abs tol 3e-5 - (x - 1.0000138879287663 + 1.0000013435286879*I) * (x - 0.9999942196864997 + 0.9999873009803959*I) * (x - 0.9999918923847313 + 1.0000113554909125*I) - * (x + 0.9999908759550227 - 1.0000069659624138*I) * (x + 0.9999985293216753 - 0.9999886153831807*I) * (x + 1.0000105947233 - 1.0000044186544053*I) - sage: [f(t[0][0]).abs() for t in F] # abs tol 1e-13 + (x - 1.0000138879287663 + 1.0000013435286879*I) + * (x - 0.9999942196864997 + 0.9999873009803959*I) + * (x - 0.9999918923847313 + 1.0000113554909125*I) + * (x + 0.9999908759550227 - 1.0000069659624138*I) + * (x + 0.9999985293216753 - 0.9999886153831807*I) + * (x + 1.0000105947233 - 1.0000044186544053*I) + sage: [f(t[0][0]).abs() for t in F] # abs tol 1e-13 [1.979365054e-14, 1.97936298566e-14, 1.97936990747e-14, 3.6812407475e-14, 3.65211563729e-14, 3.65220890052e-14] @@ -4216,8 +4276,8 @@ cdef class Polynomial(CommutativePolynomial): Factoring polynomials over the algebraic numbers (see :trac:`8544`):: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x^8 - 1).factor() # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: (x^8 - 1).factor() # needs sage.rings.number_field (x - 1) * (x - 0.7071067811865475? - 0.7071067811865475?*I) * (x - 0.7071067811865475? + 0.7071067811865475?*I) * (x - I) * (x + I) * (x + 0.7071067811865475? - 0.7071067811865475?*I) @@ -4226,8 +4286,8 @@ cdef class Polynomial(CommutativePolynomial): Factoring polynomials over the algebraic reals (see :trac:`8544`):: - sage: R. = AA[] # optional - sage.rings.number_field - sage: (x^8 + 1).factor() # optional - sage.rings.number_field + sage: R. = AA[] # needs sage.rings.number_field + sage: (x^8 + 1).factor() # needs sage.rings.number_field (x^2 - 1.847759065022574?*x + 1.000000000000000?) * (x^2 - 0.7653668647301795?*x + 1.000000000000000?) * (x^2 + 0.7653668647301795?*x + 1.000000000000000?) @@ -4237,38 +4297,50 @@ cdef class Polynomial(CommutativePolynomial): This came up in :trac:`7088`:: - sage: R.=PolynomialRing(ZZ) + sage: R. = PolynomialRing(ZZ) sage: f = 12*x^10 + x^9 + 432*x^3 + 9011 sage: g = 13*x^11 + 89*x^3 + 1 sage: F = f^2 * g^3 - sage: F = f^2 * g^3; F.factor() + sage: F = f^2 * g^3; F.factor() # needs sage.libs.pari (12*x^10 + x^9 + 432*x^3 + 9011)^2 * (13*x^11 + 89*x^3 + 1)^3 - sage: F = f^2 * g^3 * 7; F.factor() + sage: F = f^2 * g^3 * 7; F.factor() # needs sage.libs.pari 7 * (12*x^10 + x^9 + 432*x^3 + 9011)^2 * (13*x^11 + 89*x^3 + 1)^3 This example came up in :trac:`7097`:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: f = 8*x^9 + 42*x^6 + 6*x^3 - 1 - sage: g = x^24 - 12*x^23 + 72*x^22 - 286*x^21 + 849*x^20 - 2022*x^19 + 4034*x^18 - 6894*x^17 + 10182*x^16 - 13048*x^15 + 14532*x^14 - 13974*x^13 + 11365*x^12 - 7578*x^11 + 4038*x^10 - 1766*x^9 + 762*x^8 - 408*x^7 + 236*x^6 - 126*x^5 + 69*x^4 - 38*x^3 + 18*x^2 - 6*x + 1 - sage: assert g.is_irreducible() - sage: K. = NumberField(g) # optional - sage.rings.number_field - sage: len(f.roots(K)) # optional - sage.rings.number_field + sage: g = (x^24 - 12*x^23 + 72*x^22 - 286*x^21 + 849*x^20 - 2022*x^19 + 4034*x^18 + ....: - 6894*x^17 + 10182*x^16 - 13048*x^15 + 14532*x^14 - 13974*x^13 + ....: + 11365*x^12 - 7578*x^11 + 4038*x^10 - 1766*x^9 + 762*x^8 - 408*x^7 + ....: + 236*x^6 - 126*x^5 + 69*x^4 - 38*x^3 + 18*x^2 - 6*x + 1) + sage: assert g.is_irreducible() # needs sage.libs.pari + sage: K. = NumberField(g) + sage: len(f.roots(K)) 9 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (8) * (x^3 + 1/4) * (x^6 + 5*x^3 - 1/2) - sage: f.change_ring(K).factor() # optional - sage.rings.number_field - (8) * (x - 3260097/3158212*a^22 + 35861067/3158212*a^21 - 197810817/3158212*a^20 + 722970825/3158212*a^19 - 1980508347/3158212*a^18 + 4374189477/3158212*a^17 - 4059860553/1579106*a^16 + 6442403031/1579106*a^15 - 17542341771/3158212*a^14 + 20537782665/3158212*a^13 - 20658463789/3158212*a^12 + 17502836649/3158212*a^11 - 11908953451/3158212*a^10 + 6086953981/3158212*a^9 - 559822335/789553*a^8 + 194545353/789553*a^7 - 505969453/3158212*a^6 + 338959407/3158212*a^5 - 155204647/3158212*a^4 + 79628015/3158212*a^3 - 57339525/3158212*a^2 + 26692783/3158212*a - 1636338/789553) * ... - sage: f = QQbar['x'](1) # optional - sage.rings.number_field - sage: f.factor() # optional - sage.rings.number_field + sage: f.change_ring(K).factor() + (8) * (x - 3260097/3158212*a^22 + 35861067/3158212*a^21 - 197810817/3158212*a^20 + + 722970825/3158212*a^19 - 1980508347/3158212*a^18 + 4374189477/3158212*a^17 + - 4059860553/1579106*a^16 + 6442403031/1579106*a^15 - 17542341771/3158212*a^14 + + 20537782665/3158212*a^13 - 20658463789/3158212*a^12 + 17502836649/3158212*a^11 + - 11908953451/3158212*a^10 + 6086953981/3158212*a^9 - 559822335/789553*a^8 + + 194545353/789553*a^7 - 505969453/3158212*a^6 + 338959407/3158212*a^5 + - 155204647/3158212*a^4 + 79628015/3158212*a^3 - 57339525/3158212*a^2 + + 26692783/3158212*a - 1636338/789553) * ... + sage: f = QQbar['x'](1) + sage: f.factor() 1 Factorization also works even if the variable of the finite field is nefariously labeled `x`:: - sage: R. = GF(3^2, 'x')[] # optional - sage.rings.finite_rings - sage: f = x^10 +7*x -13 # optional - sage.rings.finite_rings - sage: G = f.factor(); G # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(3^2, 'x')[] + sage: f = x^10 + 7*x - 13 + sage: G = f.factor(); G (x + x) * (x + 2*x + 1) * (x^4 + (x + 2)*x^3 + (2*x + 2)*x + 2) * (x^4 + 2*x*x^3 + (x + 1)*x + 2) sage: prod(G) == f @@ -4276,70 +4348,70 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: R. = GF(9,'x')[] # purposely calling it x to test robustness # optional - sage.rings.finite_rings - sage: f = x0^3 + x0 + 1 # optional - sage.rings.finite_rings - sage: f.factor() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(9,'x')[] # purposely calling it x to test robustness + sage: f = x0^3 + x0 + 1 + sage: f.factor() (x0 + 2) * (x0 + x) * (x0 + 2*x + 1) - sage: f = 0*x0 # optional - sage.rings.finite_rings - sage: f.factor() # optional - sage.rings.finite_rings + sage: f = 0*x0 + sage: f.factor() Traceback (most recent call last): ... ArithmeticError: factorization of 0 is not defined :: - sage: f = x0^0 # optional - sage.rings.finite_rings - sage: f.factor() # optional - sage.rings.finite_rings + sage: f = x0^0 # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings 1 Over a complicated number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') sage: f = x^6 + 10/7*x^5 - 867/49*x^4 - 76/245*x^3 + 3148/35*x^2 - 25944/245*x + 48771/1225 - sage: K. = NumberField(f) # optional - sage.rings.number_field - sage: S. = K[] # optional - sage.rings.number_field - sage: ff = S(f); ff # optional - sage.rings.number_field + sage: K. = NumberField(f) + sage: S. = K[] + sage: ff = S(f); ff T^6 + 10/7*T^5 - 867/49*T^4 - 76/245*T^3 + 3148/35*T^2 - 25944/245*T + 48771/1225 - sage: F = ff.factor() # optional - sage.rings.number_field - sage: len(F) # optional - sage.rings.number_field + sage: F = ff.factor() + sage: len(F) 4 - sage: F[:2] # optional - sage.rings.number_field + sage: F[:2] [(T - a, 1), - (T - 40085763200/924556084127*a^5 - 145475769880/924556084127*a^4 + 527617096480/924556084127*a^3 - + 1289745809920/924556084127*a^2 - 3227142391585/924556084127*a - 401502691578/924556084127, 1)] - sage: expand(F) # optional - sage.rings.number_field + (T - 40085763200/924556084127*a^5 - 145475769880/924556084127*a^4 + + 527617096480/924556084127*a^3 + 1289745809920/924556084127*a^2 + - 3227142391585/924556084127*a - 401502691578/924556084127, 1)] + sage: expand(F) T^6 + 10/7*T^5 - 867/49*T^4 - 76/245*T^3 + 3148/35*T^2 - 25944/245*T + 48771/1225 :: + sage: # needs sage.rings.number_field sage: f = x^2 - 1/3 - sage: K. = NumberField(f) # optional - sage.rings.number_field - sage: A. = K[] # optional - sage.rings.number_field - sage: A(x^2 - 1).factor() # optional - sage.rings.number_field + sage: K. = NumberField(f) + sage: A. = K[] + sage: A(x^2 - 1).factor() (T - 1) * (T + 1) - - :: - - sage: A(3*x^2 - 1).factor() # optional - sage.rings.number_field + sage: A(3*x^2 - 1).factor() (3) * (T - a) * (T + a) - - :: - - sage: A(x^2 - 1/3).factor() # optional - sage.rings.number_field + sage: A(x^2 - 1/3).factor() (T - a) * (T + a) Test that :trac:`10279` is fixed:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: K. = NumberField(t^4 - t^2 + 1) # optional - sage.rings.number_field - sage: pol = t^3 + (-4*a^3 + 2*a)*t^2 - 11/3*a^2*t + 2/3*a^3 - 4/3*a # optional - sage.rings.number_field - sage: pol.factor() # optional - sage.rings.number_field + sage: K. = NumberField(t^4 - t^2 + 1) + sage: pol = t^3 + (-4*a^3 + 2*a)*t^2 - 11/3*a^2*t + 2/3*a^3 - 4/3*a + sage: pol.factor() (t - 2*a^3 + a) * (t - 4/3*a^3 + 2/3*a) * (t - 2/3*a^3 + 1/3*a) Test that this factorization really uses ``nffactor()`` internally:: + sage: # needs sage.libs.pari sage.rings.number_field sage: pari.default("debug", 3) - sage: F = pol.factor() # optional - sage.rings.number_field + sage: F = pol.factor() Entering nffactor: ... @@ -4347,56 +4419,86 @@ cdef class Polynomial(CommutativePolynomial): Test that :trac:`10369` is fixed:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K. = NumberField(x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - - sage: pol = (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7)*t^10 + (4/7*a^5 - 2/7*a^4 - 2/7*a^3 - 2/7*a^2 - 2/7*a - 6/7)*t^9 + (90/49*a^5 + 152/49*a^4 + 18/49*a^3 + 24/49*a^2 + 30/49*a + 36/49)*t^8 + (-10/49*a^5 + 10/7*a^4 + 198/49*a^3 - 102/49*a^2 - 60/49*a - 26/49)*t^7 + (40/49*a^5 + 45/49*a^4 + 60/49*a^3 + 277/49*a^2 - 204/49*a - 78/49)*t^6 + (90/49*a^5 + 110/49*a^4 + 2*a^3 + 80/49*a^2 + 46/7*a - 30/7)*t^5 + (30/7*a^5 + 260/49*a^4 + 250/49*a^3 + 232/49*a^2 + 32/7*a + 8)*t^4 + (-184/49*a^5 - 58/49*a^4 - 52/49*a^3 - 66/49*a^2 - 72/49*a - 72/49)*t^3 + (18/49*a^5 - 32/49*a^4 + 10/49*a^3 + 4/49*a^2)*t^2 + (2/49*a^4 - 4/49*a^3 + 2/49*a^2)*t # optional - sage.rings.number_field - sage: pol.factor() # optional - sage.rings.number_field - (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7) * t * (t - a^5 - a^4 - a^3 - a^2 - a - 1)^4 * (t^5 + (-12/7*a^5 - 10/7*a^4 - 8/7*a^3 - 6/7*a^2 - 4/7*a - 2/7)*t^4 + (12/7*a^5 - 8/7*a^3 + 16/7*a^2 + 2/7*a + 20/7)*t^3 + (-20/7*a^5 - 20/7*a^3 - 20/7*a^2 + 4/7*a - 2)*t^2 + (12/7*a^5 + 12/7*a^3 + 2/7*a + 16/7)*t - 4/7*a^5 - 4/7*a^3 - 4/7*a - 2/7) - - sage: pol = (1/7*a^2 - 1/7*a)*t^10 + (4/7*a - 6/7)*t^9 + (102/49*a^5 + 99/49*a^4 + 96/49*a^3 + 93/49*a^2 + 90/49*a + 150/49)*t^8 + (-160/49*a^5 - 36/49*a^4 - 48/49*a^3 - 8/7*a^2 - 60/49*a - 60/49)*t^7 + (30/49*a^5 - 55/49*a^4 + 20/49*a^3 + 5/49*a^2)*t^6 + (6/49*a^4 - 12/49*a^3 + 6/49*a^2)*t^5 # optional - sage.rings.number_field - sage: pol.factor() # optional - sage.rings.number_field - (1/7*a^2 - 1/7*a) * t^5 * (t^5 + (-40/7*a^5 - 38/7*a^4 - 36/7*a^3 - 34/7*a^2 - 32/7*a - 30/7)*t^4 + (60/7*a^5 - 30/7*a^4 - 18/7*a^3 - 9/7*a^2 - 3/7*a)*t^3 + (60/7*a^4 - 40/7*a^3 - 16/7*a^2 - 4/7*a)*t^2 + (30/7*a^3 - 25/7*a^2 - 5/7*a)*t + 6/7*a^2 - 6/7*a) - - sage: pol = x^10 + (4/7*a - 6/7)*x^9 + (9/49*a^2 - 3/7*a + 15/49)*x^8 + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^7 + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x^6 + (-6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807)*x^5 # optional - sage.rings.number_field - sage: pol.factor() # optional - sage.rings.number_field - x^5 * (x^5 + (4/7*a - 6/7)*x^4 + (9/49*a^2 - 3/7*a + 15/49)*x^3 + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^2 + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x - 6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807) + sage: K. = NumberField(x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) + sage: R. = PolynomialRing(K) + sage: pol = ((-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7)*t^10 + ....: + (4/7*a^5 - 2/7*a^4 - 2/7*a^3 - 2/7*a^2 - 2/7*a - 6/7)*t^9 + ....: + (90/49*a^5 + 152/49*a^4 + 18/49*a^3 + 24/49*a^2 + 30/49*a + 36/49)*t^8 + ....: + (-10/49*a^5 + 10/7*a^4 + 198/49*a^3 - 102/49*a^2 - 60/49*a - 26/49)*t^7 + ....: + (40/49*a^5 + 45/49*a^4 + 60/49*a^3 + 277/49*a^2 - 204/49*a - 78/49)*t^6 + ....: + (90/49*a^5 + 110/49*a^4 + 2*a^3 + 80/49*a^2 + 46/7*a - 30/7)*t^5 + ....: + (30/7*a^5 + 260/49*a^4 + 250/49*a^3 + 232/49*a^2 + 32/7*a + 8)*t^4 + ....: + (-184/49*a^5 - 58/49*a^4 - 52/49*a^3 - 66/49*a^2 - 72/49*a - 72/49)*t^3 + ....: + (18/49*a^5 - 32/49*a^4 + 10/49*a^3 + 4/49*a^2)*t^2 + ....: + (2/49*a^4 - 4/49*a^3 + 2/49*a^2)*t) + sage: pol.factor() + (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7) * t + * (t - a^5 - a^4 - a^3 - a^2 - a - 1)^4 + * (t^5 + (-12/7*a^5 - 10/7*a^4 - 8/7*a^3 - 6/7*a^2 - 4/7*a - 2/7)*t^4 + + (12/7*a^5 - 8/7*a^3 + 16/7*a^2 + 2/7*a + 20/7)*t^3 + + (-20/7*a^5 - 20/7*a^3 - 20/7*a^2 + 4/7*a - 2)*t^2 + + (12/7*a^5 + 12/7*a^3 + 2/7*a + 16/7)*t + - 4/7*a^5 - 4/7*a^3 - 4/7*a - 2/7) + sage: pol = ((1/7*a^2 - 1/7*a)*t^10 + (4/7*a - 6/7)*t^9 + ....: + (102/49*a^5 + 99/49*a^4 + 96/49*a^3 + 93/49*a^2 + 90/49*a + 150/49)*t^8 + ....: + (-160/49*a^5 - 36/49*a^4 - 48/49*a^3 - 8/7*a^2 - 60/49*a - 60/49)*t^7 + ....: + (30/49*a^5 - 55/49*a^4 + 20/49*a^3 + 5/49*a^2)*t^6 + ....: + (6/49*a^4 - 12/49*a^3 + 6/49*a^2)*t^5) + sage: pol.factor() + (1/7*a^2 - 1/7*a) * t^5 + * (t^5 + (-40/7*a^5 - 38/7*a^4 - 36/7*a^3 - 34/7*a^2 - 32/7*a - 30/7)*t^4 + + (60/7*a^5 - 30/7*a^4 - 18/7*a^3 - 9/7*a^2 - 3/7*a)*t^3 + + (60/7*a^4 - 40/7*a^3 - 16/7*a^2 - 4/7*a)*t^2 + + (30/7*a^3 - 25/7*a^2 - 5/7*a)*t + 6/7*a^2 - 6/7*a) + sage: pol = (x^10 + (4/7*a - 6/7)*x^9 + (9/49*a^2 - 3/7*a + 15/49)*x^8 + ....: + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^7 + ....: + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x^6 + ....: + (-6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807)*x^5) + sage: pol.factor() + x^5 * (x^5 + (4/7*a - 6/7)*x^4 + (9/49*a^2 - 3/7*a + 15/49)*x^3 + + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^2 + + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x + - 6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807) Factoring over a number field over which we cannot factor the discriminant by trial division:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K. = NumberField(x^16 - x - 6) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - sage: f = (x+a)^50 - (a-1)^50 # optional - sage.rings.number_field - sage: len(factor(f)) # optional - sage.rings.number_field + sage: K. = NumberField(x^16 - x - 6) + sage: R. = PolynomialRing(K) + sage: f = (x+a)^50 - (a-1)^50 + sage: len(factor(f)) 6 - sage: pari(K.discriminant()).factor(limit=10^6) # optional - sage.rings.number_field + sage: pari(K.discriminant()).factor(limit=10^6) [-1, 1; 3, 15; 23, 1; 887, 1; 12583, 1; 2354691439917211, 1] - sage: factor(K.discriminant()) # optional - sage.rings.number_field + sage: factor(K.discriminant()) -1 * 3^15 * 23 * 887 * 12583 * 6335047 * 371692813 Factoring over a number field over which we cannot factor the discriminant and over which `nffactor()` fails:: + sage: # needs sage.libs.pari sage.rings.number_field sage: p = next_prime(10^50); q = next_prime(10^51); n = p*q - sage: K. = QuadraticField(p*q) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - sage: K.pari_polynomial('a').nffactor("x^2+1") # optional - sage.rings.number_field + sage: K. = QuadraticField(p*q) + sage: R. = PolynomialRing(K) + sage: K.pari_polynomial('a').nffactor("x^2+1") Mat([x^2 + 1, 1]) - sage: factor(x^2 + 1) # optional - sage.rings.number_field + sage: factor(x^2 + 1) x^2 + 1 - sage: factor((x - a) * (x + 2*a)) # optional - sage.rings.number_field + sage: factor((x - a) * (x + 2*a)) (x - a) * (x + 2*a) A test where nffactor used to fail without a nf structure:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K = NumberField([x^2 - 1099511627777, x^3 - 3], 'a') # optional - sage.rings.number_field - sage: x = polygen(K) # optional - sage.rings.number_field - sage: f = x^3 - 3 # optional - sage.rings.number_field - sage: factor(f) # optional - sage.rings.number_field + sage: K = NumberField([x^2 - 1099511627777, x^3 - 3], 'a') + sage: x = polygen(K) + sage: f = x^3 - 3 + sage: factor(f) (x - a1) * (x^2 + a1*x + a1^2) We check that :trac:`7554` is fixed:: @@ -4404,7 +4506,7 @@ cdef class Polynomial(CommutativePolynomial): sage: L. = LaurentPolynomialRing(QQ) sage: F = L.fraction_field() sage: R. = PolynomialRing(F) - sage: factor(x) + sage: factor(x) # needs sage.libs.pari x sage: factor(x^2 - q^2) (x - q) * (x + q) @@ -4576,35 +4678,38 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: R.=PolynomialRing(ZZ) + sage: # needs sage.libs.pari + sage: R. = PolynomialRing(ZZ) sage: f = (2*x + 1) * (3*x^2 - 5)^2 - sage: f._factor_pari_helper(pari(f).factor()) # optional - sage.libs.pari + sage: f._factor_pari_helper(pari(f).factor()) (2*x + 1) * (3*x^2 - 5)^2 - sage: f._factor_pari_helper(pari(f).factor(), unit=11) # optional - sage.libs.pari + sage: f._factor_pari_helper(pari(f).factor(), unit=11) 11 * (2*x + 1) * (3*x^2 - 5)^2 - sage: (8*f)._factor_pari_helper(pari(f).factor()) # optional - sage.libs.pari + sage: (8*f)._factor_pari_helper(pari(f).factor()) 8 * (2*x + 1) * (3*x^2 - 5)^2 - sage: (8*f)._factor_pari_helper(pari(f).factor(), unit=11) # optional - sage.libs.pari + sage: (8*f)._factor_pari_helper(pari(f).factor(), unit=11) 88 * (2*x + 1) * (3*x^2 - 5)^2 - sage: QQ['x'](f)._factor_pari_helper(pari(f).factor()) # optional - sage.libs.pari + sage: QQ['x'](f)._factor_pari_helper(pari(f).factor()) (18) * (x + 1/2) * (x^2 - 5/3)^2 - sage: QQ['x'](f)._factor_pari_helper(pari(f).factor(), unit=11) # optional - sage.libs.pari + sage: QQ['x'](f)._factor_pari_helper(pari(f).factor(), unit=11) (198) * (x + 1/2) * (x^2 - 5/3)^2 - sage: f = prod((k^2*x^k + k)^(k-1) for k in primes(10)) # optional - sage.libs.pari - sage: F = f._factor_pari_helper(pari(f).factor()); F # optional - sage.libs.pari + sage: # needs sage.libs.pari + sage: f = prod((k^2*x^k + k)^(k-1) for k in primes(10)) + sage: F = f._factor_pari_helper(pari(f).factor()); F 1323551250 * (2*x^2 + 1) * (3*x^3 + 1)^2 * (5*x^5 + 1)^4 * (7*x^7 + 1)^6 - sage: F.prod() == f # optional - sage.libs.pari + sage: F.prod() == f True - sage: QQ['x'](f)._factor_pari_helper(pari(f).factor()) # optional - sage.libs.pari + sage: QQ['x'](f)._factor_pari_helper(pari(f).factor()) (1751787911376562500) * (x^2 + 1/2) * (x^3 + 1/3)^2 * (x^5 + 1/5)^4 * (x^7 + 1/7)^6 - sage: g = GF(19)['x'](f) # optional - sage.libs.pari - sage: G = g._factor_pari_helper(pari(g).factor()); G # optional - sage.libs.pari + sage: # needs sage.libs.pari + sage: g = GF(19)['x'](f) + sage: G = g._factor_pari_helper(pari(g).factor()); G (4) * (x + 3) * (x + 16)^5 * (x + 11)^6 * (x^2 + 7*x + 9)^4 * (x^2 + 15*x + 9)^4 * (x^3 + 13)^2 * (x^6 + 8*x^5 + 7*x^4 + 18*x^3 + 11*x^2 + 12*x + 1)^6 - sage: G.prod() == g # optional - sage.libs.pari + sage: G.prod() == g True """ pols, exps = G @@ -4665,26 +4770,27 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: K. = (x^3 + 2).splitting_field(); K # optional - sage.rings.number_field + sage: K. = (x^3 + 2).splitting_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 - sage: K. = (x^3 - 3*x + 1).splitting_field(); K # optional - sage.rings.number_field + sage: K. = (x^3 - 3*x + 1).splitting_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 - 3*x + 1 Relative situation:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: K. = NumberField(x^3 + 2) # optional - sage.rings.number_field - sage: S. = PolynomialRing(K) # optional - sage.rings.number_field - sage: L. = (t^2 - a).splitting_field() # optional - sage.rings.number_field - sage: L # optional - sage.rings.number_field + sage: K. = NumberField(x^3 + 2) + sage: S. = PolynomialRing(K) + sage: L. = (t^2 - a).splitting_field() + sage: L Number Field in b with defining polynomial t^6 + 2 With ``map=True``, we also get the embedding of the base field into the splitting field:: - sage: L., phi = (t^2 - a).splitting_field(map=True) # optional - sage.rings.number_field - sage: phi # optional - sage.rings.number_field + sage: L., phi = (t^2 - a).splitting_field(map=True) # needs sage.rings.number_field + sage: phi # needs sage.rings.number_field Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 To: Number Field in b with defining polynomial t^6 + 2 @@ -4692,14 +4798,14 @@ cdef class Polynomial(CommutativePolynomial): An example over a finite field:: - sage: P. = PolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: t = x^2 + 1 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(7)) + sage: t = x^2 + 1 + sage: t.splitting_field('b') # needs sage.rings.finite_rings Finite Field in b of size 7^2 - sage: P. = PolynomialRing(GF(7^3, 'a')) # optional - sage.rings.finite_rings - sage: t = x^2 + 1 # optional - sage.rings.finite_rings - sage: t.splitting_field('b', map=True) # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(7^3, 'a')) # needs sage.rings.finite_rings + sage: t = x^2 + 1 + sage: t.splitting_field('b', map=True) # needs sage.rings.finite_rings (Finite Field in b of size 7^6, Ring morphism: From: Finite Field in a of size 7^3 @@ -4709,13 +4815,13 @@ cdef class Polynomial(CommutativePolynomial): If the extension is trivial and the generators have the same name, the map will be the identity:: - sage: t = 24*x^13 + 2*x^12 + 14 # optional - sage.rings.finite_rings - sage: t.splitting_field('a', map=True) # optional - sage.rings.finite_rings + sage: t = 24*x^13 + 2*x^12 + 14 + sage: t.splitting_field('a', map=True) # needs sage.rings.finite_rings (Finite Field in a of size 7^3, Identity endomorphism of Finite Field in a of size 7^3) - sage: t = x^56 - 14*x^3 # optional - sage.rings.finite_rings - sage: t.splitting_field('b', map=True) # optional - sage.rings.finite_rings + sage: t = x^56 - 14*x^3 + sage: t.splitting_field('b', map=True) # needs sage.rings.finite_rings (Finite Field in b of size 7^3, Ring morphism: From: Finite Field in a of size 7^3 @@ -4737,48 +4843,52 @@ cdef class Polynomial(CommutativePolynomial): ... NotImplementedError: splitting_field() is only implemented over number fields and finite fields - sage: P. = PolynomialRing(GF(11^5, 'a')) # optional - sage.rings.finite_rings - sage: t = x^2 + 1 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(11^5, 'a')) + sage: t = x^2 + 1 + sage: t.splitting_field('b') Finite Field in b of size 11^10 - sage: t = 24*x^13 + 2*x^12 + 14 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = 24*x^13 + 2*x^12 + 14 + sage: t.splitting_field('b') Finite Field in b of size 11^30 - sage: t = x^56 - 14*x^3 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = x^56 - 14*x^3 + sage: t.splitting_field('b') Finite Field in b of size 11^130 - sage: P. = PolynomialRing(GF(19^6, 'a')) # optional - sage.rings.finite_rings - sage: t = -x^6 + x^2 + 1 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(19^6, 'a')) + sage: t = -x^6 + x^2 + 1 + sage: t.splitting_field('b') Finite Field in b of size 19^6 - sage: t = 24*x^13 + 2*x^12 + 14 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = 24*x^13 + 2*x^12 + 14 + sage: t.splitting_field('b') Finite Field in b of size 19^18 - sage: t = x^56 - 14*x^3 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = x^56 - 14*x^3 + sage: t.splitting_field('b') Finite Field in b of size 19^156 - sage: P. = PolynomialRing(GF(83^6, 'a')) # optional - sage.rings.finite_rings - sage: t = 2*x^14 - 5 + 6*x # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(83^6, 'a')) + sage: t = 2*x^14 - 5 + 6*x + sage: t.splitting_field('b') Finite Field in b of size 83^84 - sage: t = 24*x^13 + 2*x^12 + 14 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = 24*x^13 + 2*x^12 + 14 + sage: t.splitting_field('b') Finite Field in b of size 83^78 - sage: t = x^56 - 14*x^3 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = x^56 - 14*x^3 + sage: t.splitting_field('b') Finite Field in b of size 83^12 - sage: P. = PolynomialRing(GF(401^13, 'a')) # optional - sage.rings.finite_rings - sage: t = 2*x^14 - 5 + 6*x # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: P. = PolynomialRing(GF(401^13, 'a')) + sage: t = 2*x^14 - 5 + 6*x + sage: t.splitting_field('b') Finite Field in b of size 401^104 - sage: t = 24*x^13 + 2*x^12 + 14 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = 24*x^13 + 2*x^12 + 14 + sage: t.splitting_field('b') Finite Field in b of size 401^156 - sage: t = x^56 - 14*x^3 # optional - sage.rings.finite_rings - sage: t.splitting_field('b') # optional - sage.rings.finite_rings + sage: t = x^56 - 14*x^3 + sage: t.splitting_field('b') Finite Field in b of size 401^52 sage: R. = QQ[] @@ -4908,22 +5018,23 @@ cdef class Polynomial(CommutativePolynomial): One can easily add gcd functionality to new rings by providing a method ``_gcd_univariate_polynomial``:: - sage: O = ZZ[-sqrt(5)] # optional - sage.rings.number_field sage.symbolic - sage: R. = O[] # optional - sage.rings.number_field sage.symbolic - sage: a = O.1 # optional - sage.rings.number_field sage.symbolic - sage: p = x + a # optional - sage.rings.number_field sage.symbolic - sage: q = x^2 - 5 # optional - sage.rings.number_field sage.symbolic - sage: p.gcd(q) # optional - sage.rings.number_field sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: O = ZZ[-sqrt(5)] + sage: R. = O[] + sage: a = O.1 + sage: p = x + a + sage: q = x^2 - 5 + sage: p.gcd(q) Traceback (most recent call last): ... NotImplementedError: Order in Number Field in a with defining polynomial x^2 - 5 with a = -2.236067977499790? does not provide a gcd implementation for univariate polynomials - sage: S. = O.number_field()[] # optional - sage.rings.number_field sage.symbolic - sage: O._gcd_univariate_polynomial = lambda f, g: R(S(f).gcd(S(g))) # optional - sage.rings.number_field sage.symbolic - sage: p.gcd(q) # optional - sage.rings.number_field sage.symbolic + sage: S. = O.number_field()[] + sage: O._gcd_univariate_polynomial = lambda f, g: R(S(f).gcd(S(g))) + sage: p.gcd(q) x + a - sage: del O._gcd_univariate_polynomial # optional - sage.rings.number_field sage.symbolic + sage: del O._gcd_univariate_polynomial Use multivariate implementation for polynomials over polynomials rings:: @@ -4933,7 +5044,7 @@ cdef class Polynomial(CommutativePolynomial): sage: r = 2*x*y + z sage: p = r * (3*x*y*z - 1) sage: q = r * (x + y + z - 2) - sage: p.gcd(q) # optional - sage.libs.singular + sage: p.gcd(q) # needs sage.libs.singular z + 2*x*y sage: R. = QQ[] @@ -4941,13 +5052,13 @@ cdef class Polynomial(CommutativePolynomial): sage: r = 2*x*y + 1 sage: p = r * (x - 1/2 * y) sage: q = r * (x*y^2 - x + 1/3) - sage: p.gcd(q) # optional - sage.libs.singular + sage: p.gcd(q) # needs sage.libs.singular 2*x*y + 1 TESTS:: sage: Pol = QQ['x','y']['x'] - sage: Pol.one().gcd(1) # optional - sage.libs.singular + sage: Pol.one().gcd(1) 1 """ cdef Polynomial _other = other @@ -4977,8 +5088,8 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`32033` has been fixed:: - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: lcm(R(0), R(0)) # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: lcm(R(0), R(0)) 0 :: @@ -5053,26 +5164,27 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: R. = GF(2)['x'] # optional - sage.rings.finite_rings - sage: f = x^4 + x^3 + x^2 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_irreducible(), f.is_primitive() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(2)['x'] + sage: f = x^4 + x^3 + x^2 + x + 1 + sage: f.is_irreducible(), f.is_primitive() (True, False) - sage: f = x^3 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_irreducible(), f.is_primitive() # optional - sage.rings.finite_rings + sage: f = x^3 + x + 1 + sage: f.is_irreducible(), f.is_primitive() (True, True) - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: f = x^3 - x + 1 # optional - sage.rings.finite_rings - sage: f.is_irreducible(), f.is_primitive() # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: f = x^3 - x + 1 + sage: f.is_irreducible(), f.is_primitive() (True, True) - sage: f = x^2 + 1 # optional - sage.rings.finite_rings - sage: f.is_irreducible(), f.is_primitive() # optional - sage.rings.finite_rings + sage: f = x^2 + 1 + sage: f.is_irreducible(), f.is_primitive() (True, False) - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: f = x^2 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive() # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: f = x^2 + x + 1 + sage: f.is_primitive() False - sage: f = x^2 - x + 2 # optional - sage.rings.finite_rings - sage: f.is_primitive() # optional - sage.rings.finite_rings + sage: f = x^2 - x + 2 + sage: f.is_primitive() True sage: x = polygen(QQ); f = x^2 + 1 sage: f.is_primitive() @@ -5084,7 +5196,7 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: x=polygen(ZZ) + sage: x = polygen(ZZ) sage: f = 5*x^2 + 2 sage: f.is_primitive() True @@ -5092,16 +5204,17 @@ cdef class Polynomial(CommutativePolynomial): sage: f.is_primitive() False - sage: K = NumberField(x^2 + 5, 'a') # optional - sage.rings.number_field - sage: R = K.ring_of_integers() # optional - sage.rings.number_field - sage: a = R.gen(1) # optional - sage.rings.number_field - sage: a^2 # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K = NumberField(x^2 + 5, 'a') + sage: R = K.ring_of_integers() + sage: a = R.gen(1) + sage: a^2 -5 - sage: f = a*x + 2 # optional - sage.rings.number_field - sage: f.is_primitive() # optional - sage.rings.number_field + sage: f = a*x + 2 + sage: f.is_primitive() True - sage: f = (1+a)*x + 2 # optional - sage.rings.number_field - sage: f.is_primitive() # optional - sage.rings.number_field + sage: f = (1+a)*x + 2 + sage: f.is_primitive() False sage: x = polygen(Integers(10)) @@ -5112,33 +5225,34 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: R. = GF(2)['x'] # optional - sage.rings.finite_rings - sage: f = x^4 + x^3 + x^2 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive(15) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(2)['x'] + sage: f = x^4 + x^3 + x^2 + x + 1 + sage: f.is_primitive(15) False - sage: f.is_primitive(15, [3,5]) # optional - sage.rings.finite_rings + sage: f.is_primitive(15, [3,5]) False - sage: f.is_primitive(n_prime_divs=[3,5]) # optional - sage.rings.finite_rings + sage: f.is_primitive(n_prime_divs=[3,5]) False - sage: f = x^3 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive(7, [7]) # optional - sage.rings.finite_rings + sage: f = x^3 + x + 1 + sage: f.is_primitive(7, [7]) True - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: f = x^3 - x + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive(26, [2,13]) # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: f = x^3 - x + 1 + sage: f.is_primitive(26, [2,13]) True - sage: f = x^2 + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive(8, [2]) # optional - sage.rings.finite_rings + sage: f = x^2 + 1 + sage: f.is_primitive(8, [2]) False - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: f = x^2 + x + 1 # optional - sage.rings.finite_rings - sage: f.is_primitive(24, [2,3]) # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: f = x^2 + x + 1 + sage: f.is_primitive(24, [2,3]) False - sage: f = x^2 - x + 2 # optional - sage.rings.finite_rings - sage: f.is_primitive(24, [2,3]) # optional - sage.rings.finite_rings + sage: f = x^2 - x + 2 + sage: f.is_primitive(24, [2,3]) True sage: x = polygen(Integers(103)); f = x^2 + 1 - sage: f.is_primitive() # optional - sage.rings.finite_rings + sage: f.is_primitive() False """ R = self.base_ring() @@ -5255,56 +5369,58 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ['x'] sage: f = x^3 + x + 17 - sage: f.root_field('a') # optional - sage.rings.number_field + sage: f.root_field('a') # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + x + 17 :: sage: R. = QQ['x'] sage: f = x - 3 - sage: f.root_field('b') # optional - sage.rings.number_field + sage: f.root_field('b') # needs sage.rings.number_field Rational Field :: sage: R. = ZZ['x'] sage: f = x^3 + x + 17 - sage: f.root_field('b') # optional - sage.rings.number_field + sage: f.root_field('b') # needs sage.rings.number_field Number Field in b with defining polynomial x^3 + x + 17 :: + sage: # needs sage.rings.number_field sage: y = QQ['x'].0 - sage: L. = NumberField(y^3 - 2) # optional - sage.rings.number_field - sage: R. = L['x'] # optional - sage.rings.number_field - sage: f = x^3 + x + 17 # optional - sage.rings.number_field - sage: f.root_field('c') # optional - sage.rings.number_field + sage: L. = NumberField(y^3 - 2) + sage: R. = L['x'] + sage: f = x^3 + x + 17 + sage: f.root_field('c') Number Field in c with defining polynomial x^3 + x + 17 over its base field :: - sage: R. = PolynomialRing(GF(9, 'a')) # optional - sage.rings.finite_rings - sage: f = x^3 + x^2 + 8 # optional - sage.rings.finite_rings - sage: K. = f.root_field(); K # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(9, 'a')) + sage: f = x^3 + x^2 + 8 + sage: K. = f.root_field(); K Univariate Quotient Polynomial Ring in alpha over Finite Field in a of size 3^2 with modulus x^3 + x^2 + 2 - sage: alpha^2 + 1 # optional - sage.rings.finite_rings + sage: alpha^2 + 1 alpha^2 + 1 - sage: alpha^3 + alpha^2 # optional - sage.rings.finite_rings + sage: alpha^3 + alpha^2 1 :: sage: R. = QQ[] sage: f = x^2 - sage: K. = f.root_field() # optional - sage.libs.pari + sage: K. = f.root_field() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: polynomial must be irreducible TESTS:: - sage: (PolynomialRing(Integers(31), name='x').0 + 5).root_field('a') # optional - sage.rings.finite_rings + sage: (PolynomialRing(Integers(31), name='x').0 + 5).root_field('a') # needs sage.rings.finite_rings Ring of integers modulo 31 """ R = self.base_ring() @@ -5317,6 +5433,8 @@ cdef class Polynomial(CommutativePolynomial): if self.degree() <= 1: return R.fraction_field() + from sage.rings.number_field.number_field import is_NumberField, NumberField + if is_IntegerRing(R): from sage.rings.number_field.number_field import NumberField return NumberField(self, names) @@ -5347,7 +5465,7 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = PolynomialRing(ZZ) sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) - sage: M = f.sylvester_matrix(g); M # optional - sage.modules + sage: M = f.sylvester_matrix(g); M # needs sage.modules [ 42 317 134 1786 0 0 0] [ 0 42 317 134 1786 0 0] [ 0 0 42 317 134 1786 0] @@ -5359,7 +5477,7 @@ cdef class Polynomial(CommutativePolynomial): If the polynomials share a non-constant common factor then the determinant of the Sylvester matrix will be zero:: - sage: M.determinant() # optional - sage.modules + sage: M.determinant() # needs sage.modules 0 If ``self`` and ``right`` are polynomials of positive degree, the determinant @@ -5367,16 +5485,16 @@ cdef class Polynomial(CommutativePolynomial): sage: h1 = R._random_nonzero_element() sage: h2 = R._random_nonzero_element() - sage: M1 = h1.sylvester_matrix(h2) # optional - sage.modules - sage: M1.determinant() == h1.resultant(h2) # optional - sage.libs.pari sage.modules + sage: M1 = h1.sylvester_matrix(h2) # needs sage.modules + sage: M1.determinant() == h1.resultant(h2) # needs sage.libs.pari sage.modules True The rank of the Sylvester matrix is related to the degree of the gcd of ``self`` and ``right``:: - sage: f.gcd(g).degree() == f.degree() + g.degree() - M.rank() # optional - sage.modules + sage: f.gcd(g).degree() == f.degree() + g.degree() - M.rank() # needs sage.modules True - sage: h1.gcd(h2).degree() == h1.degree() + h2.degree() - M1.rank() # optional - sage.modules + sage: h1.gcd(h2).degree() == h1.degree() + h2.degree() - M1.rank() # needs sage.modules True TESTS: @@ -5386,10 +5504,10 @@ cdef class Polynomial(CommutativePolynomial): sage: K. = QQ['x'] sage: f = x + 1 sage: g = QQ['y']([1, 0, 1]) - sage: f.sylvester_matrix(f, x) # optional - sage.modules + sage: f.sylvester_matrix(f, x) # needs sage.modules [1 1] [1 1] - sage: f.sylvester_matrix(g, x) # optional - sage.modules + sage: f.sylvester_matrix(g, x) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -5400,18 +5518,18 @@ cdef class Polynomial(CommutativePolynomial): sage: f = QQ['x']([1, 0, 1]) sage: g = ZZ['x']([1, 0, 1]) - sage: h = GF(25, 'a')['x']([1, 0, 1]) # optional - sage.rings.finite_rings - sage: f.sylvester_matrix(g) # optional - sage.modules + sage: h = GF(25, 'a')['x']([1, 0, 1]) # needs sage.rings.finite_rings + sage: f.sylvester_matrix(g) # needs sage.modules [1 0 1 0] [0 1 0 1] [1 0 1 0] [0 1 0 1] - sage: g.sylvester_matrix(h) # optional - sage.rings.finite_rings sage.modules + sage: g.sylvester_matrix(h) # needs sage.modules sage.rings.finite_rings [1 0 1 0] [0 1 0 1] [1 0 1 0] [0 1 0 1] - sage: f.sylvester_matrix(h) # optional - sage.rings.finite_rings sage.modules + sage: f.sylvester_matrix(h) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -5423,30 +5541,31 @@ cdef class Polynomial(CommutativePolynomial): sage: K. = QQ['x,y'] sage: g = K.random_element() - sage: f.sylvester_matrix(g) == K(f).sylvester_matrix(g, x) # optional - sage.modules + sage: f.sylvester_matrix(g) == K(f).sylvester_matrix(g, x) # needs sage.modules True Corner cases:: + sage: # needs sage.modules sage: K. = QQ[] sage: f = x^2 + 1 sage: g = K(0) - sage: f.sylvester_matrix(g) # optional - sage.modules + sage: f.sylvester_matrix(g) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: g.sylvester_matrix(f) # optional - sage.modules + sage: g.sylvester_matrix(f) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: g.sylvester_matrix(g) # optional - sage.modules + sage: g.sylvester_matrix(g) Traceback (most recent call last): ... ValueError: The Sylvester matrix is not defined for zero polynomials - sage: K(3).sylvester_matrix(x^2) # optional - sage.modules + sage: K(3).sylvester_matrix(x^2) [3 0] [0 3] - sage: K(3).sylvester_matrix(K(4)) # optional - sage.modules + sage: K(3).sylvester_matrix(K(4)) [] """ @@ -5518,10 +5637,10 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = PolynomialRing(GF(9, 'a'), sparse=True) # optional - sage.rings.finite_rings - sage: a = w._new_constant_poly(0, R); a # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(9, 'a'), sparse=True) # needs sage.rings.finite_rings + sage: a = w._new_constant_poly(0, R); a # needs sage.rings.finite_rings 0 - sage: a.coefficients() # optional - sage.rings.finite_rings + sage: a.coefficients() # needs sage.rings.finite_rings [] """ t = type(self) @@ -5564,12 +5683,14 @@ cdef class Polynomial(CommutativePolynomial): sage: b = a(2*191*236607587) sage: b.is_nilpotent() True - sage: R. = a[] # optional - sage.libs.pari - sage: f = 3 + b*x + b^2*x^2 # optional - sage.libs.pari - sage: f.is_unit() # optional - sage.libs.pari + + sage: # needs sage.libs.pari + sage: R. = a[] + sage: f = 3 + b*x + b^2*x^2 + sage: f.is_unit() True - sage: f = 3 + b*x + b^2*x^2 + 17*x^3 # optional - sage.libs.pari - sage: f.is_unit() # optional - sage.libs.pari + sage: f = 3 + b*x + b^2*x^2 + 17*x^3 + sage: f.is_unit() False EXERCISE (Atiyah-McDonald, Ch 1): Let `A[x]` be a @@ -5830,72 +5951,73 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = 3*x^3 + 2*x^2 + x - sage: exp(f.global_height()) + sage: exp(f.global_height()) # needs sage.symbolic 3.00000000000000 Scaling should not change the result:: sage: R. = PolynomialRing(QQ) sage: f = 1/25*x^2 + 25/3*x + 1 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 sage: g = 100 * f - sage: g.global_height() + sage: g.global_height() # needs sage.symbolic 6.43775164973640 :: - sage: R. = PolynomialRing(QQbar) # optional - sage.rings.number_field - sage: f = QQbar(i)*x^2 + 3*x # optional - sage.rings.number_field - sage: f.global_height() # optional - sage.rings.number_field + sage: R. = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: f = QQbar(i)*x^2 + 3*x # needs sage.rings.number_field + sage: f.global_height() # needs sage.rings.number_field 1.09861228866811 :: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: K. = NumberField(x^2 + 5) # optional - sage.rings.number_field - sage: T. = PolynomialRing(K) # optional - sage.rings.number_field - sage: f = 1/1331 * t^2 + 5 * t + 7 # optional - sage.rings.number_field - sage: f.global_height() # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 5) + sage: T. = PolynomialRing(K) + sage: f = 1/1331 * t^2 + 5 * t + 7 + sage: f.global_height() 9.13959596745043 :: sage: R. = QQ[] sage: f = 1/123*x^2 + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: sage: R. = QQ[] sage: f = 0*x - sage: f.global_height() + sage: f.global_height() # needs sage.rings.real_mpfr 0.000000000000000 """ if prec is None: prec = 53 if self.is_zero(): + from sage.rings.real_mpfr import RealField return RealField(prec).zero() - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields - from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics K = self.base_ring() - if K in NumberFields() or is_NumberFieldOrder(K): + if K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K): from sage.schemes.projective.projective_space import ProjectiveSpace P = ProjectiveSpace(K, self.number_of_terms()-1) return P.point(self.coefficients()).global_height(prec=prec) - elif K is QQbar: - K_pre, P, phi = number_field_elements_from_algebraics(self.coefficients()) + elif isinstance(K, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import number_field_elements_from_algebraics from sage.schemes.projective.projective_space import ProjectiveSpace + + K_pre, P, phi = number_field_elements_from_algebraics(self.coefficients()) Pr = ProjectiveSpace(K_pre, len(P)-1) return Pr.point(P).global_height(prec=prec) raise TypeError("Must be over a Numberfield or a Numberfield Order.") - def local_height(self, v, prec=None): """ Return the maximum of the local height of the coefficients of @@ -5914,34 +6036,34 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = 1/1331*x^2 + 1/4000*x - sage: f.local_height(1331) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^2 - 5) # optional - sage.rings.number_field - sage: T. = K[] # optional - sage.rings.number_field - sage: I = K.ideal(3) # optional - sage.rings.number_field - sage: f = 1/3*t^2 + 3 # optional - sage.rings.number_field - sage: f.local_height(I) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 5) + sage: T. = K[] + sage: I = K.ideal(3) + sage: f = 1/3*t^2 + 3 + sage: f.local_height(I) 1.09861228866811 :: sage: R. = QQ[] sage: f = 1/2*x^2 + 2 - sage: f.local_height(2, prec=2) + sage: f.local_height(2, prec=2) # needs sage.rings.real_mpfr 0.75 """ - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K)): raise TypeError("must be over a Numberfield or a Numberfield order") return max([K(c).local_height(v, prec=prec) for c in self.coefficients()]) @@ -5964,33 +6086,33 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = 210*x^2 - sage: f.local_height_arch(0) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: + sage: # needs sage.rings.number_field sage: R. = QQ[] - sage: K. = NumberField(x^2 - 5) # optional - sage.rings.number_field - sage: T. = K[] # optional - sage.rings.number_field - sage: f = 1/2*t^2 + 3 # optional - sage.rings.number_field - sage: f.local_height_arch(1, prec=52) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 - 5) + sage: T. = K[] + sage: f = 1/2*t^2 + 3 + sage: f.local_height_arch(1, prec=52) 1.09861228866811 :: sage: R. = QQ[] sage: f = 1/2*x^2 + 3 - sage: f.local_height_arch(0, prec=2) + sage: f.local_height_arch(0, prec=2) # needs sage.rings.real_mpfr 1.0 """ - from sage.rings.number_field.order import is_NumberFieldOrder from sage.categories.number_fields import NumberFields if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K)): return TypeError("must be over a Numberfield or a Numberfield Order") if K == QQ: @@ -6186,11 +6308,13 @@ cdef class Polynomial(CommutativePolynomial): sage: f = - 1/2*x^2 + x^9 + 7*x + 5/11 sage: f.monomials() [x^9, x^2, x, 1] + + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = NumberField(x**2 + 1) # optional - sage.rings.number_field - sage: R. = QQ[] # optional - sage.rings.number_field - sage: p = rho * y # optional - sage.rings.number_field - sage: p.monomials() # optional - sage.rings.number_field + sage: K. = NumberField(x**2 + 1) + sage: R. = QQ[] + sage: p = rho * y + sage: p.monomials() [y] """ if self.is_zero(): @@ -6225,9 +6349,9 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: x = PolynomialRing(RealField(), 'x').gen() - sage: f = x^2 - 2 - sage: f.newton_raphson(4, 1) + sage: x = PolynomialRing(RealField(), 'x').gen() # needs sage.rings.real_mpfr + sage: f = x^2 - 2 # needs sage.rings.real_mpfr + sage: f.newton_raphson(4, 1) # needs sage.rings.real_mpfr [1.50000000000000, 1.41666666666667, 1.41421568627451, 1.41421356237469] AUTHORS: @@ -6287,11 +6411,11 @@ cdef class Polynomial(CommutativePolynomial): sage: x = QQ['x'].0 sage: f = x^3 + 2 - sage: f.newton_slopes(2) # optional - sage.libs.pari + sage: f.newton_slopes(2) # needs sage.libs.pari [1/3, 1/3, 1/3] sage: R. = PolynomialRing(ZZ, sparse=True) sage: p = x^5 + 6*x^2 + 4 - sage: p.newton_slopes(2) # optional - sage.libs.pari + sage: p.newton_slopes(2) # needs sage.libs.pari [1/2, 1/2, 1/3, 1/3, 1/3] sage: p.newton_slopes(2, lengths=True) [(1/2, 2), (1/3, 3)] @@ -6348,13 +6472,13 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: Pol. = QQ[] - sage: x.dispersion_set(x + 1) # optional - sage.libs.pari + sage: x.dispersion_set(x + 1) # needs sage.libs.pari [1] - sage: (x + 1).dispersion_set(x) # optional - sage.libs.pari + sage: (x + 1).dispersion_set(x) # needs sage.libs.pari [] sage: pol = x^3 + x - 7 - sage: (pol*pol(x+3)^2).dispersion_set() # optional - sage.libs.pari + sage: (pol*pol(x+3)^2).dispersion_set() # needs sage.libs.pari [0, 3] """ other = self if other is None else self._parent.coerce(other) @@ -6395,16 +6519,17 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: Pol. = QQ[] - sage: x.dispersion(x + 1) # optional - sage.libs.pari + sage: x.dispersion(x + 1) # needs sage.libs.pari 1 - sage: (x + 1).dispersion(x) # optional - sage.libs.pari + sage: (x + 1).dispersion(x) # needs sage.libs.pari -Infinity - sage: Pol. = QQbar[] # optional - sage.libs.pari sage.rings.number_field - sage: pol = Pol([sqrt(5), 1, 3/2]) # optional - sage.libs.pari sage.rings.number_field sage.symbolic - sage: pol.dispersion() # optional - sage.libs.pari sage.rings.number_field sage.symbolic + sage: # needs sage.libs.pari sage.rings.number_field sage.symbolic + sage: Pol. = QQbar[] + sage: pol = Pol([sqrt(5), 1, 3/2]) + sage: pol.dispersion() 0 - sage: (pol*pol(x+3)).dispersion() # optional - sage.libs.pari sage.rings.number_field sage.symbolic + sage: (pol*pol(x+3)).dispersion() 3 """ dispersions = self.dispersion_set(other) @@ -6425,7 +6550,7 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: f = QQ['x']([0,1,2/3,3]) - sage: pari(f) # optional - sage.libs.pari + sage: pari(f) # needs sage.libs.pari 3*x^3 + 2/3*x^2 + x :: @@ -6433,18 +6558,19 @@ cdef class Polynomial(CommutativePolynomial): sage: S. = QQ['a'] sage: R. = S['x'] sage: f = R([0, a]) + R([0, 0, 2/3]) - sage: pari(f) # optional - sage.libs.pari + sage: pari(f) # needs sage.libs.pari 2/3*x^2 + a*x Polynomials over a number field work, provided that the variable is called 'x':: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K. = NumberField(x^2 + x + 1) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - sage: pol = (b + x)^3; pol # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + x + 1) + sage: R. = PolynomialRing(K) + sage: pol = (b + x)^3; pol x^3 + 3*b*x^2 + (-3*b - 3)*x + 1 - sage: pari(pol) # optional - sage.libs.pari sage.rings.number_field + sage: pari(pol) # needs sage.libs.pari Mod(1, y^2 + y + 1)*x^3 + Mod(3*y, y^2 + y + 1)*x^2 + Mod(-3*y - 3, y^2 + y + 1)*x + Mod(1, y^2 + y + 1) @@ -6455,7 +6581,7 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a; g = y^3 + a - sage: pari(f) # optional - sage.libs.pari + sage: pari(f) # needs sage.libs.pari Traceback (most recent call last): ... PariError: incorrect priority in gtopoly: variable x <= a @@ -6465,9 +6591,9 @@ cdef class Polynomial(CommutativePolynomial): sage: S. = QQ['a'] sage: R. = S['x'] - sage: pari(x^2 + 2*x) # optional - sage.libs.pari + sage: pari(x^2 + 2*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 2*x^3) # optional - sage.libs.pari + sage: pari(a*x + 2*x^3) # needs sage.libs.pari 2*x^3 + a*x Stacked polynomial rings, second with a multivariate ring on the @@ -6475,27 +6601,27 @@ cdef class Polynomial(CommutativePolynomial): sage: S. = ZZ['a', 'b'] sage: R. = S['x'] - sage: pari(x^2 + 2*x) # optional - sage.libs.pari + sage: pari(x^2 + 2*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 2*b*x^3) # optional - sage.libs.pari + sage: pari(a*x + 2*b*x^3) # needs sage.libs.pari 2*b*x^3 + a*x Stacked polynomial rings with exotic base rings:: - sage: S. = GF(7)['a', 'b'] # optional - sage.rings.finite_rings - sage: R. = S['x'] # optional - sage.rings.finite_rings - sage: pari(x^2 + 9*x) # optional - sage.rings.finite_rings + sage: S. = GF(7)['a', 'b'] + sage: R. = S['x'] + sage: pari(x^2 + 9*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 9*b*x^3) # optional - sage.rings.finite_rings + sage: pari(a*x + 9*b*x^3) # needs sage.libs.pari 2*b*x^3 + a*x :: sage: S. = Integers(8)['a'] sage: R. = S['x'] - sage: pari(x^2 + 2*x) # optional - sage.libs.pari + sage: pari(x^2 + 2*x) # needs sage.libs.pari Mod(1, 8)*x^2 + Mod(2, 8)*x - sage: pari(a*x + 10*x^3) # optional - sage.libs.pari + sage: pari(a*x + 10*x^3) # needs sage.libs.pari Mod(2, 8)*x^3 + Mod(1, 8)*a*x """ return self._pari_with_name(self._parent.variable_name()) @@ -6514,20 +6640,21 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = 2*x^2 + 7*x - 5 - sage: pol._pari_or_constant() # optional - sage.libs.pari + sage: pol._pari_or_constant() 2*x^2 + 7*x - 5 - sage: pol._pari_or_constant('a') # optional - sage.libs.pari + sage: pol._pari_or_constant('a') 2*a^2 + 7*a - 5 sage: pol = R(7) - sage: pol._pari_or_constant() # optional - sage.libs.pari + sage: pol._pari_or_constant() 7 - sage: pol._pari_or_constant().type() # optional - sage.libs.pari + sage: pol._pari_or_constant().type() 't_INT' - sage: pol.__pari__().type() # optional - sage.libs.pari + sage: pol.__pari__().type() 't_POL' - sage: PolynomialRing(IntegerModRing(101), 't')()._pari_or_constant() # optional - sage.libs.pari + sage: PolynomialRing(IntegerModRing(101), 't')()._pari_or_constant() Mod(0, 101) """ if self.is_constant(): @@ -6546,9 +6673,9 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: (2*a^2 + a)._pari_with_name() # optional - sage.libs.pari + sage: (2*a^2 + a)._pari_with_name() # needs sage.libs.pari 2*x^2 + x - sage: (2*a^2 + a)._pari_with_name('y') # optional - sage.libs.pari + sage: (2*a^2 + a)._pari_with_name('y') # needs sage.libs.pari 2*y^2 + y """ vals = [x.__pari__() for x in self.list()] @@ -6563,12 +6690,13 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: magma = Magma() # new session # optional - magma + sage: # optional - magma + sage: magma = Magma() # new session sage: R. = ZZ[] sage: f = y^3 - 17*y + 5 - sage: f._magma_init_(magma) # optional - magma + sage: f._magma_init_(magma) '_sage_[...]![5,-17,0,1]' - sage: g = magma(f); g # optional - magma + sage: g = magma(f); g y^3 - 17*y + 5 Note that in Magma there is only one polynomial ring over each @@ -6577,20 +6705,21 @@ cdef class Polynomial(CommutativePolynomial): we already defined:: sage: R. = ZZ[] - sage: magma(R) # optional - magma + sage: magma(R) # optional - magma Univariate Polynomial Ring in z over Integer Ring - sage: g # optional - magma + sage: g # optional - magma z^3 - 17*z + 5 In Sage the variable name does not change:: - sage: f + sage: f # optional - magma y^3 - 17*y + 5 A more complicated nested example:: - sage: k. = GF(9); R. = k[]; S. = R[] # optional - sage.rings.finite_rings - sage: magma(a*W^20 + s*t/a) # optional - magma # optional - sage.rings.finite_rings + sage: # optional - magma, needs sage.rings.finite_rings + sage: k. = GF(9); R. = k[]; S. = R[] + sage: magma(a*W^20 + s*t/a) a*W^20 + a^7*s*t """ # Get a reference to Magma version of parent. @@ -6609,35 +6738,37 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.gap sage: R. = ZZ[] sage: f = y^3 - 17*y + 5 - sage: g = gap(f); g # indirect doctest # optional - sage.libs.gap + sage: g = gap(f); g # indirect doctest y^3-17*y+5 - sage: f._gap_init_() # optional - sage.libs.gap + sage: f._gap_init_() 'y^3 - 17*y + 5' sage: R. = ZZ[] - sage: gap(R) # optional - sage.libs.gap + sage: gap(R) PolynomialRing( Integers, ["z"] ) - sage: g # optional - sage.libs.gap + sage: g y^3-17*y+5 - sage: gap(z^2 + z) # optional - sage.libs.gap + sage: gap(z^2 + z) z^2+z - sage: libgap(z^2 + z) # optional - sage.libs.gap + sage: libgap(z^2 + z) z^2+z Coefficients in a finite field:: - sage: R. = GF(7)[] # optional - sage.rings.finite_rings - sage: f = y^3 - 17*y + 5 # optional - sage.rings.finite_rings - sage: g = gap(f); g # optional - sage.libs.gap sage.rings.finite_rings + sage: # needs sage.libs.gap + sage: R. = GF(7)[] + sage: f = y^3 - 17*y + 5 + sage: g = gap(f); g y^3+Z(7)^4*y+Z(7)^5 - sage: h = libgap(f); h # optional - sage.libs.gap sage.rings.finite_rings + sage: h = libgap(f); h y^3+Z(7)^4*y+Z(7)^5 - sage: g.Factors() # optional - sage.libs.gap sage.rings.finite_rings + sage: g.Factors() [ y+Z(7)^0, y+Z(7)^0, y+Z(7)^5 ] - sage: h.Factors() # optional - sage.libs.gap sage.rings.finite_rings + sage: h.Factors() [ y+Z(7)^0, y+Z(7)^0, y+Z(7)^5 ] - sage: f.factor() # optional - sage.libs.gap sage.rings.finite_rings + sage: f.factor() (y + 5) * (y + 1)^2 """ R = gap(self._parent) @@ -6649,9 +6780,9 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: sage: R. = ZZ[] - sage: libgap(-x^3 + 3*x) # indirect doctest # optional - sage.libs.gap + sage: libgap(-x^3 + 3*x) # indirect doctest # needs sage.libs.gap -x^3+3*x - sage: libgap(R.zero()) # indirect doctest # optional - sage.libs.gap + sage: libgap(R.zero()) # indirect doctest # needs sage.libs.gap 0 """ from sage.libs.gap.libgap import libgap @@ -6663,13 +6794,14 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: R. = GF(101)['e,i'][] # optional - sage.rings.finite_rings - sage: f = R('e*i') * x + x^2 # optional - sage.rings.finite_rings - sage: f._giac_init_() # optional - sage.rings.finite_rings + sage: # needs sage.libs.giac + sage: R. = GF(101)['e,i'][] + sage: f = R('e*i') * x + x^2 + sage: f._giac_init_() '((1)*1)*sageVARx^2+((1)*sageVARe*sageVARi)*sageVARx' - sage: giac(f) # optional - sage.rings.finite_rings + sage: giac(f) sageVARx^2+sageVARe*sageVARi*sageVARx - sage: giac(R.zero()) # optional - sage.rings.finite_rings + sage: giac(R.zero()) 0 """ g = 'sageVAR' + self.variable_name() @@ -6700,9 +6832,9 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^3 + x + 1; g = x^3 - x - 1 - sage: r = f.resultant(g); r # optional - sage.libs.pari + sage: r = f.resultant(g); r # needs sage.libs.pari -8 - sage: r.parent() is QQ # optional - sage.libs.pari + sage: r.parent() is QQ # needs sage.libs.pari True We can compute resultants over univariate and multivariate @@ -6711,9 +6843,9 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a; g = x^3 + a - sage: r = f.resultant(g); r # optional - sage.libs.pari + sage: r = f.resultant(g); r # needs sage.libs.pari a^3 + a^2 - sage: r.parent() is R # optional - sage.libs.pari + sage: r.parent() is R # needs sage.libs.pari True :: @@ -6721,9 +6853,9 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a; g = x^3 + b - sage: r = f.resultant(g); r # optional - sage.libs.pari + sage: r = f.resultant(g); r # needs sage.libs.pari a^3 + b^2 - sage: r.parent() is R # optional - sage.libs.pari + sage: r.parent() is R # needs sage.libs.pari True TESTS:: @@ -6731,18 +6863,18 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a; g = y^3 + a - sage: h = f.resultant(g); h # optional - sage.libs.pari + sage: h = f.resultant(g); h # needs sage.libs.pari y^3 - x^2 - sage: h.parent() is R # optional - sage.libs.pari + sage: h.parent() is R # needs sage.libs.pari True Check that :trac:`13672` is fixed:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: f = (t^2 + t)*x + t^2 + t # optional - sage.rings.finite_rings - sage: g = (t + 1)*x + t^2 # optional - sage.rings.finite_rings - sage: f.resultant(g) # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: S. = R[] + sage: f = (t^2 + t)*x + t^2 + t + sage: g = (t + 1)*x + t^2 + sage: f.resultant(g) # needs sage.libs.pari t^4 + t Check that :trac:`15061` is fixed:: @@ -6751,23 +6883,24 @@ cdef class Polynomial(CommutativePolynomial): sage: F = R([1,1],2) sage: RP. = PolynomialRing(R) sage: P = x^2 - F - sage: P.resultant(P.derivative()) # optional - sage.libs.pari + sage: P.resultant(P.derivative()) # needs sage.libs.pari -4 - 4*T + O(T^2) Check that :trac:`16360` is fixed:: sage: K. = FunctionField(QQ) sage: R. = K[] - sage: y.resultant(y + x) # optional - sage.libs.pari + sage: y.resultant(y + x) # needs sage.libs.pari x + sage: # needs sage.libs.singular sage: K. = FunctionField(QQ) sage: R. = K[] - sage: L. = K.extension(b^2 - a) # optional - sage.libs.singular - sage: R. = L[] # optional - sage.libs.singular - sage: f = x^2 - a # optional - sage.libs.singular - sage: g = x - b # optional - sage.libs.singular - sage: f.resultant(g) # optional - sage.libs.pari sage.libs.singular + sage: L. = K.extension(b^2 - a) + sage: R. = L[] + sage: f = x^2 - a + sage: g = x - b + sage: f.resultant(g) # needs sage.libs.pari 0 Check that :trac:`17817` is fixed:: @@ -6778,16 +6911,19 @@ cdef class Polynomial(CommutativePolynomial): sage: S. = PolynomialRing(R,'y') sage: p = ((1/b^2*d^2+1/a)*x*y^2+a*b/c*y+e+x^2) sage: q = -4*c^2*y^3+1 - sage: p.resultant(q) # optional - sage.libs.pari - (16*c^4)*x^6 + (48*c^4)*e*x^4 + (1/(b^6)*d^6 + 3/(a*b^4)*d^4 + (-12*a^3*b*c + 3)/(a^2*b^2)*d^2 + (-12*a^3*b*c + 1)/(a^3))*x^3 + (48*c^4)*e^2*x^2 + ((-12*a*c)/b*d^2*e + (-12*b*c)*e)*x + (16*c^4)*e^3 + (4*a^3*b^3)/c + sage: p.resultant(q) # needs sage.libs.pari + (16*c^4)*x^6 + (48*c^4)*e*x^4 + (1/(b^6)*d^6 + 3/(a*b^4)*d^4 + + (-12*a^3*b*c + 3)/(a^2*b^2)*d^2 + (-12*a^3*b*c + 1)/(a^3))*x^3 + + (48*c^4)*e^2*x^2 + ((-12*a*c)/b*d^2*e + (-12*b*c)*e)*x + (16*c^4)*e^3 + (4*a^3*b^3)/c Test for :trac:`10978`:: + sage: # needs sage.libs.pari sage.rings.complex_double sage.symbolic sage: R. = PolynomialRing(CDF) sage: f = R(1 - I*x + (0.5)*x^2 + (1.7)*x^3) sage: g = f.derivative() - sage: f.resultant(g) # optional - sage.libs.pari + sage: f.resultant(g) 133.92599999999996 + 37.56999999999999*I """ variable = self.variable_name() @@ -6937,45 +7073,47 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(ZZ) sage: p1 = x^2 - 1 sage: p2 = x^4 - 1 - sage: p1.composed_op(p2, operator.add) # optional - sage.libs.singular + sage: p1.composed_op(p2, operator.add) # needs sage.libs.singular x^8 - 4*x^6 + 4*x^4 - 16*x^2 - sage: p1.composed_op(p2, operator.mul) # optional - sage.libs.singular + sage: p1.composed_op(p2, operator.mul) # needs sage.libs.singular x^8 - 2*x^4 + 1 - sage: p1.composed_op(p2, operator.truediv) # optional - sage.libs.singular + sage: p1.composed_op(p2, operator.truediv) # needs sage.libs.singular x^8 - 2*x^4 + 1 This function works over any field. However for base rings other than `\ZZ` and `\QQ` only the resultant algorithm is available:: - sage: x = polygen(QQbar) # optional - sage.rings.number_field - sage: p1 = x**2 - AA(2).sqrt() # optional - sage.rings.number_field - sage: p2 = x**3 - AA(3).sqrt() # optional - sage.rings.number_field - sage: r1 = p1.roots(multiplicities=False) # optional - sage.rings.number_field - sage: r2 = p2.roots(multiplicities=False) # optional - sage.rings.number_field - sage: p = p1.composed_op(p2, operator.add); p # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: x = polygen(QQbar) + sage: p1 = x**2 - AA(2).sqrt() + sage: p2 = x**3 - AA(3).sqrt() + sage: r1 = p1.roots(multiplicities=False) + sage: r2 = p2.roots(multiplicities=False) + sage: p = p1.composed_op(p2, operator.add); p x^6 - 4.242640687119285?*x^4 - 3.464101615137755?*x^3 + 6*x^2 - 14.69693845669907?*x + 0.1715728752538099? - sage: all(p(x+y).is_zero() for x in r1 for y in r2) # optional - sage.rings.number_field + sage: all(p(x+y).is_zero() for x in r1 for y in r2) True - sage: x = polygen(GF(2)) # optional - sage.rings.finite_rings - sage: p1 = x**2 + x - 1 # optional - sage.rings.finite_rings - sage: p2 = x**3 + x - 1 # optional - sage.rings.finite_rings - sage: p_add = p1.composed_op(p2, operator.add); p_add # optional - sage.rings.finite_rings + sage: x = polygen(GF(2)) + sage: p1 = x**2 + x - 1 + sage: p2 = x**3 + x - 1 + sage: p_add = p1.composed_op(p2, operator.add); p_add # needs sage.libs.singular x^6 + x^5 + x^3 + x^2 + 1 - sage: p_mul = p1.composed_op(p2, operator.mul); p_mul # optional - sage.rings.finite_rings + sage: p_mul = p1.composed_op(p2, operator.mul); p_mul # needs sage.libs.singular x^6 + x^4 + x^2 + x + 1 - sage: p_div = p1.composed_op(p2, operator.truediv); p_div # optional - sage.rings.finite_rings + sage: p_div = p1.composed_op(p2, operator.truediv); p_div # needs sage.libs.singular x^6 + x^5 + x^4 + x^2 + 1 - sage: K = GF(2**6, 'a') # optional - sage.rings.finite_rings - sage: r1 = p1.roots(K, multiplicities=False) # optional - sage.rings.finite_rings - sage: r2 = p2.roots(K, multiplicities=False) # optional - sage.rings.finite_rings - sage: all(p_add(x1+x2).is_zero() for x1 in r1 for x2 in r2) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K = GF(2**6, 'a') + sage: r1 = p1.roots(K, multiplicities=False) + sage: r2 = p2.roots(K, multiplicities=False) + sage: all(p_add(x1+x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True - sage: all(p_mul(x1*x2).is_zero() for x1 in r1 for x2 in r2) # optional - sage.rings.finite_rings + sage: all(p_mul(x1*x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True - sage: all(p_div(x1/x2).is_zero() for x1 in r1 for x2 in r2) # optional - sage.rings.finite_rings + sage: all(p_div(x1/x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True TESTS: @@ -6983,7 +7121,7 @@ cdef class Polynomial(CommutativePolynomial): :: sage: y = polygen(ZZ) - sage: for p1 in [2*y^3 - y + 3, -y^5 - 2, 4*y - 3]: # optional - sage.libs.singular + sage: for p1 in [2*y^3 - y + 3, -y^5 - 2, 4*y - 3]: # needs sage.libs.singular ....: for p2 in [5*y^2 - 7, -3*y - 1]: ....: for monic in [True,False]: ....: for op in [operator.add, operator.sub, operator.mul, operator.truediv]: @@ -7131,21 +7269,22 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: x = polygen(R) sage: f = (x - a) * (x - b) * (x - c) - sage: f.compose_power(2).factor() # optional - sage.libs.singular sage.modules + sage: f.compose_power(2).factor() # needs sage.libs.singular sage.modules (x - c^2) * (x - b^2) * (x - a^2) * (x - b*c)^2 * (x - a*c)^2 * (x - a*b)^2 + sage: # needs sage.libs.singular sage.modules sage: x = polygen(QQ) sage: f = x^2 - 2*x + 2 sage: f2 = f.compose_power(2); f2 x^4 - 4*x^3 + 8*x^2 - 16*x + 16 - sage: f2 == f.composed_op(f, operator.mul) # optional - sage.libs.singular sage.modules + sage: f2 == f.composed_op(f, operator.mul) True - sage: f3 = f.compose_power(3); f3 # optional - sage.libs.singular sage.modules + sage: f3 = f.compose_power(3); f3 x^8 - 8*x^7 + 32*x^6 - 64*x^5 + 128*x^4 - 512*x^3 + 2048*x^2 - 4096*x + 4096 - sage: f3 == f2.composed_op(f, operator.mul) # optional - sage.libs.singular sage.modules + sage: f3 == f2.composed_op(f, operator.mul) True - sage: f4 = f.compose_power(4) # optional - sage.libs.singular sage.modules - sage: f4 == f3.composed_op(f, operator.mul) # optional - sage.libs.singular sage.modules + sage: f4 = f.compose_power(4) + sage: f4 == f3.composed_op(f, operator.mul) True """ try: @@ -7185,21 +7324,22 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: f = cyclotomic_polynomial(30) # optional - sage.libs.pari - sage: f.adams_operator(7)==f # optional - sage.libs.pari + sage: # needs sage.libs.pari + sage: f = cyclotomic_polynomial(30) + sage: f.adams_operator(7)==f True - sage: f.adams_operator(6) == cyclotomic_polynomial(5)**2 # optional - sage.libs.pari + sage: f.adams_operator(6) == cyclotomic_polynomial(5)**2 True - sage: f.adams_operator(10) == cyclotomic_polynomial(3)**4 # optional - sage.libs.pari + sage: f.adams_operator(10) == cyclotomic_polynomial(3)**4 True - sage: f.adams_operator(15) == cyclotomic_polynomial(2)**8 # optional - sage.libs.pari + sage: f.adams_operator(15) == cyclotomic_polynomial(2)**8 True - sage: f.adams_operator(30) == cyclotomic_polynomial(1)**8 # optional - sage.libs.pari + sage: f.adams_operator(30) == cyclotomic_polynomial(1)**8 True sage: x = polygen(QQ) sage: f = x^2 - 2*x + 2 - sage: f.adams_operator(10) # optional - sage.libs.singular + sage: f.adams_operator(10) # needs sage.libs.singular x^2 + 1024 When ``self`` is monic, the output will have leading coefficient @@ -7209,12 +7349,14 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: x = polygen(R) sage: f = (x - a) * (x - b) * (x - c) - sage: f.adams_operator(3).factor() # optional - sage.libs.singular + sage: f.adams_operator(3).factor() # needs sage.libs.singular (-1) * (x - c^3) * (x - b^3) * (x - a^3) - sage: f.adams_operator(3, monic=True).factor() # optional - sage.libs.singular + sage: f.adams_operator(3, monic=True).factor() # needs sage.libs.singular (x - c^3) * (x - b^3) * (x - a^3) """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + u, v = PolynomialRing(self._parent.base_ring(), ['u', 'v']).gens() R = (u - v**n).resultant(self(v), v) R = R([self.variables()[0], 0]) @@ -7231,11 +7373,11 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(QQ) sage: f = x^4 - x + 2 - sage: [f.symmetric_power(k) for k in range(5)] # optional - sage.libs.singular + sage: [f.symmetric_power(k) for k in range(5)] # needs sage.libs.singular [x - 1, x^4 - x + 2, x^6 - 2*x^4 - x^3 - 4*x^2 + 8, x^4 - x^3 + 8, x - 2] sage: f = x^5 - 2*x + 2 - sage: [f.symmetric_power(k) for k in range(6)] # optional - sage.libs.singular + sage: [f.symmetric_power(k) for k in range(6)] # needs sage.libs.singular [x - 1, x^5 - 2*x + 2, x^10 + 2*x^8 - 4*x^6 - 8*x^5 - 8*x^4 - 8*x^3 + 16, @@ -7246,7 +7388,7 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: x = polygen(R) sage: f = (x - a) * (x - b) * (x - c) * (x - d) - sage: [f.symmetric_power(k).factor() for k in range(5)] # optional - sage.libs.singular + sage: [f.symmetric_power(k).factor() for k in range(5)] # needs sage.libs.singular [x - 1, (-x + d) * (-x + c) * (-x + b) * (-x + a), (x - c*d) * (x - b*d) * (x - a*d) * (x - b*c) * (x - a*c) * (x - a*b), @@ -7341,18 +7483,18 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^3 + x + 1 - sage: d = f.discriminant(); d # optional - sage.libs.pari + sage: d = f.discriminant(); d # needs sage.libs.pari -31 - sage: d.parent() is QQ # optional - sage.libs.pari + sage: d.parent() is QQ # needs sage.libs.pari True - sage: EllipticCurve([1, 1]).discriminant()/16 # optional - sage.libs.pari + sage: EllipticCurve([1, 1]).discriminant()/16 # needs sage.libs.pari -31 :: sage: R. = QQ[] sage: f = 2*x^3 + x + 1 - sage: d = f.discriminant(); d # optional - sage.libs.pari + sage: d = f.discriminant(); d # needs sage.libs.pari -116 We can compute discriminants over univariate and multivariate @@ -7361,9 +7503,9 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = a*x + x + a + 1 - sage: d = f.discriminant(); d # optional - sage.libs.pari + sage: d = f.discriminant(); d # needs sage.libs.pari 1 - sage: d.parent() is R # optional - sage.libs.pari + sage: d.parent() is R # needs sage.libs.pari True :: @@ -7371,9 +7513,9 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a + b - sage: d = f.discriminant(); d # optional - sage.libs.pari + sage: d = f.discriminant(); d # needs sage.libs.pari -4*a - 4*b - sage: d.parent() is R # optional - sage.libs.pari + sage: d.parent() is R # needs sage.libs.pari True TESTS:: @@ -7381,41 +7523,42 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: S. = R[] sage: f = x^2 + a - sage: f.discriminant() # optional - sage.libs.pari + sage: f.discriminant() # needs sage.libs.pari 1 Check that :trac:`13672` is fixed:: - sage: R. = GF(5)[] # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: f = x^10 + 2*x^6 + 2*x^5 + x + 2 # optional - sage.rings.finite_rings - sage: (f - t).discriminant() # optional - sage.rings.finite_rings + sage: R. = GF(5)[] + sage: S. = R[] + sage: f = x^10 + 2*x^6 + 2*x^5 + x + 2 + sage: (f - t).discriminant() # needs sage.rings.finite_rings 4*t^5 The following examples show that :trac:`11782` has been fixed:: - sage: var('x') # optional - sage.symbolic + sage: var('x') # needs sage.symbolic x - sage: ZZ.quo(81)['x'](3*x^2 + 3*x + 3).discriminant() # optional - sage.libs.pari sage.symbolic + sage: ZZ.quo(81)['x'](3*x^2 + 3*x + 3).discriminant() # needs sage.libs.pari sage.symbolic 54 - sage: ZZ.quo(9)['x'](2*x^3 + x^2 + x).discriminant() # optional - sage.libs.pari sage.symbolic + sage: ZZ.quo(9)['x'](2*x^3 + x^2 + x).discriminant() # needs sage.libs.pari sage.symbolic 2 This was fixed by :trac:`15422`:: - sage: R. = PolynomialRing(Qp(2)) # optional - sage.rings.padics - sage: (s^2).discriminant() # optional - sage.rings.padics + sage: R. = PolynomialRing(Qp(2)) # needs sage.rings.padics + sage: (s^2).discriminant() # needs sage.rings.padics 0 This was fixed by :trac:`16014`:: + sage: # needs sage.modules sage: PR. = QQ[] sage: PRmu. = PR[] - sage: E1 = diagonal_matrix(PR, [1, b^2, -b^2]) # optional - sage.modules - sage: M = matrix(PR, [[1,-t1,x1-t1*y1], [t1,1,y1+t1*x1], [0,0,1]]) # optional - sage.modules - sage: E1 = M.transpose()*E1*M # optional - sage.modules - sage: E2 = E1.subs(t1=t2, x1=x2, y1=y2) # optional - sage.modules - sage: det(mu*E1 + E2).discriminant().degrees() # optional - sage.modules sage.libs.pari + sage: E1 = diagonal_matrix(PR, [1, b^2, -b^2]) + sage: M = matrix(PR, [[1,-t1,x1-t1*y1], [t1,1,y1+t1*x1], [0,0,1]]) + sage: E1 = M.transpose()*E1*M + sage: E2 = E1.subs(t1=t2, x1=x2, y1=y2) + sage: det(mu*E1 + E2).discriminant().degrees() # needs sage.libs.pari (24, 12, 12, 8, 8, 8, 8) This addresses an issue raised by :trac:`15061`:: @@ -7424,7 +7567,7 @@ cdef class Polynomial(CommutativePolynomial): sage: F = R([1,1],2) sage: RP. = PolynomialRing(R) sage: P = x^2 - F - sage: P.discriminant() # optional - sage.libs.pari + sage: P.discriminant() # needs sage.libs.pari 4 + 4*T + O(T^2) """ # Late import to avoid cyclic dependencies: @@ -7567,36 +7710,35 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: x = QQ['x'].0 sage: f = x^3 - 1 - sage: f.roots() # optional - sage.libs.pari + sage: f.roots() [(1, 1)] - sage: f.roots(ring=CC) # ... - low order bits slightly different on ppc # optional - sage.libs.pari + sage: f.roots(ring=CC) # ... - low order bits slightly different on ppc [(1.00000000000000, 1), (-0.500000000000000 - 0.86602540378443...*I, 1), (-0.500000000000000 + 0.86602540378443...*I, 1)] sage: f = (x^3 - 1)^2 - sage: f.roots() # optional - sage.libs.pari + sage: f.roots() [(1, 2)] - - :: - sage: f = -19*x + 884736 - sage: f.roots() # optional - sage.libs.pari + sage: f.roots() [(884736/19, 1)] - sage: (f^20).roots() # optional - sage.libs.pari + sage: (f^20).roots() [(884736/19, 20)] :: - sage: K. = CyclotomicField(3) # optional - sage.rings.number_field - sage: f = K.defining_polynomial() # optional - sage.rings.number_field - sage: f.roots(ring=GF(7)) # optional - sage.rings.finite_rings sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = CyclotomicField(3) + sage: f = K.defining_polynomial() + sage: f.roots(ring=GF(7)) [(4, 1), (2, 1)] - sage: g = f.change_ring(GF(7)) # optional - sage.rings.finite_rings sage.rings.number_field - sage: g.roots() # optional - sage.rings.finite_rings sage.rings.number_field + sage: g = f.change_ring(GF(7)) + sage: g.roots() [(4, 1), (2, 1)] - sage: g.roots(multiplicities=False) # optional - sage.rings.finite_rings sage.rings.number_field + sage: g.roots(multiplicities=False) [4, 2] A new ring. In the example below, we add the special method @@ -7607,18 +7749,19 @@ cdef class Polynomial(CommutativePolynomial): introduce:: sage: R. = QQ[] - sage: (x^2 + 1).roots() # optional - sage.libs.pari + sage: (x^2 + 1).roots() # needs sage.libs.pari [] sage: def my_roots(f, *args, **kwds): ....: return f.change_ring(CDF).roots() sage: QQ._roots_univariate_polynomial = my_roots - sage: (x^2 + 1).roots() # abs tol 1e-14 + sage: (x^2 + 1).roots() # abs tol 1e-14 # needs numpy [(2.7755575615628914e-17 - 1.0*I, 1), (0.9999999999999997*I, 1)] sage: del QQ._roots_univariate_polynomial An example over RR, which illustrates that only the roots in RR are returned:: + sage: # needs numpy sage.rings.real_mpfr sage: x = RR['x'].0 sage: f = x^3 - 2 sage: f.roots() @@ -7634,11 +7777,11 @@ cdef class Polynomial(CommutativePolynomial): sage: x = CC['x'].0 sage: f = x^3 - 2 - sage: f.roots() + sage: f.roots() # needs numpy [(1.25992104989487, 1), (-0.62996052494743... - 1.09112363597172*I, 1), (-0.62996052494743... + 1.09112363597172*I, 1)] - sage: f.roots(algorithm='pari') # optional - sage.libs.pari + sage: f.roots(algorithm='pari') # needs sage.libs.pari [(1.25992104989487, 1), (-0.629960524947437 - 1.09112363597172*I, 1), (-0.629960524947437 + 1.09112363597172*I, 1)] @@ -7648,9 +7791,9 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(ZZ) sage: f = (2*x - 3) * (x - 1) * (x + 1) - sage: f.roots() + sage: f.roots() # needs sage.libs.pari [(1, 1), (-1, 1)] - sage: f.roots(ring=QQ) + sage: f.roots(ring=QQ) # needs sage.libs.pari [(3/2, 1), (1, 1), (-1, 1)] An example where we compute the roots lying in a subring of the @@ -7658,11 +7801,12 @@ cdef class Polynomial(CommutativePolynomial): sage: Pols. = QQ[] sage: pol = (n - 1/2)^2 * (n - 1)^2 * (n - 2) - sage: pol.roots(ZZ) + sage: pol.roots(ZZ) # needs sage.libs.pari [(2, 1), (1, 2)] An example involving large numbers:: + sage: # needs numpy sage.rings.real_mpfr sage: x = RR['x'].0 sage: f = x^2 - 1e100 sage: f.roots() @@ -7673,6 +7817,7 @@ cdef class Polynomial(CommutativePolynomial): :: + sage: # needs numpy sage.rings.real_mpfr sage: x = CC['x'].0 sage: i = CC.0 sage: f = (x - 1) * (x - i) @@ -7686,15 +7831,15 @@ cdef class Polynomial(CommutativePolynomial): sage: x = QQ['x'].0 sage: f = x^2 + 2 - sage: f.roots(SR) # optional - sage.symbolic + sage: f.roots(SR) # needs sage.symbolic [(-I*sqrt(2), 1), (I*sqrt(2), 1)] - sage: f.roots(SR, multiplicities=False) # optional - sage.symbolic + sage: f.roots(SR, multiplicities=False) # needs sage.symbolic [-I*sqrt(2), I*sqrt(2)] The roots of some polynomials cannot be described using radical expressions:: - sage: (x^5 - x + 1).roots(SR) # optional - sage.symbolic + sage: (x^5 - x + 1).roots(SR) # needs sage.symbolic [] For some other polynomials, no roots can be found at the moment @@ -7703,28 +7848,30 @@ cdef class Polynomial(CommutativePolynomial): is the following:: sage: f = x^6 - 300*x^5 + 30361*x^4 - 1061610*x^3 + 1141893*x^2 - 915320*x + 101724 - sage: f.roots() + sage: f.roots() # needs sage.libs.pari [] A purely symbolic roots example:: - sage: X = var('X') # optional - sage.symbolic - sage: f = expand((X - 1) * (X - I)^3 * (X^2 - sqrt(2))); f # optional - sage.symbolic + sage: # needs sage.symbolic + sage: X = var('X') + sage: f = expand((X - 1) * (X - I)^3 * (X^2 - sqrt(2))); f X^6 - (3*I + 1)*X^5 - sqrt(2)*X^4 + (3*I - 3)*X^4 + (3*I + 1)*sqrt(2)*X^3 + (I + 3)*X^3 - (3*I - 3)*sqrt(2)*X^2 - I*X^2 - (I + 3)*sqrt(2)*X + I*sqrt(2) - sage: f.roots() # optional - sage.symbolic + sage: f.roots() [(I, 3), (-2^(1/4), 1), (2^(1/4), 1), (1, 1)] The same operation, performed over a polynomial ring with symbolic coefficients:: - sage: X = SR['X'].0 # optional - sage.symbolic - sage: f = (X - 1) * (X - I)^3 * (X^2 - sqrt(2)); f # optional - sage.symbolic + sage: # needs sage.symbolic + sage: X = SR['X'].0 + sage: f = (X - 1) * (X - I)^3 * (X^2 - sqrt(2)); f X^6 + (-3*I - 1)*X^5 + (-sqrt(2) + 3*I - 3)*X^4 + ((3*I + 1)*sqrt(2) + I + 3)*X^3 + (-(3*I - 3)*sqrt(2) - I)*X^2 + (-(I + 3)*sqrt(2))*X + I*sqrt(2) - sage: f.roots() # optional - sage.symbolic + sage: f.roots() [(I, 3), (-2^(1/4), 1), (2^(1/4), 1), (1, 1)] - sage: f.roots(multiplicities=False) # optional - sage.symbolic + sage: f.roots(multiplicities=False) [I, -2^(1/4), 2^(1/4), 1] A couple of examples where the base ring does not have a @@ -7739,18 +7886,19 @@ cdef class Polynomial(CommutativePolynomial): ... NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option) - sage: p.roots(multiplicities=False) + sage: p.roots(multiplicities=False) # needs sage.libs.pari [5, 1] sage: R = Integers(9) sage: A = PolynomialRing(R, 'y') sage: y = A.gen() sage: f = 10*y^2 - y^3 - 9 - sage: f.roots(multiplicities=False) + sage: f.roots(multiplicities=False) # needs sage.libs.pari [1, 0, 3, 6] An example over the complex double field (where root finding is fast, thanks to NumPy):: + sage: # needs numpy sage.rings.complex_double sage: R. = CDF[] sage: f = R.cyclotomic_polynomial(5); f x^4 + x^3 + x^2 + x + 1.0 @@ -7769,13 +7917,14 @@ cdef class Polynomial(CommutativePolynomial): Another example over RDF:: sage: x = RDF['x'].0 - sage: ((x^3 - 1)).roots() # abs tol 4e-16 + sage: ((x^3 - 1)).roots() # abs tol 4e-16 # needs numpy [(1.0000000000000002, 1)] - sage: ((x^3 - 1)).roots(multiplicities=False) # abs tol 4e-16 + sage: ((x^3 - 1)).roots(multiplicities=False) # abs tol 4e-16 # needs numpy [1.0000000000000002] More examples involving the complex double field:: + sage: # needs numpy sage.rings.complex_double sage.rings.real_mpfr sage: x = CDF['x'].0 sage: i = CDF.0 sage: f = x^3 + 2*i; f @@ -7802,8 +7951,12 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(ZZ) sage: f = x^2 - x - 1 - sage: f.roots() + sage: f.roots() # needs sage.libs.pari [] + sage: f.roots(ring=AA) # needs sage.rings.number_field + [(-0.618033988749895?, 1), (1.618033988749895?, 1)] + + sage: # needs sage.rings.real_interval_field sage: f.roots(ring=RIF) [(-0.6180339887498948482045868343657?, 1), (1.6180339887498948482045868343657?, 1)] sage: f.roots(ring=RIF, multiplicities=False) @@ -7811,8 +7964,6 @@ cdef class Polynomial(CommutativePolynomial): sage: f.roots(ring=RealIntervalField(150)) [(-0.6180339887498948482045868343656381177203091798057628621354486227?, 1), (1.618033988749894848204586834365638117720309179805762862135448623?, 1)] - sage: f.roots(ring=AA) # optional - sage.rings.number_field - [(-0.618033988749895?, 1), (1.618033988749895?, 1)] sage: f = f^2 * (x - 1) sage: f.roots(ring=RIF) [(-0.6180339887498948482045868343657?, 2), @@ -7827,29 +7978,42 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(ZZ) sage: p = x^5 - x - 1 - sage: p.roots() + sage: p.roots() # needs sage.libs.pari [] - sage: p.roots(ring=CIF) + sage: p.roots(ring=CIF) # needs sage.rings.complex_interval_field [(1.167303978261419?, 1), (-0.764884433600585? - 0.352471546031727?*I, 1), (-0.764884433600585? + 0.352471546031727?*I, 1), (0.181232444469876? - 1.083954101317711?*I, 1), (0.181232444469876? + 1.083954101317711?*I, 1)] - sage: p.roots(ring=ComplexIntervalField(200)) - [(1.167303978261418684256045899854842180720560371525489039140082?, 1), (-0.76488443360058472602982318770854173032899665194736756700778? - 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), (-0.76488443360058472602982318770854173032899665194736756700778? + 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), (0.18123244446987538390180023778112063996871646618462304743774? - 1.08395410131771066843034449298076657427364024315511565430114?*I, 1), (0.18123244446987538390180023778112063996871646618462304743774? + 1.08395410131771066843034449298076657427364024315511565430114?*I, 1)] - sage: rts = p.roots(ring=QQbar); rts # optional - sage.rings.number_field - [(1.167303978261419?, 1), (-0.7648844336005847? - 0.3524715460317263?*I, 1), (-0.7648844336005847? + 0.3524715460317263?*I, 1), (0.1812324444698754? - 1.083954101317711?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 1)] - sage: p.roots(ring=AA) # optional - sage.rings.number_field + sage: p.roots(ring=ComplexIntervalField(200)) # needs sage.rings.complex_interval_field + [(1.167303978261418684256045899854842180720560371525489039140082?, 1), + (-0.76488443360058472602982318770854173032899665194736756700778? - 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), + (-0.76488443360058472602982318770854173032899665194736756700778? + 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), + (0.18123244446987538390180023778112063996871646618462304743774? - 1.08395410131771066843034449298076657427364024315511565430114?*I, 1), + (0.18123244446987538390180023778112063996871646618462304743774? + 1.08395410131771066843034449298076657427364024315511565430114?*I, 1)] + sage: rts = p.roots(ring=QQbar); rts # needs sage.rings.number_field + [(1.167303978261419?, 1), + (-0.7648844336005847? - 0.3524715460317263?*I, 1), + (-0.7648844336005847? + 0.3524715460317263?*I, 1), + (0.1812324444698754? - 1.083954101317711?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 1)] + sage: p.roots(ring=AA) # needs sage.rings.number_field [(1.167303978261419?, 1)] - sage: p = (x - rts[4][0])^2 * (3*x^2 + x + 1) - sage: p.roots(ring=QQbar) # optional - sage.rings.number_field - [(-0.1666666666666667? - 0.552770798392567?*I, 1), (-0.1666666666666667? + 0.552770798392567?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 2)] - sage: p.roots(ring=CIF) - [(-0.1666666666666667? - 0.552770798392567?*I, 1), (-0.1666666666666667? + 0.552770798392567?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 2)] + sage: p = (x - rts[4][0])^2 * (3*x^2 + x + 1) # needs sage.rings.number_field + sage: p.roots(ring=QQbar) # needs sage.rings.number_field + [(-0.1666666666666667? - 0.552770798392567?*I, 1), + (-0.1666666666666667? + 0.552770798392567?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 2)] + sage: p.roots(ring=CIF) # needs sage.rings.complex_interval_field + [(-0.1666666666666667? - 0.552770798392567?*I, 1), + (-0.1666666666666667? + 0.552770798392567?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 2)] In some cases, it is possible to isolate the roots of polynomials over complex ball fields:: + sage: # needs sage.libs.flint sage: Pol. = CBF[] sage: (x^2 + 2).roots(multiplicities=False) [[+/- ...e-19] + [-1.414213562373095 +/- ...e-17]*I, @@ -7868,16 +8032,17 @@ cdef class Polynomial(CommutativePolynomial): :: - sage: K. = QuadraticField(-1) # optional - sage.rings.number_field - sage: y = polygen(K) # optional - sage.rings.number_field - sage: p = y^4 - 2 - im # optional - sage.rings.number_field - sage: p.roots(ring=CC) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-1) + sage: y = polygen(K) + sage: p = y^4 - 2 - im + sage: p.roots(ring=CC) [(-1.2146389322441... - 0.14142505258239...*I, 1), (-0.14142505258239... + 1.2146389322441...*I, 1), (0.14142505258239... - 1.2146389322441...*I, 1), (1.2146389322441... + 0.14142505258239...*I, 1)] - sage: p = p^2 * (y^2 - 2) # optional - sage.rings.number_field - sage: p.roots(ring=CIF) # optional - sage.rings.number_field + sage: p = p^2 * (y^2 - 2) + sage: p.roots(ring=CIF) [(-1.414213562373095?, 1), (1.414213562373095?, 1), (-1.214638932244183? - 0.141425052582394?*I, 2), (-0.141425052582394? + 1.214638932244183?*I, 2), @@ -7887,21 +8052,22 @@ cdef class Polynomial(CommutativePolynomial): Note that one should not use NumPy when wanting high precision output as it does not support any of the high precision types:: + sage: # needs numpy sage.rings.real_mpfr sage.symbolic sage: R. = RealField(200)[] - sage: f = x^2 - R(pi) # optional - sage.symbolic - sage: f.roots() # optional - sage.symbolic + sage: f = x^2 - R(pi) + sage: f.roots() [(-1.7724538509055160272981674833411451827975494561223871282138, 1), (1.7724538509055160272981674833411451827975494561223871282138, 1)] - sage: f.roots(algorithm='numpy') # optional - numpy sage.symbolic + sage: f.roots(algorithm='numpy') doctest... UserWarning: NumPy does not support arbitrary precision arithmetic. The roots found will likely have less precision than you expect. [(-1.77245385090551..., 1), (1.77245385090551..., 1)] We can also find roots over number fields:: - sage: K. = CyclotomicField(15) # optional - sage.rings.number_field - sage: R. = PolynomialRing(K) # optional - sage.rings.number_field - sage: (x^2 + x + 1).roots() # optional - sage.rings.number_field + sage: K. = CyclotomicField(15) # needs sage.rings.number_field + sage: R. = PolynomialRing(K) # needs sage.rings.number_field + sage: (x^2 + x + 1).roots() # needs sage.rings.number_field [(z^5, 1), (-z^5 - 1, 1)] There are many combinations of floating-point input and output @@ -7910,6 +8076,7 @@ cdef class Polynomial(CommutativePolynomial): :: + sage: # needs sage.rings.complex_double sage.rings.real_mpfr sage: rflds = (RR, RDF, RealField(100)) sage: cflds = (CC, CDF, ComplexField(100)) sage: def cross(a, b): @@ -7937,16 +8104,17 @@ cdef class Polynomial(CommutativePolynomial): Note that we can find the roots of a polynomial with algebraic coefficients:: - sage: rt2 = sqrt(AA(2)) # optional - sage.rings.number_field - sage: rt3 = sqrt(AA(3)) # optional - sage.rings.number_field - sage: x = polygen(AA) # optional - sage.rings.number_field - sage: f = (x - rt2) * (x - rt3); f # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: rt2 = sqrt(AA(2)) + sage: rt3 = sqrt(AA(3)) + sage: x = polygen(AA) + sage: f = (x - rt2) * (x - rt3); f x^2 - 3.146264369941973?*x + 2.449489742783178? - sage: rts = f.roots(); rts # optional - sage.rings.number_field + sage: rts = f.roots(); rts [(1.414213562373095?, 1), (1.732050807568878?, 1)] - sage: rts[0][0] == rt2 # optional - sage.rings.number_field + sage: rts[0][0] == rt2 True - sage: f.roots(ring=RealIntervalField(150)) # optional - sage.rings.number_field + sage: f.roots(ring=RealIntervalField(150)) [(1.414213562373095048801688724209698078569671875376948073176679738?, 1), (1.732050807568877293527446341505872366942805253810380628055806980?, 1)] @@ -7956,9 +8124,9 @@ cdef class Polynomial(CommutativePolynomial): ``RR`` and ``CC`` allow a much larger range of floating-point numbers:: sage: bigc = 2^1500 - sage: CDF(bigc) + sage: CDF(bigc) # needs sage.rings.complex_double +infinity - sage: CC(bigc) + sage: CC(bigc) # needs sage.rings.real_mpfr 3.50746621104340e451 Polynomials using such large coefficients can't be handled by @@ -7966,37 +8134,37 @@ cdef class Polynomial(CommutativePolynomial): sage: x = polygen(QQ) sage: p = x + bigc - sage: p.roots(ring=RR, algorithm='numpy') # optional - numpy + sage: p.roots(ring=RR, algorithm='numpy') # needs numpy Traceback (most recent call last): ... LinAlgError: Array must not contain infs or NaNs - sage: p.roots(ring=RR, algorithm='pari') # optional - sage.libs.pari + sage: p.roots(ring=RR, algorithm='pari') # needs sage.libs.pari [(-3.50746621104340e451, 1)] - sage: p.roots(ring=AA) # optional - sage.rings.number_field + sage: p.roots(ring=AA) # needs sage.rings.number_field [(-3.5074662110434039?e451, 1)] - sage: p.roots(ring=QQbar) # optional - sage.rings.number_field + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-3.5074662110434039?e451, 1)] sage: p = bigc*x + 1 - sage: p.roots(ring=RR) + sage: p.roots(ring=RR) # needs numpy [(-2.85106096489671e-452, 1)] - sage: p.roots(ring=AA) # optional - sage.rings.number_field + sage: p.roots(ring=AA) # needs sage.rings.number_field [(-2.8510609648967059?e-452, 1)] - sage: p.roots(ring=QQbar) # optional - sage.rings.number_field + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-2.8510609648967059?e-452, 1)] sage: p = x^2 - bigc - sage: p.roots(ring=RR) + sage: p.roots(ring=RR) # needs numpy [(-5.92238652153286e225, 1), (5.92238652153286e225, 1)] - sage: p.roots(ring=QQbar) # optional - sage.rings.number_field + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-5.9223865215328558?e225, 1), (5.9223865215328558?e225, 1)] Check that :trac:`30522` is fixed:: - sage: PolynomialRing(SR, names="x")("x^2").roots() # optional - sage.symbolic + sage: PolynomialRing(SR, names="x")("x^2").roots() # needs sage.symbolic [(0, 2)] Check that :trac:`30523` is fixed:: - sage: PolynomialRing(SR, names="x")("x^2 + q").roots() # optional - sage.symbolic + sage: PolynomialRing(SR, names="x")("x^2 + q").roots() # needs sage.symbolic [(-sqrt(-q), 1), (sqrt(-q), 1)] ALGORITHM: @@ -8088,40 +8256,41 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: K. = CyclotomicField(2) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: factor(x^3 - 1) # optional - sage.rings.number_field + sage: K. = CyclotomicField(2) # needs sage.rings.number_field + sage: R. = K[] # needs sage.rings.number_field + sage: factor(x^3 - 1) # needs sage.rings.number_field (x - 1) * (x^2 + x + 1) This shows that the issue from :trac:`6237` is fixed:: sage: R. = QQ[] sage: g = -27*u^14 - 32*u^9 - sage: g.roots(CDF, multiplicities=False) # abs tol 2e-15 + sage: g.roots(CDF, multiplicities=False) # abs tol 2e-15 # needs numpy [-1.0345637159435719, 0.0, -0.3196977699902601 - 0.9839285635706636*I, -0.3196977699902601 + 0.9839285635706636*I, 0.8369796279620465 - 0.6081012947885318*I, 0.8369796279620465 + 0.6081012947885318*I] - sage: g.roots(CDF) # abs tol 2e-15 + sage: g.roots(CDF) # abs tol 2e-15 # needs numpy [(-1.0345637159435719, 1), (0.0, 9), (-0.3196977699902601 - 0.9839285635706636*I, 1), (-0.3196977699902601 + 0.9839285635706636*I, 1), (0.8369796279620465 - 0.6081012947885318*I, 1), (0.8369796279620465 + 0.6081012947885318*I, 1)] This shows that the issue at :trac:`2418` is fixed:: sage: x = polygen(QQ) - sage: p = (x^50/2^100 + x^10 + x + 1).change_ring(ComplexField(106)) - sage: rts = (p/2^100).roots(multiplicities=False) + sage: p = (x^50/2^100 + x^10 + x + 1).change_ring(ComplexField(106)) # needs sage.rings.real_mpfr + sage: rts = (p/2^100).roots(multiplicities=False) # needs sage.libs.pari sage: eps = 2^(-50) # we test the roots numerically - sage: [abs(p(rt)) < eps for rt in rts] == [True]*50 + sage: [abs(p(rt)) < eps for rt in rts] == [True]*50 # needs sage.rings.number_field True This shows that the issue at :trac:`10901` is fixed:: - sage: a = var('a'); R. = SR[] # optional - sage.symbolic - sage: f = x - a # optional - sage.symbolic - sage: f.roots(RR) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: a = var('a'); R. = SR[] + sage: f = x - a + sage: f.roots(RR) Traceback (most recent call last): ... TypeError: cannot evaluate symbolic expression to a numeric value - sage: f.roots(CC) # optional - sage.symbolic + sage: f.roots(CC) Traceback (most recent call last): ... TypeError: cannot evaluate symbolic expression to a numeric value @@ -8131,24 +8300,24 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: pol = (x - 1)^2 - sage: pol.roots(Qp(3, 5)) # optional - sage.rings.padics + sage: pol.roots(Qp(3, 5)) # needs sage.rings.padics [(1 + O(3^5), 2)] We lose precision if we first change coefficients to `\QQ_p`:: - sage: pol.change_ring(Qp(3, 5)).roots() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: pol.change_ring(Qp(3, 5)).roots() [(1 + O(3^3), 2)] - - sage: (pol - 3^6).roots(Qp(3, 5)) # optional - sage.rings.padics + sage: (pol - 3^6).roots(Qp(3, 5)) [(1 + 2*3^3 + 2*3^4 + O(3^5), 1), (1 + 3^3 + O(3^5), 1)] - sage: r = pol.roots(Zp(3, 5), multiplicities=False); r # optional - sage.rings.padics + sage: r = pol.roots(Zp(3, 5), multiplicities=False); r [1 + O(3^5)] - sage: parent(r[0]) # optional - sage.rings.padics + sage: parent(r[0]) 3-adic Ring with capped relative precision 5 Spurious crash with pari-2.5.5, see :trac:`16165`:: - sage: f=(1+x+x^2)^3 + sage: f = (1+x+x^2)^3 sage: f.roots(ring=CC) [(-0.500000000000000 - 0.866025403784439*I, 3), (-0.500000000000000 + 0.866025403784439*I, 3)] @@ -8165,14 +8334,14 @@ cdef class Polynomial(CommutativePolynomial): Test that some large finite rings can be handled (:trac:`13825`):: - sage: R. = IntegerModRing(20000009)[] + sage: R. = IntegerModRing(20000009)[] # needs sage.libs.pari sage: eq = x^6+x-17 - sage: eq.roots(multiplicities=False) + sage: eq.roots(multiplicities=False) # needs sage.libs.pari [3109038, 17207405] Test that roots in fixed modulus p-adic fields work (:trac:`17598`):: - sage: len(cyclotomic_polynomial(3).roots(ZpFM(739, 566))) # optional - sage.rings.padics + sage: len(cyclotomic_polynomial(3).roots(ZpFM(739, 566))) # needs sage.rings.padics 2 Check that :trac:`26421` is fixed:: @@ -8186,15 +8355,16 @@ cdef class Polynomial(CommutativePolynomial): Check that :trac:`31040` is fixed:: sage: R. = QQ[] - sage: K. = Qq(3).extension(x^2 + 1) # optional - sage.rings.padics - sage: (x^2 + 1).roots(K) # optional - sage.rings.padics + sage: K. = Qq(3).extension(x^2 + 1) # needs sage.rings.padics + sage: (x^2 + 1).roots(K) # needs sage.rings.padics [(a + O(3^20), 1), - (2*a + 2*a*3 + 2*a*3^2 + 2*a*3^3 + 2*a*3^4 + 2*a*3^5 + 2*a*3^6 + 2*a*3^7 + 2*a*3^8 + 2*a*3^9 + 2*a*3^10 + 2*a*3^11 + 2*a*3^12 + 2*a*3^13 + 2*a*3^14 + 2*a*3^15 + 2*a*3^16 + 2*a*3^17 + 2*a*3^18 + 2*a*3^19 + O(3^20), + (2*a + 2*a*3 + 2*a*3^2 + 2*a*3^3 + 2*a*3^4 + 2*a*3^5 + 2*a*3^6 + 2*a*3^7 + 2*a*3^8 + 2*a*3^9 + 2*a*3^10 + + 2*a*3^11 + 2*a*3^12 + 2*a*3^13 + 2*a*3^14 + 2*a*3^15 + 2*a*3^16 + 2*a*3^17 + 2*a*3^18 + 2*a*3^19 + O(3^20), 1)] Check that :trac:`31710` is fixed:: - sage: CBF['x'].zero().roots(multiplicities=False) + sage: CBF['x'].zero().roots(multiplicities=False) # needs sage.libs.flint Traceback (most recent call last): ... ArithmeticError: taking the roots of the zero polynomial @@ -8207,7 +8377,7 @@ cdef class Polynomial(CommutativePolynomial): sage: a = randint(0, n - 1) sage: b = randint(0, n - 1) sage: f = (x - a) * (x - b) - sage: all(r.parent() is K for r in f.roots(multiplicities=False)) + sage: all(r.parent() is K for r in f.roots(multiplicities=False)) # needs sage.rings.finite_rings True """ from sage.rings.finite_rings.finite_field_constructor import GF @@ -8268,6 +8438,8 @@ cdef class Polynomial(CommutativePolynomial): import numpy from numpy.linalg.linalg import LinAlgError + from sage.rings.complex_double import CDF + numpy_dtype = ('complex' if input_complex else 'double') ty = (complex if input_complex else float) coeffs = self.list() @@ -8287,6 +8459,8 @@ cdef class Polynomial(CommutativePolynomial): if algorithm == 'pari': if not input_arbprec: + from sage.rings.real_mpfr import RR + from sage.rings.cc import CC self = self.change_ring(CC if input_complex else RR) ext_rts = self.__pari__().polroots(precision=L.prec()) @@ -8398,6 +8572,7 @@ cdef class Polynomial(CommutativePolynomial): if isinstance(L, sage.rings.abc.ComplexDoubleField): real_field = RDF else: + from sage.rings.real_mpfr import RealField real_field = RealField(L.prec()) return self.change_ring(real_field).roots(ring=L, multiplicities=multiplicities, algorithm=algorithm) @@ -8472,11 +8647,11 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: pol = 20*x^3 - 50*x^2 + 20*x - sage: F = pol.factor(); F # optional - sage.libs.pari + sage: F = pol.factor(); F # needs sage.libs.pari 2 * 5 * (x - 2) * x * (2*x - 1) - sage: pol._roots_from_factorization(F, multiplicities=True) # optional - sage.libs.pari + sage: pol._roots_from_factorization(F, multiplicities=True) # needs sage.libs.pari [(2, 1), (0, 1)] - sage: pol.change_ring(QQ)._roots_from_factorization(F, multiplicities=False) # optional - sage.libs.pari + sage: pol.change_ring(QQ)._roots_from_factorization(F, multiplicities=False) # needs sage.libs.pari [2, 0, 1/2] """ seq = [] @@ -8506,14 +8681,14 @@ cdef class Polynomial(CommutativePolynomial): sage: Pols. = QQ[] sage: pol = (n - 1/2)^2 * (n - 1)^2 * (n - 2) - sage: rts = pol.roots(ZZ, multiplicities=False); rts # optional - sage.libs.pari + sage: rts = pol.roots(ZZ, multiplicities=False); rts # needs sage.libs.pari [2, 1] - sage: rts[0].parent() # optional - sage.libs.pari + sage: rts[0].parent() # needs sage.libs.pari Integer Ring sage: Pols_x. = QQ[] sage: Pols_xy. = Pols_x[] - sage: ((y - 1)*(y - x))._roots_in_subring(QQ, True, None) # optional - sage.libs.singular + sage: ((y - 1)*(y - x))._roots_in_subring(QQ, True, None) # needs sage.libs.singular [(1, 1)] """ K = self._parent.base_ring() @@ -8546,26 +8721,28 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^2 - x - 1).real_roots() + sage: (x^2 - x - 1).real_roots() # needs sage.rings.real_mpfr [-0.618033988749895, 1.61803398874989] TESTS:: - sage: x = polygen(RealField(100)) - sage: (x^2 - x - 1).real_roots()[0].parent() + sage: x = polygen(RealField(100)) # needs sage.rings.real_mpfr + sage: (x^2 - x - 1).real_roots()[0].parent() # needs sage.rings.real_mpfr Real Field with 100 bits of precision sage: x = polygen(RDF) - sage: (x^2 - x - 1).real_roots()[0].parent() + sage: (x^2 - x - 1).real_roots()[0].parent() # needs numpy Real Double Field - sage: x=polygen(ZZ,'x'); v=(x^2-x-1).real_roots() - sage: v[0].parent() is RR + sage: x = polygen(ZZ,'x'); v = (x^2 - x - 1).real_roots() # needs sage.rings.real_mpfr + sage: v[0].parent() is RR # needs sage.rings.real_mpfr True """ K = self.base_ring() if isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)): return self.roots(multiplicities=False) + from sage.rings.real_mpfr import RR + return self.roots(ring=RR, multiplicities=False) def complex_roots(self): @@ -8580,38 +8757,48 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^3 - 1).complex_roots() # note: low order bits slightly different on ppc. - [1.00000000000000, -0.500000000000000 - 0.86602540378443...*I, -0.500000000000000 + 0.86602540378443...*I] + sage: (x^3 - 1).complex_roots() # note: low order bits slightly different on ppc. # needs sage.rings.real_mpfr + [1.00000000000000, + -0.500000000000000 - 0.86602540378443...*I, + -0.500000000000000 + 0.86602540378443...*I] TESTS:: - sage: x = polygen(RR) - sage: (x^3 - 1).complex_roots()[0].parent() + sage: x = polygen(RR) # needs sage.rings.real_mpfr + sage: (x^3 - 1).complex_roots()[0].parent() # needs sage.rings.real_mpfr Complex Field with 53 bits of precision + sage: x = polygen(RDF) - sage: (x^3 - 1).complex_roots()[0].parent() + sage: (x^3 - 1).complex_roots()[0].parent() # needs numpy Complex Double Field - sage: x = polygen(RealField(200)) - sage: (x^3 - 1).complex_roots()[0].parent() + + sage: x = polygen(RealField(200)) # needs sage.rings.real_mpfr + sage: (x^3 - 1).complex_roots()[0].parent() # needs sage.rings.real_mpfr Complex Field with 200 bits of precision - sage: x = polygen(CDF) - sage: (x^3 - 1).complex_roots()[0].parent() + + sage: x = polygen(CDF) # needs sage.rings.complex_double + sage: (x^3 - 1).complex_roots()[0].parent() # needs numpy sage.rings.complex_double Complex Double Field + + + sage: # needs sage.rings.real_mpfr sage: x = polygen(ComplexField(200)) sage: (x^3 - 1).complex_roots()[0].parent() Complex Field with 200 bits of precision - sage: x=polygen(ZZ,'x'); v=(x^2-x-1).complex_roots() + sage: x = polygen(ZZ,'x'); v=(x^2-x-1).complex_roots() sage: v[0].parent() is CC True """ K = self.base_ring() if isinstance(K, sage.rings.abc.RealField): + from sage.rings.complex_mpfr import ComplexField return self.roots(ring=ComplexField(K.prec()), multiplicities=False) if isinstance(K, sage.rings.abc.RealDoubleField): + from sage.rings.complex_double import CDF return self.roots(ring=CDF, multiplicities=False) if isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)): return self.roots(multiplicities=False) - + from sage.rings.cc import CC return self.roots(ring=CC, multiplicities=False) def number_of_roots_in_interval(self, a=None, b=None): @@ -8630,37 +8817,41 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) - sage: pol.number_of_roots_in_interval(1, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(1, 2) 2 - sage: pol.number_of_roots_in_interval(1.01, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(1.01, 2) 1 - sage: pol.number_of_roots_in_interval(None, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(None, 2) 2 - sage: pol.number_of_roots_in_interval(1, Infinity) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(1, Infinity) 3 - sage: pol.number_of_roots_in_interval() # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval() 3 sage: pol = (x - 1) * (x - 2) * (x - 3) + + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: pol2 = pol.change_ring(CC) - sage: pol2.number_of_roots_in_interval() # optional - sage.libs.pari + sage: pol2.number_of_roots_in_interval() 3 sage: R. = PolynomialRing(CC) sage: pol = (x - 1) * (x - CC(I)) - sage: pol.number_of_roots_in_interval(0, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(0, 2) 1 TESTS:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) - sage: pol.number_of_roots_in_interval(1, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(1, 2) 2 sage: pol = chebyshev_T(5,x) - sage: pol.number_of_roots_in_interval(-1, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(-1, 2) 5 - sage: pol.number_of_roots_in_interval(0, 2) # optional - sage.libs.pari + sage: pol.number_of_roots_in_interval(0, 2) 3 """ @@ -8688,17 +8879,20 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) - sage: pol.number_of_real_roots() # optional - sage.libs.pari + sage: pol.number_of_real_roots() 3 sage: pol = (x - 1) * (x - 2) * (x - 3) + + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: pol2 = pol.change_ring(CC) - sage: pol2.number_of_real_roots() # optional - sage.libs.pari + sage: pol2.number_of_real_roots() 3 sage: R. = PolynomialRing(CC) sage: pol = (x - 1) * (x - CC(I)) - sage: pol.number_of_real_roots() # optional - sage.libs.pari + sage: pol.number_of_real_roots() 1 """ return self.number_of_roots_in_interval() @@ -8710,19 +8904,20 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) - sage: pol.all_roots_in_interval(1, 3) # optional - sage.libs.pari + sage: pol.all_roots_in_interval(1, 3) True - sage: pol.all_roots_in_interval(1.01, 3) # optional - sage.libs.pari + sage: pol.all_roots_in_interval(1.01, 3) False sage: pol = chebyshev_T(5, x) - sage: pol.all_roots_in_interval(-1, 1) # optional - sage.libs.pari + sage: pol.all_roots_in_interval(-1, 1) True sage: pol = chebyshev_T(5, x/2) - sage: pol.all_roots_in_interval(-1, 1) # optional - sage.libs.pari + sage: pol.all_roots_in_interval(-1, 1) False - sage: pol.all_roots_in_interval() # optional - sage.libs.pari + sage: pol.all_roots_in_interval() True """ pol = self // self.gcd(self.derivative()) @@ -8734,12 +8929,13 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.libs.pari sage: R. = PolynomialRing(ZZ) sage: pol = chebyshev_T(5, x) - sage: pol.is_real_rooted() # optional - sage.libs.pari + sage: pol.is_real_rooted() True sage: pol = x^2 + 1 - sage: pol.is_real_rooted() # optional - sage.libs.pari + sage: pol.is_real_rooted() False """ return self.all_roots_in_interval() @@ -8820,22 +9016,23 @@ cdef class Polynomial(CommutativePolynomial): We check that this function works for rings that have a coercion to the reals:: - sage: K. = NumberField(x^2 - 2, embedding=1.4) # optional - sage.rings.number_field - sage: u = x^4 + a*x^3 + 3*x^2 + 2*a*x + 4 # optional - sage.rings.number_field - sage: u.trace_polynomial() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = NumberField(x^2 - 2, embedding=1.4) + sage: u = x^4 + a*x^3 + 3*x^2 + 2*a*x + 4 + sage: u.trace_polynomial() (x^2 + a*x - 1, 1, 2) - sage: (u*(x^2-2)).trace_polynomial() # optional - sage.rings.number_field + sage: (u*(x^2-2)).trace_polynomial() (x^2 + a*x - 1, x^2 - 2, 2) - sage: (u*(x^2-2)^2).trace_polynomial() # optional - sage.rings.number_field + sage: (u*(x^2-2)^2).trace_polynomial() (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, 1, 2) - sage: (u*(x^2-2)^3).trace_polynomial() # optional - sage.rings.number_field + sage: (u*(x^2-2)^3).trace_polynomial() (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, x^2 - 2, 2) - sage: u = x^4 + a*x^3 + 3*x^2 + 4*a*x + 16 # optional - sage.rings.number_field - sage: u.trace_polynomial() # optional - sage.rings.number_field + sage: u = x^4 + a*x^3 + 3*x^2 + 4*a*x + 16 + sage: u.trace_polynomial() (x^2 + a*x - 5, 1, 4) - sage: (u*(x-2)).trace_polynomial() # optional - sage.rings.number_field + sage: (u*(x-2)).trace_polynomial() (x^2 + a*x - 5, x - 2, 4) - sage: (u*(x+2)).trace_polynomial() # optional - sage.rings.number_field + sage: (u*(x+2)).trace_polynomial() (x^2 + a*x - 5, x + 2, 4) TESTS: @@ -8900,15 +9097,15 @@ cdef class Polynomial(CommutativePolynomial): sage: P0 = x^4 + 5*x^3 + 15*x^2 + 25*x + 25 sage: P1 = x^4 + 25*x^3 + 15*x^2 + 5*x + 25 sage: P2 = x^4 + 5*x^3 + 25*x^2 + 25*x + 25 - sage: P0.is_weil_polynomial(return_q=True) # optional - sage.libs.pari + sage: P0.is_weil_polynomial(return_q=True) # needs sage.libs.pari (True, 5) - sage: P0.is_weil_polynomial(return_q=False) # optional - sage.libs.pari + sage: P0.is_weil_polynomial(return_q=False) # needs sage.libs.pari True - sage: P1.is_weil_polynomial(return_q=True) # optional - sage.libs.pari + sage: P1.is_weil_polynomial(return_q=True) (False, 0) - sage: P1.is_weil_polynomial(return_q=False) # optional - sage.libs.pari + sage: P1.is_weil_polynomial(return_q=False) False - sage: P2.is_weil_polynomial() # optional - sage.libs.pari + sage: P2.is_weil_polynomial() # needs sage.libs.pari False .. SEEALSO:: @@ -8923,7 +9120,7 @@ cdef class Polynomial(CommutativePolynomial): sage: P. = QQ[] sage: u = t^10 + 4*t^9 + 8*t^8 + 18*t^7 + 81*t^6 + 272*t^5 + 567*t^4 + 882*t^3 + 2744*t^2 + 9604*t + 16807 - sage: u.is_weil_polynomial() # optional - sage.libs.pari + sage: u.is_weil_polynomial() # needs sage.libs.pari True AUTHORS: @@ -9002,6 +9199,8 @@ cdef class Polynomial(CommutativePolynomial): For full definitions and related discussion, see [BrHu2019]_ and [HMMS2019]_. """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.base_ring(), 1, [self.variable_name()]) return R(self).is_lorentzian(explain=explain) @@ -9044,12 +9243,13 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (2*x^2).gcd(2*x) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: (2*x^2).gcd(2*x) x - sage: R.zero().gcd(0) # optional - sage.rings.number_field + sage: R.zero().gcd(0) 0 - sage: (2*x).gcd(0) # optional - sage.rings.number_field + sage: (2*x).gcd(0) x One can easily add xgcd functionality to new rings by providing a @@ -9175,11 +9375,12 @@ cdef class Polynomial(CommutativePolynomial): Over `\QQ_5`:: - sage: x = PolynomialRing(Qp(5), 'x').gen() # optional - sage.rings.padics - sage: p = 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + 4*x + 2 # optional - sage.rings.padics - sage: m = x^6 # optional - sage.rings.padics - sage: n, d = p.rational_reconstruction(m, 3, 2) # optional - sage.rings.padics - sage: ((p*d - n) % m).is_zero() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: x = PolynomialRing(Qp(5), 'x').gen() + sage: p = 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + 4*x + 2 + sage: m = x^6 + sage: n, d = p.rational_reconstruction(m, 3, 2) + sage: ((p*d - n) % m).is_zero() True Can also be used to obtain known Padé approximations:: @@ -9427,11 +9628,11 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: R. = ZZ[] - sage: (x^3 + 1).is_irreducible() # optional - sage.libs.pari + sage: (x^3 + 1).is_irreducible() # needs sage.libs.pari False - sage: (x^2 - 1).is_irreducible() # optional - sage.libs.pari + sage: (x^2 - 1).is_irreducible() # needs sage.libs.pari False - sage: (x^3 + 2).is_irreducible() # optional - sage.libs.pari + sage: (x^3 + 2).is_irreducible() # needs sage.libs.pari True sage: R(0).is_irreducible() False @@ -9440,31 +9641,32 @@ cdef class Polynomial(CommutativePolynomial): polynomial in `\QQ[x]`, but not in `\ZZ[x]`:: sage: R. = ZZ[] - sage: R(2*x).is_irreducible() # optional - sage.libs.pari + sage: R(2*x).is_irreducible() # needs sage.libs.pari False sage: R. = QQ[] - sage: R(2*x).is_irreducible() # optional - sage.libs.pari + sage: R(2*x).is_irreducible() # needs sage.libs.pari True TESTS:: - sage: F. = NumberField(x^2 - 5) # optional - sage.rings.number_field - sage: Fx. = PolynomialRing(F) # optional - sage.rings.number_field - sage: f = Fx([2*t - 5, 5*t - 10, 3*t - 6, -t, -t + 2, 1]) # optional - sage.rings.number_field - sage: f.is_irreducible() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: F. = NumberField(x^2 - 5) + sage: Fx. = PolynomialRing(F) + sage: f = Fx([2*t - 5, 5*t - 10, 3*t - 6, -t, -t + 2, 1]) + sage: f.is_irreducible() False - sage: f = Fx([2*t - 3, 5*t - 10, 3*t - 6, -t, -t + 2, 1]) # optional - sage.rings.number_field - sage: f.is_irreducible() # optional - sage.rings.number_field + sage: f = Fx([2*t - 3, 5*t - 10, 3*t - 6, -t, -t + 2, 1]) + sage: f.is_irreducible() True If the base ring implements `_is_irreducible_univariate_polynomial`, then this method gets used instead of the generic algorithm which just factors the input:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: hasattr(QQbar, "_is_irreducible_univariate_polynomial") # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: hasattr(QQbar, "_is_irreducible_univariate_polynomial") # needs sage.rings.number_field True - sage: (x^2 + 1).is_irreducible() # optional - sage.rings.number_field + sage: (x^2 + 1).is_irreducible() # needs sage.rings.number_field False Constants can be irreducible if they are not units:: @@ -9472,17 +9674,17 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: R(1).is_irreducible() False - sage: R(4).is_irreducible() # optional - sage.libs.pari + sage: R(4).is_irreducible() False - sage: R(5).is_irreducible() # optional - sage.libs.pari + sage: R(5).is_irreducible() True Check that caching works:: sage: R. = ZZ[] - sage: x.is_irreducible() # optional - sage.libs.pari + sage: x.is_irreducible() # needs sage.libs.pari True - sage: x.is_irreducible.cache # optional - sage.libs.pari + sage: x.is_irreducible.cache # needs sage.libs.pari True @@ -9629,56 +9831,58 @@ cdef class Polynomial(CommutativePolynomial): A generic implementation is available, which relies on gcd computations:: + sage: # needs sage.libs.pari sage: R. = ZZ[] - sage: (2*x).is_squarefree() # optional - sage.libs.pari + sage: (2*x).is_squarefree() # needs sage.libs.pari True - sage: (4*x).is_squarefree() # optional - sage.libs.pari + sage: (4*x).is_squarefree() # needs sage.libs.pari False - sage: (2*x^2).is_squarefree() # optional - sage.libs.pari + sage: (2*x^2).is_squarefree() # needs sage.libs.pari False - sage: R(0).is_squarefree() # optional - sage.libs.pari + sage: R(0).is_squarefree() # needs sage.libs.pari False - sage: S. = QQ[] # optional - sage.libs.pari - sage: R. = S[] # optional - sage.libs.pari - sage: (2*x*y).is_squarefree() # optional - sage.libs.pari + + sage: S. = QQ[] + sage: R. = S[] + sage: (2*x*y).is_squarefree() True - sage: (2*x*y^2).is_squarefree() # optional - sage.libs.pari + sage: (2*x*y^2).is_squarefree() False In positive characteristic, we compute the square-free decomposition or a full factorization, depending on which is available:: - sage: K. = FunctionField(GF(3)) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: (x^3 - x).is_squarefree() # optional - sage.rings.finite_rings + sage: K. = FunctionField(GF(3)) + sage: R. = K[] + sage: (x^3 - x).is_squarefree() True - sage: (x^3 - 1).is_squarefree() # optional - sage.rings.finite_rings + sage: (x^3 - 1).is_squarefree() # needs sage.libs.pari False - sage: (x^3 + t).is_squarefree() # optional - sage.rings.finite_rings + sage: (x^3 + t).is_squarefree() # needs sage.libs.pari True - sage: (x^3 + t^3).is_squarefree() # optional - sage.rings.finite_rings + sage: (x^3 + t^3).is_squarefree() # needs sage.libs.pari False In the following example, `t^2` is a unit in the base field:: - sage: R(t^2).is_squarefree() # optional - sage.rings.finite_rings + sage: R(t^2).is_squarefree() True This method is not consistent with :meth:`.squarefree_decomposition`:: sage: R. = ZZ[] sage: f = 4 * x - sage: f.is_squarefree() # optional - sage.rings.finite_rings + sage: f.is_squarefree() # needs sage.libs.pari False - sage: f.squarefree_decomposition() # optional - sage.rings.finite_rings + sage: f.squarefree_decomposition() # needs sage.libs.pari (4) * x If you want this method equally not to consider the content, you can remove it as in the following example:: sage: c = f.content() - sage: (f/c).is_squarefree() # optional - sage.rings.finite_rings + sage: (f/c).is_squarefree() # needs sage.libs.pari True If the base ring is not an integral domain, the question is not @@ -9699,7 +9903,7 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = ZZ[] sage: f = x^2 - sage: f.is_squarefree() + sage: f.is_squarefree() # needs sage.libs.pari False sage: f.is_squarefree.cache False @@ -9708,15 +9912,16 @@ cdef class Polynomial(CommutativePolynomial): then this method gets used instead of the generic algorithm in :meth:`_is_squarefree_generic`:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x^2).is_squarefree() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: (x^2).is_squarefree() False - sage: hasattr(QQbar, '_is_squarefree_univariate_polynomial') # optional - sage.rings.number_field + sage: hasattr(QQbar, '_is_squarefree_univariate_polynomial') False - sage: QQbar._is_squarefree_univariate_polynomial = lambda self: True # optional - sage.rings.number_field - sage: (x^2).is_squarefree() # optional - sage.rings.number_field + sage: QQbar._is_squarefree_univariate_polynomial = lambda self: True + sage: (x^2).is_squarefree() True - sage: del(QQbar._is_squarefree_univariate_polynomial) # optional - sage.rings.number_field + sage: del(QQbar._is_squarefree_univariate_polynomial) """ B = self._parent.base_ring() @@ -9736,10 +9941,10 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: (x^2*(x + 1)).is_squarefree() # indirect doctest # optional - sage.rings.number_field + sage: R. = QQbar[] # needs sage.rings.number_field + sage: (x^2*(x + 1)).is_squarefree() # indirect doctest # needs sage.rings.number_field False - sage: (x*(x+1)).is_squarefree() # indirect doctest # optional - sage.rings.number_field + sage: (x*(x+1)).is_squarefree() # indirect doctest # needs sage.rings.number_field True """ @@ -9790,8 +9995,8 @@ cdef class Polynomial(CommutativePolynomial): If self has a factor of multiplicity divisible by the characteristic (see :trac:`8736`):: - sage: P. = GF(2)[] # optional - sage.rings.finite_rings - sage: (x^3 + x^2).radical() # optional - sage.rings.finite_rings + sage: P. = GF(2)[] + sage: (x^3 + x^2).radical() # needs sage.rings.finite_rings x^2 + x """ P = self._parent @@ -9850,38 +10055,39 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R. = RR[] sage: f = x^6 + x^2 + -x^4 - 2*x^3 sage: f.norm(2) 2.64575131106459 - sage: (sqrt(1^2 + 1^2 + (-1)^2 + (-2)^2)).n() + sage: (sqrt(1^2 + 1^2 + (-1)^2 + (-2)^2)).n() # needs sage.symbolic 2.64575131106459 :: - sage: f.norm(1) + sage: f.norm(1) # needs sage.rings.real_mpfr 5.00000000000000 - sage: f.norm(infinity) + sage: f.norm(infinity) # needs sage.rings.real_mpfr 2.00000000000000 :: - sage: f.norm(-1) + sage: f.norm(-1) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: The degree of the norm must be positive TESTS:: - sage: R. = RR[] - sage: f = x^6 + x^2 + -x^4 -x^3 - sage: f.norm(int(2)) + sage: R. = RR[] # needs sage.rings.real_mpfr + sage: f = x^6 + x^2 + -x^4 -x^3 # needs sage.rings.real_mpfr + sage: f.norm(int(2)) # needs sage.rings.real_mpfr 2.00000000000000 Check that :trac:`18600` is fixed:: sage: R. = PolynomialRing(ZZ, sparse=True) - sage: (x^2^100 + 1).norm(1) + sage: (x^2^100 + 1).norm(1) # needs sage.rings.real_mpfr 2.00000000000000 AUTHORS: @@ -9889,7 +10095,9 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes - William Stein: fix bugs, add definition, etc. """ - if p <= 0 : + from sage.rings.real_mpfr import RR + + if p <= 0: raise ValueError("The degree of the norm must be positive") coeffs = self.coefficients() @@ -9920,10 +10128,10 @@ cdef class Polynomial(CommutativePolynomial): sage: f = (x + 1)^100 sage: f.number_of_terms() 101 - sage: S = GF(5)['y'] # optional - sage.rings.finite_rings - sage: S(f).number_of_terms() # optional - sage.rings.finite_rings + sage: S = GF(5)['y'] + sage: S(f).number_of_terms() 5 - sage: cyclotomic_polynomial(105).number_of_terms() # optional - sage.rings.finite_rings + sage: cyclotomic_polynomial(105).number_of_terms() 33 The method :meth:`hamming_weight` is an alias:: @@ -9959,41 +10167,43 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: R. = SR[] # optional - sage.symbolic - sage: f = (1+I)*x^2 + 3*x - I # optional - sage.symbolic - sage: f.map_coefficients(lambda z: z.conjugate()) # optional - sage.symbolic - (-I + 1)*x^2 + 3*x + I sage: R. = ZZ[] sage: f = x^2 + 2 sage: f.map_coefficients(lambda a: a + 42) 43*x^2 + 44 - sage: R. = PolynomialRing(SR, sparse=True) # optional - sage.symbolic - sage: f = (1+I)*x^(2^32) - I # optional - sage.symbolic - sage: f.map_coefficients(lambda z: z.conjugate()) # optional - sage.symbolic - (-I + 1)*x^4294967296 + I sage: R. = PolynomialRing(ZZ, sparse=True) sage: f = x^(2^32) + 2 sage: f.map_coefficients(lambda a: a + 42) 43*x^4294967296 + 44 + sage: # needs sage.symbolic + sage: R. = SR[] + sage: f = (1+I)*x^2 + 3*x - I + sage: f.map_coefficients(lambda z: z.conjugate()) + (-I + 1)*x^2 + 3*x + I + sage: R. = PolynomialRing(SR, sparse=True) + sage: f = (1+I)*x^(2^32) - I + sage: f.map_coefficients(lambda z: z.conjugate()) + (-I + 1)*x^4294967296 + I + Examples with different base ring:: sage: R. = ZZ[] - sage: k = GF(2) # optional - sage.rings.finite_rings - sage: residue = lambda x: k(x) # optional - sage.rings.finite_rings - sage: f = 4*x^2 + x + 3 # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(residue); g # optional - sage.rings.finite_rings + sage: k = GF(2) + sage: residue = lambda x: k(x) + sage: f = 4*x^2 + x + 3 + sage: g = f.map_coefficients(residue); g x + 1 - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() Univariate Polynomial Ring in x over Integer Ring - sage: g = f.map_coefficients(residue, new_base_ring=k); g # optional - sage.rings.finite_rings + sage: g = f.map_coefficients(residue, new_base_ring=k); g x + 1 - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: residue = k.coerce_map_from(ZZ) # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(residue); g # optional - sage.rings.finite_rings + sage: residue = k.coerce_map_from(ZZ) + sage: g = f.map_coefficients(residue); g x + 1 - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) """ R = self._parent @@ -10040,54 +10250,55 @@ cdef class Polynomial(CommutativePolynomial): Quick tests:: + sage: # needs sage.libs.pari sage: P. = ZZ['x'] - sage: (x - 1).is_cyclotomic() # optional - sage.libs.pari + sage: (x - 1).is_cyclotomic() True - sage: (x + 1).is_cyclotomic() # optional - sage.libs.pari + sage: (x + 1).is_cyclotomic() True - sage: (x^2 - 1).is_cyclotomic() # optional - sage.libs.pari + sage: (x^2 - 1).is_cyclotomic() False - sage: (x^2 + x + 1).is_cyclotomic(certificate=True) # optional - sage.libs.pari + sage: (x^2 + x + 1).is_cyclotomic(certificate=True) 3 - sage: (x^2 + 2*x + 1).is_cyclotomic(certificate=True) # optional - sage.libs.pari + sage: (x^2 + 2*x + 1).is_cyclotomic(certificate=True) 0 Test first 100 cyclotomic polynomials:: - sage: all(cyclotomic_polynomial(i).is_cyclotomic() for i in range(1, 101)) # optional - sage.libs.pari + sage: all(cyclotomic_polynomial(i).is_cyclotomic() for i in range(1, 101)) # needs sage.libs.pari True Some more tests:: + sage: # needs sage.libs.pari sage: f = x^16 + x^14 - x^10 + x^8 - x^6 + x^2 + 1 - sage: f.is_cyclotomic(algorithm="pari") # optional - sage.libs.pari + sage: f.is_cyclotomic(algorithm="pari") False - sage: f.is_cyclotomic(algorithm="sage") # optional - sage.libs.pari + sage: f.is_cyclotomic(algorithm="sage") False - sage: g = x^16 + x^14 - x^10 - x^8 - x^6 + x^2 + 1 - sage: g.is_cyclotomic(algorithm="pari") # optional - sage.libs.pari + sage: g.is_cyclotomic(algorithm="pari") True - sage: g.is_cyclotomic(algorithm="sage") # optional - sage.libs.pari + sage: g.is_cyclotomic(algorithm="sage") True sage: y = polygen(QQ) - sage: (y/2 - 1/2).is_cyclotomic() # optional - sage.libs.pari + sage: (y/2 - 1/2).is_cyclotomic() False - sage: (2*(y/2 - 1/2)).is_cyclotomic() # optional - sage.libs.pari + sage: (2*(y/2 - 1/2)).is_cyclotomic() # needs sage.libs.pari True Invalid arguments:: - sage: (x - 3).is_cyclotomic(algorithm="sage", certificate=True) + sage: (x - 3).is_cyclotomic(algorithm="sage", certificate=True) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no implementation of the certificate within Sage Test using other rings:: - sage: z = polygen(GF(5)) # optional - sage.rings.finite_rings - sage: (z - 1).is_cyclotomic() # optional - sage.rings.finite_rings + sage: z = polygen(GF(5)) + sage: (z - 1).is_cyclotomic() Traceback (most recent call last): ... NotImplementedError: not implemented in non-zero characteristic @@ -10095,28 +10306,28 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: sage: R = ZZ['x'] - sage: for _ in range(20): # optional - sage.libs.pari + sage: for _ in range(20): # needs sage.libs.pari ....: p = R.random_element(degree=randint(10,20)) ....: ans_pari = p.is_cyclotomic(algorithm="pari") ....: ans_sage = p.is_cyclotomic(algorithm="sage") ....: assert ans_pari == ans_sage, "problem with p={}".format(p) - sage: for d in range(2, 20): # optional - sage.libs.pari + sage: for d in range(2, 20): # needs sage.libs.pari ....: p = cyclotomic_polynomial(d) ....: assert p.is_cyclotomic(algorithm="pari"), "pari problem with p={}".format(p) ....: assert p.is_cyclotomic(algorithm="sage"), "sage problem with p={}".format(p) Test the output type when ``certificate=True``:: - sage: type((x^2 - 2).is_cyclotomic(certificate=True)) # optional - sage.libs.pari + sage: type((x^2 - 2).is_cyclotomic(certificate=True)) # needs sage.libs.pari - sage: type((x - 1).is_cyclotomic(certificate=True)) # optional - sage.libs.pari + sage: type((x - 1).is_cyclotomic(certificate=True)) # needs sage.libs.pari Check that the arguments are forwarded when the input is not a polynomial with coefficients in `\ZZ`:: sage: x = polygen(QQ) - sage: (x - 1).is_cyclotomic(certificate=True) # optional - sage.libs.pari + sage: (x - 1).is_cyclotomic(certificate=True) # needs sage.libs.pari 1 """ S = self.base_ring() @@ -10193,20 +10404,20 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^5 - 1).is_cyclotomic_product() # optional - sage.libs.pari + sage: (x^5 - 1).is_cyclotomic_product() # needs sage.libs.pari True - sage: (x^5 + x^4 - x^2 + 1).is_cyclotomic_product() # optional - sage.libs.pari + sage: (x^5 + x^4 - x^2 + 1).is_cyclotomic_product() # needs sage.libs.pari False - sage: p = prod(cyclotomic_polynomial(i) for i in [2, 5, 7, 12]) # optional - sage.libs.pari - sage: p.is_cyclotomic_product() # optional - sage.libs.pari + sage: p = prod(cyclotomic_polynomial(i) for i in [2, 5, 7, 12]) + sage: p.is_cyclotomic_product() # needs sage.libs.pari True - sage: (x^5 - 1/3).is_cyclotomic_product() # optional - sage.libs.pari + sage: (x^5 - 1/3).is_cyclotomic_product() False sage: x = polygen(Zmod(5)) - sage: (x - 1).is_cyclotomic_product() # optional - sage.libs.pari + sage: (x - 1).is_cyclotomic_product() Traceback (most recent call last): ... NotImplementedError: not implemented in non-zero characteristic @@ -10327,8 +10538,8 @@ cdef class Polynomial(CommutativePolynomial): True sage: u = x^5 - 2; u.has_cyclotomic_factor() False - sage: u = pol(cyclotomic_polynomial(7)) * pol.random_element() # random # optional - sage.libs.pari - sage: u.has_cyclotomic_factor() # random # optional - sage.libs.pari + sage: u = pol(cyclotomic_polynomial(7)) * pol.random_element() # random + sage: u.has_cyclotomic_factor() # random True """ if not QQ.has_coerce_map_from(self.base_ring()): @@ -10419,9 +10630,9 @@ cdef class Polynomial(CommutativePolynomial): In positive characteristic, the degree can drop in this case:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: f = x + 1 # optional - sage.rings.finite_rings - sage: f.homogenize(x) # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: f = x + 1 + sage: f.homogenize(x) 0 For compatibility with the multivariate case, the parameter ``var`` can @@ -10450,6 +10661,8 @@ cdef class Polynomial(CommutativePolynomial): if var == x_name: return sum(self.coefficients())*x**self.degree() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(self.base_ring(), [x_name, var]) return P(self)._homogenize(1) @@ -10498,43 +10711,46 @@ cdef class Polynomial(CommutativePolynomial): sage: a.nth_root(2) 1/56*x^3 + 103/336*x^2 + 365/252*x + 25/12 - sage: K. = QuadraticField(2) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: a = (x + sqrt2)^3 * ((1+sqrt2)*x - 1/sqrt2)^6 # optional - sage.rings.number_field - sage: b = a.nth_root(3); b # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(2) + sage: R. = K[] + sage: a = (x + sqrt2)^3 * ((1+sqrt2)*x - 1/sqrt2)^6 + sage: b = a.nth_root(3); b (2*sqrt2 + 3)*x^3 + (2*sqrt2 + 2)*x^2 + (-2*sqrt2 - 3/2)*x + 1/2*sqrt2 - sage: b^3 == a # optional - sage.rings.number_field + sage: b^3 == a True - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: p = x**3 + QQbar(2).sqrt() * x - QQbar(3).sqrt() # optional - sage.rings.number_field - sage: r = (p**5).nth_root(5) # optional - sage.rings.number_field - sage: r * p[0] == p * r[0] # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: p = x**3 + QQbar(2).sqrt() * x - QQbar(3).sqrt() + sage: r = (p**5).nth_root(5) + sage: r * p[0] == p * r[0] True - sage: p = (x+1)^20 + x^20 # optional - sage.rings.number_field - sage: p.nth_root(20) # optional - sage.rings.number_field + sage: p = (x+1)^20 + x^20 + sage: p.nth_root(20) Traceback (most recent call last): ... ValueError: not a 20th power - sage: z = GF(4).gen() # optional - sage.rings.finite_rings - sage: R. = GF(4)[] # optional - sage.rings.finite_rings - sage: p = z*x**4 + 2*x - 1 # optional - sage.rings.finite_rings - sage: r = (p**15).nth_root(15) # optional - sage.rings.finite_rings - sage: r * p[0] == p * r[0] # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: z = GF(4).gen() + sage: R. = GF(4)[] + sage: p = z*x**4 + 2*x - 1 + sage: r = (p**15).nth_root(15) + sage: r * p[0] == p * r[0] True - sage: ((x+1)**2).nth_root(2) # optional - sage.rings.finite_rings + sage: ((x+1)**2).nth_root(2) x + 1 - sage: ((x+1)**4).nth_root(4) # optional - sage.rings.finite_rings + sage: ((x+1)**4).nth_root(4) x + 1 - sage: ((x+1)**12).nth_root(12) # optional - sage.rings.finite_rings + sage: ((x+1)**12).nth_root(12) x + 1 - sage: (x^4 + x^3 + 1).nth_root(2) # optional - sage.rings.finite_rings + sage: (x^4 + x^3 + 1).nth_root(2) Traceback (most recent call last): ... ValueError: not a 2nd power - sage: p = (x+1)^17 + x^17 # optional - sage.rings.finite_rings - sage: r = p.nth_root(17) # optional - sage.rings.finite_rings + sage: p = (x+1)^17 + x^17 + sage: r = p.nth_root(17) Traceback (most recent call last): ... ValueError: not a 17th power @@ -10550,15 +10766,16 @@ cdef class Polynomial(CommutativePolynomial): Here we consider a base ring without ``nth_root`` method. The third example with a non-trivial coefficient of lowest degree raises an error:: + sage: # needs sage.libs.pari sage: R. = QQ[] - sage: R2 = R.quotient(x**2 + 1) # optional - sage.libs.pari - sage: x = R2.gen() # optional - sage.libs.pari - sage: R3. = R2[] # optional - sage.libs.pari - sage: (y**2 - 2*y + 1).nth_root(2) # optional - sage.libs.pari + sage: R2 = R.quotient(x**2 + 1) + sage: x = R2.gen() + sage: R3. = R2[] + sage: (y**2 - 2*y + 1).nth_root(2) -y + 1 - sage: (y**3).nth_root(3) # optional - sage.libs.pari + sage: (y**3).nth_root(3) y - sage: (y**2 + x).nth_root(2) # optional - sage.libs.pari + sage: (y**2 + x).nth_root(2) Traceback (most recent call last): ... AttributeError: ... has no attribute 'nth_root' @@ -10594,7 +10811,7 @@ cdef class Polynomial(CommutativePolynomial): Some random tests:: - sage: for R in [QQ['x'], GF(4)['x']]: # optional - sage.rings.finite_rings + sage: for R in [QQ['x'], GF(4)['x']]: # needs sage.rings.finite_rings ....: for _ in range(30): ....: p = R.random_element(degree=randint(10,20)) ....: n = ZZ.random_element(2,20) @@ -10678,10 +10895,11 @@ cdef class Polynomial(CommutativePolynomial): sage: R.one()._nth_root_series(3, 5) 1 - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: p = 2 + 3*x^2 # optional - sage.rings.number_field - sage: q = p._nth_root_series(3, 20) # optional - sage.rings.number_field - sage: (q**3).truncate(20) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: p = 2 + 3*x^2 + sage: q = p._nth_root_series(3, 20) + sage: (q**3).truncate(20) 3*x^2 + 2 The exponent must be invertible in the base ring:: @@ -10703,12 +10921,12 @@ cdef class Polynomial(CommutativePolynomial): Finite characteristic:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: (1 + x)._nth_root_series(3, 10) # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: (1 + x)._nth_root_series(3, 10) x^9 + x^8 + x^3 + x^2 + x + 1 - sage: (1 + x^2)._nth_root_series(2, 10) # optional - sage.rings.finite_rings + sage: (1 + x^2)._nth_root_series(2, 10) x + 1 - sage: (1 + x)._nth_root_series(2, 10) # optional - sage.rings.finite_rings + sage: (1 + x)._nth_root_series(2, 10) Traceback (most recent call last): ... ValueError: not a 2nd power @@ -10821,21 +11039,24 @@ cdef class Polynomial(CommutativePolynomial): TESTS:: - sage: R. = PolynomialRing(ZZ, implementation="NTL") # optional - sage.libs.ntl - sage: (2*x + 1).divides(4*x**2 + 1) # optional - sage.libs.ntl + sage: R. = PolynomialRing(ZZ, implementation="NTL") # needs sage.libs.ntl + sage: (2*x + 1).divides(4*x**2 + 1) # needs sage.libs.ntl False - sage: K. = GF(4) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: p = ((3*z + 2)*x + 2*z - 1) * y + 2*x + z # optional - sage.rings.finite_rings - sage: q = y^2 + z*y*x + 2*y + z # optional - sage.rings.finite_rings - sage: p.divides(q), p.divides(p*q) # optional - sage.rings.finite_rings + + sage: # needs sage.rings.finite_rings + sage: K. = GF(4) + sage: R. = K[] + sage: S. = R[] + sage: p = ((3*z + 2)*x + 2*z - 1) * y + 2*x + z + sage: q = y^2 + z*y*x + 2*y + z + sage: p.divides(q), p.divides(p*q) (False, True) - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: p = (x+y+1) * z + x*y # optional - sage.rings.finite_rings - sage: q = (y^2-x^2) * z^2 + z + x-y # optional - sage.rings.finite_rings - sage: p.divides(q), p.divides(p*q) # optional - sage.rings.finite_rings + + sage: R. = GF(2)[] + sage: S. = R[] + sage: p = (x+y+1) * z + x*y + sage: q = (y^2-x^2) * z^2 + z + x-y + sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ if not self.base_ring().is_integral_domain(): @@ -10909,8 +11130,8 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: Pol. = CBF[] - sage: (1 + x)._log_series(3) + sage: Pol. = CBF[] # needs sage.libs.flint + sage: (1 + x)._log_series(3) # needs sage.libs.flint -0.5000000000000000*x^2 + x """ raise NotImplementedError @@ -10922,8 +11143,8 @@ cdef class Polynomial(CommutativePolynomial): EXAMPLES:: - sage: Pol. = CBF[] - sage: x._exp_series(3) + sage: Pol. = CBF[] # needs sage.libs.flint + sage: x._exp_series(3) # needs sage.libs.flint 0.5000000000000000*x^2 + x + 1.000000000000000 """ raise NotImplementedError @@ -11304,6 +11525,7 @@ cdef class Polynomial_generic_dense(Polynomial): TESTS:: + sage: # needs sage.rings.real_mpfr sage: from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense sage: isinstance(f, Polynomial_generic_dense) True @@ -11434,14 +11656,15 @@ cdef class Polynomial_generic_dense(Polynomial): EXAMPLES:: - sage: R. = SR[] # optional - sage.symbolic - sage: R(0).is_term() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: R. = SR[] + sage: R(0).is_term() False - sage: R(1).is_term() # optional - sage.symbolic + sage: R(1).is_term() True - sage: (3*x^5).is_term() # optional - sage.symbolic + sage: (3*x^5).is_term() True - sage: (1 + 3*x^5).is_term() # optional - sage.symbolic + sage: (1 + 3*x^5).is_term() False """ if not self.__coeffs: @@ -11565,30 +11788,32 @@ cdef class Polynomial_generic_dense(Polynomial): EXAMPLES:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: f = (1+2*x)^3 + 3*x; f # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: f = (1+2*x)^3 + 3*x; f 8*x^3 + 12*x^2 + 9*x + 1 - sage: g = f // (1+2*x); g # optional - sage.rings.number_field + sage: g = f // (1+2*x); g 4*x^2 + 4*x + 5/2 - sage: f - g * (1+2*x) # optional - sage.rings.number_field + sage: f - g * (1+2*x) -3/2 - sage: f.quo_rem(1+2*x) # optional - sage.rings.number_field + sage: f.quo_rem(1+2*x) (4*x^2 + 4*x + 5/2, -3/2) TESTS: Check that :trac:`13048` and :trac:`2034` are fixed:: - sage: R. = QQbar[] # optional - sage.rings.number_field - sage: x // x # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQbar[] + sage: x // x 1 - sage: x // 1 # optional - sage.rings.number_field + sage: x // 1 x - sage: x // int(1) # optional - sage.rings.number_field + sage: x // int(1) x - sage: x //= int(1); x # optional - sage.rings.number_field + sage: x //= int(1); x x - sage: int(1) // x # check that this doesn't segfault # optional - sage.rings.number_field + sage: int(1) // x # check that this doesn't segfault Traceback (most recent call last): ... AttributeError: type object 'int' has no attribute 'base_ring' @@ -11702,10 +11927,10 @@ cdef class Polynomial_generic_dense(Polynomial): EXAMPLES:: - sage: R. = GF(17)[] # optional - sage.rings.finite_rings - sage: f = (1+2*x)^3 + 3*x; f # optional - sage.rings.finite_rings + sage: R. = GF(17)[] + sage: f = (1+2*x)^3 + 3*x; f 8*x^3 + 12*x^2 + 9*x + 1 - sage: f.list() # optional - sage.rings.finite_rings + sage: f.list() [1, 9, 12, 8] """ if copy: @@ -11809,12 +12034,13 @@ cdef class Polynomial_generic_dense(Polynomial): Polynomials over noncommutative rings are also allowed (after :trac:`34733`):: - sage: HH = QuaternionAlgebra(QQ, -1, -1) # optional - sage.combinat sage.modules - sage: P. = HH[] # optional - sage.combinat sage.modules - sage: f = P.random_element(5) # optional - sage.combinat sage.modules - sage: g = P.random_element((0, 5)) # optional - sage.combinat sage.modules - sage: q, r = f.quo_rem(g) # optional - sage.combinat sage.modules - sage: f == q*g + r # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: HH = QuaternionAlgebra(QQ, -1, -1) + sage: P. = HH[] + sage: f = P.random_element(5) + sage: g = P.random_element((0, 5)) + sage: q, r = f.quo_rem(g) + sage: f == q*g + r True TESTS: @@ -11945,19 +12171,22 @@ def universal_discriminant(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.rings.polynomial.polynomial_element import universal_discriminant - sage: universal_discriminant(1) # optional - sage.libs.pari + sage: universal_discriminant(1) 1 - sage: universal_discriminant(2) # optional - sage.libs.pari + sage: universal_discriminant(2) a1^2 - 4*a0*a2 - sage: universal_discriminant(3) # optional - sage.libs.pari + sage: universal_discriminant(3) a1^2*a2^2 - 4*a0*a2^3 - 4*a1^3*a3 + 18*a0*a1*a2*a3 - 27*a0^2*a3^2 - sage: universal_discriminant(4).degrees() # optional - sage.libs.pari + sage: universal_discriminant(4).degrees() (3, 4, 4, 4, 3) .. SEEALSO:: :meth:`Polynomial.discriminant` """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) @@ -11982,7 +12211,7 @@ cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): sage: from sage.rings.polynomial.polynomial_element import generic_power_trunc - sage: for S in [ZZ, GF(3)]: # known bug # not tested (see :trac:`32075`) # optional - sage.rings.finite_rings + sage: for S in [ZZ, GF(3)]: # known bug, not tested (see :trac:`32075`) ....: R = PolynomialRing(S, 'x') ....: for _ in range(100): ....: p = R.random_element() @@ -12082,9 +12311,9 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): Coefficients indistinguishable from 0 are not removed. - sage: R = Zp(5) # optional - sage.rings.padics - sage: S. = R[] # optional - sage.rings.padics - sage: S([1, R(0, 20)]) # optional - sage.rings.padics + sage: R = Zp(5) # needs sage.rings.padics + sage: S. = R[] # needs sage.rings.padics + sage: S([1, R(0, 20)]) # needs sage.rings.padics O(5^20)*x + 1 + O(5^20) """ cdef list x = self.__coeffs @@ -12116,27 +12345,29 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): EXAMPLES:: - sage: K = Qp(3, 10) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = T + 2; f # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(3, 10) + sage: R. = K[] + sage: f = T + 2; f (1 + O(3^10))*T + 2 + O(3^10) - sage: f.degree() # optional - sage.rings.padics + sage: f.degree() 1 - sage: (f - T).degree() # optional - sage.rings.padics + sage: (f - T).degree() 0 - sage: (f - T).degree(secure=True) # optional - sage.rings.padics + sage: (f - T).degree(secure=True) Traceback (most recent call last): ... PrecisionError: the leading coefficient is indistinguishable from 0 - sage: x = O(3^5) # optional - sage.rings.padics - sage: li = [3^i * x for i in range(0,5)]; li # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: x = O(3^5) + sage: li = [3^i * x for i in range(0,5)]; li [O(3^5), O(3^6), O(3^7), O(3^8), O(3^9)] - sage: f = R(li); f # optional - sage.rings.padics + sage: f = R(li); f O(3^9)*T^4 + O(3^8)*T^3 + O(3^7)*T^2 + O(3^6)*T + O(3^5) - sage: f.degree() # optional - sage.rings.padics + sage: f.degree() -1 - sage: f.degree(secure=True) # optional - sage.rings.padics + sage: f.degree(secure=True) Traceback (most recent call last): ... PrecisionError: the leading coefficient is indistinguishable from 0 @@ -12168,20 +12399,21 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): EXAMPLES:: - sage: K = Qp(3, 10) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = T + 2; f # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(3, 10) + sage: R. = K[] + sage: f = T + 2; f (1 + O(3^10))*T + 2 + O(3^10) - sage: f.degree() # optional - sage.rings.padics + sage: f.degree() 1 - sage: f.prec_degree() # optional - sage.rings.padics + sage: f.prec_degree() 1 - sage: g = f - T; g # optional - sage.rings.padics + sage: g = f - T; g # needs sage.rings.padics O(3^10)*T + 2 + O(3^10) - sage: g.degree() # optional - sage.rings.padics + sage: g.degree() # needs sage.rings.padics 0 - sage: g.prec_degree() # optional - sage.rings.padics + sage: g.prec_degree() # needs sage.rings.padics 1 AUTHOR: @@ -12200,20 +12432,20 @@ cdef class ConstantPolynomialSection(Map): EXAMPLES:: - sage: P0. = GF(3)[] # optional - sage.rings.finite_rings - sage: P1. = GF(3)[] # optional - sage.rings.finite_rings - sage: P0(-y_1) # indirect doctest # optional - sage.rings.finite_rings + sage: P0. = GF(3)[] + sage: P1. = GF(3)[] + sage: P0(-y_1) 2*y_1 - sage: phi = GF(3).convert_map_from(P0); phi # optional - sage.rings.finite_rings + sage: phi = GF(3).convert_map_from(P0); phi Generic map: From: Univariate Polynomial Ring in y_1 over Finite Field of size 3 To: Finite Field of size 3 - sage: type(phi) # optional - sage.rings.finite_rings + sage: type(phi) - sage: phi(P0.one()) # optional - sage.rings.finite_rings + sage: phi(P0.one()) 1 - sage: phi(y_1) # optional - sage.rings.finite_rings + sage: phi(y_1) Traceback (most recent call last): ... TypeError: not a constant polynomial @@ -12228,7 +12460,7 @@ cdef class ConstantPolynomialSection(Map): Generic map: From: Univariate Polynomial Ring in x over Rational Field To: Rational Field - sage: m(x-x+1/2) # implicit + sage: m(x-x+1/2) # implicit 1/2 sage: m(x-x) 0 @@ -12264,18 +12496,20 @@ cdef class PolynomialBaseringInjection(Morphism): supposed to be the fastest maps for that purpose. See :trac:`9944`. :: - sage: R. = Qp(3)[] # optional - sage.rings.padics - sage: R.coerce_map_from(R.base_ring()) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: R. = Qp(3)[] + sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: From: 3-adic Field with capped relative precision 20 To: Univariate Polynomial Ring in x over 3-adic Field with capped relative precision 20 - sage: R. = Qp(3)[] # optional - sage.rings.padics - sage: R.coerce_map_from(R.base_ring()) # optional - sage.rings.padics + sage: R. = Qp(3)[] + sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: From: 3-adic Field with capped relative precision 20 To: Multivariate Polynomial Ring in x, y over 3-adic Field with capped relative precision 20 + sage: R. = QQ[] sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: @@ -12314,11 +12548,12 @@ cdef class PolynomialBaseringInjection(Morphism): :: - sage: R. = Qp(2)[] # optional - sage.rings.padics - sage: f = R.convert_map_from(R.base_ring()) # indirect doctest # optional - sage.rings.padics - sage: f(Qp(2).one()*3) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: R. = Qp(2)[] + sage: f = R.convert_map_from(R.base_ring()) # indirect doctest + sage: f(Qp(2).one()*3) 1 + 2 + O(2^20) - sage: (Qp(2).one()*3)*t # optional - sage.rings.padics + sage: (Qp(2).one()*3)*t (1 + 2 + O(2^20))*t """ assert codomain.base_ring() is domain, "domain must be basering" @@ -12370,7 +12605,7 @@ cdef class PolynomialBaseringInjection(Morphism): Polynomial base injection morphism: From: Integer Ring To: Univariate Polynomial Ring in x over Integer Ring - sage: m(2) # indirect doctest + sage: m(2) # indirect doctest 2 sage: parent(m(2)) Univariate Polynomial Ring in x over Integer Ring @@ -12382,8 +12617,8 @@ cdef class PolynomialBaseringInjection(Morphism): TESTS:: sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection - sage: m = PolynomialBaseringInjection(Qp(5), Qp(5)['x']) # optional - sage.rings.padics - sage: m(1 + O(5^11), absprec=5) # indirect doctest # optional - sage.rings.padics + sage: m = PolynomialBaseringInjection(Qp(5), Qp(5)['x']) # needs sage.rings.padics + sage: m(1 + O(5^11), absprec=5) # indirect doctest # needs sage.rings.padics 1 + O(5^11) """ try: @@ -12421,7 +12656,7 @@ cdef class PolynomialBaseringInjection(Morphism): Check that :trac:`23203` has been resolved:: - sage: R.is_subring(S) # indirect doctest + sage: R.is_subring(S) # indirect doctest True """ diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index cf4e6344a8c..77b9a7d8c92 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -14,10 +14,10 @@ sage: W. = QQ['w'] sage: WZ. = W['z'] - sage: m = matrix(WZ, 2, 2, [1, z, z, z^2]) # optional - sage.modules - sage: a = m.charpoly() # optional - sage.modules - sage: R. = WZ[] # optional - sage.modules - sage: R(a) # optional - sage.modules + sage: m = matrix(WZ, 2, 2, [1, z, z, z^2]) # needs sage.modules + sage: a = m.charpoly() # needs sage.modules + sage: R. = WZ[] + sage: R(a) # needs sage.modules x^2 + (-z^2 - 1)*x """ @@ -34,7 +34,11 @@ from sage.rings.polynomial.polynomial_singular_interface import Polynomial_singular_repr -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + from sage.structure.richcmp import richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn from sage.structure.element import coerce_binop, parent @@ -65,15 +69,16 @@ class Polynomial_generic_sparse(Polynomial): A more extensive example:: - sage: A. = PolynomialRing(Integers(5), sparse=True) # optional - sage.libs.pari - sage: f = T^2 + 1; B = A.quo(f) # optional - sage.libs.pari - sage: C. = PolynomialRing(B) # optional - sage.libs.pari - sage: C # optional - sage.libs.pari + sage: # needs sage.libs.pari + sage: A. = PolynomialRing(Integers(5), sparse=True) + sage: f = T^2 + 1; B = A.quo(f) + sage: C. = PolynomialRing(B) + sage: C Univariate Polynomial Ring in s over Univariate Quotient Polynomial Ring in Tbar over Ring of integers modulo 5 with modulus T^2 + 1 - sage: s + T # optional - sage.libs.pari + sage: s + T s + Tbar - sage: (s + T)**2 # optional - sage.libs.pari + sage: (s + T)**2 s^2 + 2*Tbar*s + 4 """ @@ -81,11 +86,11 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): """ TESTS:: - sage: PolynomialRing(RIF, 'z', sparse=True)([RIF(-1, 1), RIF(-1,1)]) + sage: PolynomialRing(RIF, 'z', sparse=True)([RIF(-1, 1), RIF(-1,1)]) # needs sage.rings.real_interval_field 0.?*z + 0.? - sage: PolynomialRing(RIF, 'z', sparse=True)((RIF(-1, 1), RIF(-1,1))) + sage: PolynomialRing(RIF, 'z', sparse=True)((RIF(-1, 1), RIF(-1,1))) # needs sage.rings.real_interval_field 0.?*z + 0.? - sage: PolynomialRing(CIF, 'z', sparse=True)([CIF(RIF(-1,1), RIF(-1,1)), RIF(-1,1)]) + sage: PolynomialRing(CIF, 'z', sparse=True)([CIF(RIF(-1,1), RIF(-1,1)), RIF(-1,1)]) # needs sage.rings.complex_interval_field 0.?*z + 0.? + 0.?*I """ Polynomial.__init__(self, parent, is_gen=is_gen) @@ -190,13 +195,14 @@ def valuation(self, p=None): EXAMPLES:: - sage: R. = PolynomialRing(GF(9, 'a'), sparse=True) # optional - sage.rings.finite_rings - sage: f = w^1997 - w^10000 # optional - sage.rings.finite_rings - sage: f.valuation() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = PolynomialRing(GF(9, 'a'), sparse=True) + sage: f = w^1997 - w^10000 + sage: f.valuation() 1997 - sage: R(19).valuation() # optional - sage.rings.finite_rings + sage: R(19).valuation() 0 - sage: R(0).valuation() # optional - sage.rings.finite_rings + sage: R(0).valuation() +Infinity """ if not self.__coeffs: @@ -245,10 +251,10 @@ def _derivative(self, var=None): Check that :trac:`28187` is fixed:: sage: R = PolynomialRing(ZZ, 't', sparse=True) - sage: t, u = var('t, u') # optional - sage.symbolic - sage: R.gen()._derivative(t) # optional - sage.symbolic + sage: t, u = var('t, u') # needs sage.symbolic + sage: R.gen()._derivative(t) # needs sage.symbolic 1 - sage: R.gen()._derivative(u) # optional - sage.symbolic + sage: R.gen()._derivative(u) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to u @@ -356,6 +362,7 @@ def _repr(self, name=None): r""" EXAMPLES:: + sage: # needs sage.rings.complex_double sage.symbolic sage: R. = PolynomialRing(CDF, sparse=True) sage: f = CDF(1,2) + w^5 - CDF(pi)*w + CDF(e) sage: f._repr() # abs tol 1e-15 @@ -365,8 +372,8 @@ def _repr(self, name=None): TESTS:: - sage: pol = RIF['x']([0, 0, (-1,1)]) - sage: PolynomialRing(RIF, 'x', sparse=True)(pol) + sage: pol = RIF['x']([0, 0, (-1,1)]) # needs sage.rings.real_interval_field + sage: PolynomialRing(RIF, 'x', sparse=True)(pol) # needs sage.rings.real_interval_field 0.?*x^2 AUTHOR: @@ -418,40 +425,42 @@ def __getitem__(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: R. = PolynomialRing(RDF, sparse=True) - sage: e = RDF(e) # optional - sage.symbolic - sage: f = sum(e^n*w^n for n in range(4)); f # abs tol 1.1e-14 # optional - sage.symbolic + sage: e = RDF(e) + sage: f = sum(e^n*w^n for n in range(4)); f # abs tol 1.1e-14 20.085536923187664*w^3 + 7.3890560989306495*w^2 + 2.718281828459045*w + 1.0 - sage: f[1] # abs tol 5e-16 # optional - sage.symbolic + sage: f[1] # abs tol 5e-16 2.718281828459045 - sage: f[5] # optional - sage.symbolic + sage: f[5] 0.0 - sage: f[-1] # optional - sage.symbolic + sage: f[-1] 0.0 - sage: R. = PolynomialRing(RealField(19), sparse=True) - sage: f = (2-3.5*x)^3; f + + sage: R. = PolynomialRing(RealField(19), sparse=True) # needs sage.rings.real_mpfr + sage: f = (2-3.5*x)^3; f # needs sage.rings.real_mpfr -42.875*x^3 + 73.500*x^2 - 42.000*x + 8.0000 Using slices, we can truncate polynomials:: - sage: f[:2] + sage: f[:2] # needs sage.rings.real_mpfr -42.000*x + 8.0000 Any other kind of slicing is an error, see :trac:`18940`:: - sage: f[1:3] + sage: f[1:3] # needs sage.rings.real_mpfr Traceback (most recent call last): ... IndexError: polynomial slicing with a start is not defined - sage: f[1:3:2] + sage: f[1:3:2] # needs sage.rings.real_mpfr Traceback (most recent call last): ... IndexError: polynomial slicing with a step is not defined TESTS:: - sage: f["hello"] + sage: f["hello"] # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: list indices must be integers, not str @@ -486,6 +495,7 @@ def _unsafe_mutate(self, n, value): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R. = PolynomialRing(CC, sparse=True) sage: f = z^2 + CC.0; f 1.00000000000000*z^2 + 1.00000000000000*I @@ -495,8 +505,8 @@ def _unsafe_mutate(self, n, value): Much more nasty:: - sage: z._unsafe_mutate(1, 0) - sage: z + sage: z._unsafe_mutate(1, 0) # needs sage.rings.real_mpfr + sage: z # needs sage.rings.real_mpfr 0 """ n = int(n) @@ -549,14 +559,15 @@ def __floordiv__(self, right): EXAMPLES:: - sage: R. = PolynomialRing(QQbar, sparse=True) # optional - sage.rings.number_field - sage: f = (1+2*x)^3 + 3*x; f # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, sparse=True) + sage: f = (1+2*x)^3 + 3*x; f 8*x^3 + 12*x^2 + 9*x + 1 - sage: g = f // (1+2*x); g # optional - sage.rings.number_field + sage: g = f // (1+2*x); g 4*x^2 + 4*x + 5/2 - sage: f - g * (1+2*x) # optional - sage.rings.number_field + sage: f - g * (1+2*x) -3/2 - sage: f.quo_rem(1+2*x) # optional - sage.rings.number_field + sage: f.quo_rem(1+2*x) (4*x^2 + 4*x + 5/2, -3/2) """ @@ -827,12 +838,13 @@ def quo_rem(self, other): Polynomials over noncommutative rings are also allowed:: - sage: HH = QuaternionAlgebra(QQ, -1, -1) # optional - sage.combinat sage.modules - sage: P. = PolynomialRing(HH, sparse=True) # optional - sage.combinat sage.modules - sage: f = P.random_element(5) # optional - sage.combinat sage.modules - sage: g = P.random_element((0, 5)) # optional - sage.combinat sage.modules - sage: q, r = f.quo_rem(g) # optional - sage.combinat sage.modules - sage: f == q*g + r # optional - sage.combinat sage.modules + sage: # needs sage.combinat sage.modules + sage: HH = QuaternionAlgebra(QQ, -1, -1) + sage: P. = PolynomialRing(HH, sparse=True) + sage: f = P.random_element(5) + sage: g = P.random_element((0, 5)) + sage: q, r = f.quo_rem(g) + sage: f == q*g + r True TESTS:: @@ -1066,12 +1078,13 @@ def quo_rem(self, other): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: K. = NumberField(y^2 - 2) # optional - sage.rings.number_field - sage: P. = PolynomialRing(K) # optional - sage.rings.number_field - sage: x.quo_rem(K(1)) # optional - sage.rings.number_field + sage: K. = NumberField(y^2 - 2) + sage: P. = PolynomialRing(K) + sage: x.quo_rem(K(1)) (x, 0) - sage: x.xgcd(K(1)) # optional - sage.rings.number_field + sage: x.xgcd(K(1)) (1, 0, 1) """ P = self.parent() @@ -1142,15 +1155,16 @@ def newton_slopes(self, repetition=True): EXAMPLES:: - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = 5 + 3*t + t^4 + 25*t^10 # optional - sage.rings.padics - sage: f.newton_polygon() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5) + sage: R. = K[] + sage: f = 5 + 3*t + t^4 + 25*t^10 + sage: f.newton_polygon() Finite Newton polygon with 4 vertices: (0, 1), (1, 0), (4, 0), (10, 2) - sage: f.newton_slopes() # optional - sage.rings.padics + sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: f.newton_slopes(repetition=False) # optional - sage.rings.padics + sage: f.newton_slopes(repetition=False) # needs sage.rings.padics [1, 0, -1/3] AUTHOR: @@ -1170,15 +1184,16 @@ def newton_polygon(self): EXAMPLES:: - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = 5 + 3*t + t^4 + 25*t^10 # optional - sage.rings.padics - sage: f.newton_polygon() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5) + sage: R. = K[] + sage: f = 5 + 3*t + t^4 + 25*t^10 + sage: f.newton_polygon() Finite Newton polygon with 4 vertices: (0, 1), (1, 0), (4, 0), (10, 2) - sage: g = f + K(0,0)*t^4; g # optional - sage.rings.padics + sage: g = f + K(0,0)*t^4; g # needs sage.rings.padics (5^2 + O(5^22))*t^10 + O(5^0)*t^4 + (3 + O(5^20))*t + 5 + O(5^21) - sage: g.newton_polygon() # optional - sage.rings.padics + sage: g.newton_polygon() # needs sage.rings.padics Traceback (most recent call last): ... PrecisionError: The coefficient of t^4 has not enough precision @@ -1187,10 +1202,10 @@ def newton_polygon(self): Check that :trac:`22936` is fixed:: - sage: S. = PowerSeriesRing(GF(5)) # optional - sage.rings.finite_rings - sage: R. = S[] # optional - sage.rings.finite_rings - sage: p = x^2 + y + x*y^2 # optional - sage.rings.finite_rings - sage: p.newton_polygon() # optional - sage.rings.finite_rings + sage: S. = PowerSeriesRing(GF(5)) + sage: R. = S[] + sage: p = x^2 + y + x*y^2 + sage: p.newton_polygon() # needs sage.geometry.polyhedron Finite Newton polygon with 3 vertices: (0, 2), (1, 0), (2, 1) AUTHOR: @@ -1225,16 +1240,17 @@ def hensel_lift(self, a): EXAMPLES:: - sage: K = Qp(5, 10) # optional - sage.rings.padics - sage: P. = PolynomialRing(K) # optional - sage.rings.padics - sage: f = x^2 + 1 # optional - sage.rings.padics - sage: root = f.hensel_lift(2); root # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5, 10) + sage: P. = PolynomialRing(K) + sage: f = x^2 + 1 + sage: root = f.hensel_lift(2); root 2 + 5 + 2*5^2 + 5^3 + 3*5^4 + 4*5^5 + 2*5^6 + 3*5^7 + 3*5^9 + O(5^10) - sage: f(root) # optional - sage.rings.padics + sage: f(root) O(5^10) - sage: g = (x^2 + 1) * (x - 7) # optional - sage.rings.padics - sage: g.hensel_lift(2) # here, 2 is a multiple root modulo p # optional - sage.rings.padics + sage: g = (x^2 + 1) * (x - 7) # needs sage.rings.padics + sage: g.hensel_lift(2) # here, 2 is a multiple root modulo p # needs sage.rings.padics Traceback (most recent call last): ... ValueError: a is not close enough to a root of this polynomial @@ -1273,27 +1289,28 @@ def _factor_of_degree(self, deg): EXAMPLES:: - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = 5 + 3*t + t^4 + 25*t^10 # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5) + sage: R. = K[] + sage: K = Qp(5) + sage: R. = K[] + sage: f = 5 + 3*t + t^4 + 25*t^10 - sage: g = f._factor_of_degree(4) # optional - sage.rings.padics - sage: (f % g).is_zero() # optional - sage.rings.padics + sage: g = f._factor_of_degree(4) # needs sage.rings.padics + sage: (f % g).is_zero() # needs sage.rings.padics True - sage: g = f._factor_of_degree(3) # not tested # optional - sage.rings.padics + sage: g = f._factor_of_degree(3) # not tested # needs sage.rings.padics Traceback (most recent call last) ... KeyboardInterrupt: TESTS:: - sage: S. = PowerSeriesRing(GF(5)) # optional - sage.rings.finite_rings - sage: R. = S[] # optional - sage.rings.finite_rings - sage: p = x^2 + y + x*y^2 # optional - sage.rings.finite_rings - sage: p._factor_of_degree(1) # optional - sage.rings.finite_rings + sage: S. = PowerSeriesRing(GF(5)) + sage: R. = S[] + sage: p = x^2 + y + x*y^2 + sage: p._factor_of_degree(1) (1 + O(x^20))*y + x^2 + x^5 + 2*x^8 + 4*x^14 + 2*x^17 + 2*x^20 + O(x^22) AUTHOR: @@ -1337,30 +1354,31 @@ def factor_of_slope(self, slope=None): EXAMPLES:: - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = 5 + 3*t + t^4 + 25*t^10 # optional - sage.rings.padics - sage: f.newton_slopes() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5) + sage: R. = K[] + sage: K = Qp(5) + sage: R. = K[] + sage: f = 5 + 3*t + t^4 + 25*t^10 + sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: g = f.factor_of_slope(0) # optional - sage.rings.padics - sage: g.newton_slopes() # optional - sage.rings.padics + sage: g = f.factor_of_slope(0) # needs sage.rings.padics + sage: g.newton_slopes() # needs sage.rings.padics [0, 0, 0] - sage: (f % g).is_zero() # optional - sage.rings.padics + sage: (f % g).is_zero() # needs sage.rings.padics True - sage: h = f.factor_of_slope() # optional - sage.rings.padics - sage: h.newton_slopes() # optional - sage.rings.padics + sage: h = f.factor_of_slope() # needs sage.rings.padics + sage: h.newton_slopes() # needs sage.rings.padics [1] - sage: (f % h).is_zero() # optional - sage.rings.padics + sage: (f % h).is_zero() # needs sage.rings.padics True If ``slope`` is not a slope of ``self``, the corresponding factor is `1`:: - sage: f.factor_of_slope(-1) # optional - sage.rings.padics + sage: f.factor_of_slope(-1) # needs sage.rings.padics 1 + O(5^20) AUTHOR: @@ -1406,18 +1424,19 @@ def slope_factorization(self): EXAMPLES:: - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: K = Qp(5) # optional - sage.rings.padics - sage: R. = K[] # optional - sage.rings.padics - sage: f = 5 + 3*t + t^4 + 25*t^10 # optional - sage.rings.padics - sage: f.newton_slopes() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K = Qp(5) + sage: R. = K[] + sage: K = Qp(5) + sage: R. = K[] + sage: f = 5 + 3*t + t^4 + 25*t^10 + sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: F = f.slope_factorization() # optional - sage.rings.padics - sage: F.prod() == f # optional - sage.rings.padics + sage: F = f.slope_factorization() # needs sage.rings.padics + sage: F.prod() == f # needs sage.rings.padics True - sage: for (f,_) in F: # optional - sage.rings.padics + sage: for (f,_) in F: # needs sage.rings.padics ....: print(f.newton_slopes()) [-1/3, -1/3, -1/3, -1/3, -1/3, -1/3] [0, 0, 0] @@ -1425,10 +1444,10 @@ def slope_factorization(self): TESTS:: - sage: S. = PowerSeriesRing(GF(5)) # optional - sage.rings.finite_rings - sage: R. = S[] # optional - sage.rings.finite_rings - sage: p = x^2 + y + x*y^2 # optional - sage.rings.finite_rings - sage: p.slope_factorization() # optional - sage.rings.finite_rings + sage: S. = PowerSeriesRing(GF(5)) + sage: R. = S[] + sage: p = x^2 + y + x*y^2 + sage: p.slope_factorization() # needs sage.geometry.polyhedron (x) * ((x + O(x^22))*y + 1 + 4*x^3 + 4*x^6 + 3*x^9 + x^15 + 3*x^18 + O(x^21)) * ((x^-1 + O(x^20))*y + x + x^4 + 2*x^7 + 4*x^13 + 2*x^16 + 2*x^19 + O(x^22)) @@ -1483,11 +1502,12 @@ def _roots(self, secure, minval, hint): TESTS:: - sage: R = Zp(2) # optional - sage.rings.padics - sage: S. = R[] # optional - sage.rings.padics - sage: P = (x-1) * (x-2) * (x-4) * (x-8) * (x-16) # optional - sage.rings.padics - sage: Q = P^2 # optional - sage.rings.padics - sage: Q.roots(algorithm="sage") # indirect doctest # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: R = Zp(2) + sage: S. = R[] + sage: P = (x-1) * (x-2) * (x-4) * (x-8) * (x-16) + sage: Q = P^2 + sage: Q.roots(algorithm="sage") # indirect doctest [(2^4 + O(2^14), 2), (2^3 + O(2^13), 2), (2^2 + O(2^12), 2), @@ -1591,9 +1611,11 @@ class Polynomial_generic_sparse_cdvf(Polynomial_generic_sparse_cdv, Polynomial_g # XXX: Ensures that the generic polynomials implemented in Sage via PARI # # until at least until 4.5.0 unpickle correctly as polynomials implemented # # via FLINT. # -from sage.misc.persist import register_unpickle_override -from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint - -register_unpickle_override( - 'sage.rings.polynomial.polynomial_element_generic', - 'Polynomial_rational_dense', Polynomial_rational_flint) +try: + from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint +except ImportError: + pass +else: + from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.rings.polynomial.polynomial_element_generic', + 'Polynomial_rational_dense', Polynomial_rational_flint) diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index fd03ece69d6..57468e3510f 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -536,30 +536,30 @@ def small_roots(self, X=None, beta=1.0, epsilon=None, **kwds): sage: length = 512 sage: hidden = 110 sage: p = next_prime(2^int(round(length/2))) - sage: q = next_prime( round(pi.n()*p) ) - sage: N = p*q + sage: q = next_prime(round(pi.n()*p)) # needs sage.symbolic + sage: N = p*q # needs sage.symbolic Now we disturb the low 110 bits of `q`:: - sage: qbar = q + ZZ.random_element(0,2^hidden-1) + sage: qbar = q + ZZ.random_element(0, 2^hidden - 1) # needs sage.symbolic And try to recover `q` from it:: - sage: F. = PolynomialRing(Zmod(N), implementation='NTL') - sage: f = x - qbar + sage: F. = PolynomialRing(Zmod(N), implementation='NTL') # needs sage.symbolic + sage: f = x - qbar # needs sage.symbolic We know that the error is `\le 2^{\text{hidden}}-1` and that the modulus we are looking for is `\ge \sqrt{N}`:: sage: from sage.misc.verbose import set_verbose sage: set_verbose(2) - sage: d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random + sage: d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random # needs sage.symbolic verbose 2 () m = 4 verbose 2 () t = 4 verbose 2 () X = 1298074214633706907132624082305023 verbose 1 () LLL of 8x8 matrix (algorithm fpLLL:wrapper) verbose 1 () LLL finished (time = 0.006998) - sage: q == qbar - d + sage: q == qbar - d # needs sage.symbolic True REFERENCES: @@ -1061,8 +1061,8 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): TESTS:: - sage: y = var("y") - sage: f._derivative(y) + sage: y = var("y") # needs sage.symbolic + sage: f._derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1619,8 +1619,8 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): TESTS:: - sage: y = var("y") - sage: f._derivative(y) + sage: y = var("y") # needs sage.symbolic + sage: f._derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y diff --git a/src/sage/rings/polynomial/polynomial_number_field.pyx b/src/sage/rings/polynomial/polynomial_number_field.pyx index a5e7a245574..96f1c002e99 100644 --- a/src/sage/rings/polynomial/polynomial_number_field.pyx +++ b/src/sage/rings/polynomial/polynomial_number_field.pyx @@ -30,34 +30,36 @@ operations with them:: Polynomials are aware of embeddings of the underlying field:: + sage: # needs sage.rings.padics sage: x = polygen(ZZ, 'x') - sage: Q7 = Qp(7) # optional - sage.rings.padics - sage: r1 = Q7(3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 # optional - sage.rings.padics + sage: Q7 = Qp(7) + sage: r1 = Q7(3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 ....: + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 ....: + 4*7^18 + 6*7^19) - sage: N. = NumberField(x^2 - 2, embedding=r1) # optional - sage.rings.padics - sage: K. = N[] # optional - sage.rings.padics - sage: f = t^3 - 2*t + 1 # optional - sage.rings.padics - sage: f(r1) # optional - sage.rings.padics + sage: N. = NumberField(x^2 - 2, embedding=r1) + sage: K. = N[] + sage: f = t^3 - 2*t + 1 + sage: f(r1) 1 + O(7^20) We can also construct polynomials over relative number fields:: - sage: N. = QQ[I, sqrt(2)] # optional - sage.symbolic - sage: K. = N[] # optional - sage.symbolic - sage: f = x - s2 # optional - sage.symbolic - sage: g = x^3 - 2*i*x^2 + s2*x # optional - sage.symbolic - sage: f * (x + s2) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: N. = QQ[I, sqrt(2)] + sage: K. = N[] + sage: f = x - s2 + sage: g = x^3 - 2*i*x^2 + s2*x + sage: f * (x + s2) x^2 - 2 - sage: f + g # optional - sage.symbolic + sage: f + g x^3 - 2*I*x^2 + (sqrt2 + 1)*x - sqrt2 - sage: g // f # optional - sage.symbolic + sage: g // f x^2 + (-2*I + sqrt2)*x - 2*sqrt2*I + sqrt2 + 2 - sage: g % f # optional - sage.symbolic + sage: g % f -4*I + 2*sqrt2 + 2 - sage: factor(i*x^4 - 2*i*x^2 + 9*i) # optional - sage.symbolic + sage: factor(i*x^4 - 2*i*x^2 + 9*i) (I) * (x - I + sqrt2) * (x + I - sqrt2) * (x - I - sqrt2) * (x + I + sqrt2) - sage: gcd(f, x - i) # optional - sage.symbolic + sage: gcd(f, x - i) 1 """ @@ -222,18 +224,18 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): - ``parent`` -- polynomial ring in which to construct the element. - - ``x`` -- (default: None) an object representing the + - ``x`` -- (default: ``None``) an object representing the polynomial, e.g. a list of coefficients. See :meth:`sage.rings.polynomial.polynomial_element_generic.Polynomial_generic_dense_field.__init__` for more details. - - ``check`` -- boolean (default: True) if True, make sure that + - ``check`` -- boolean (default: ``True``) if ``True``, make sure that the coefficients of the polynomial are in the base ring. - - ``is_gen`` -- boolean (default: False) if True, ``x`` is the + - ``is_gen`` -- boolean (default: ``False``) if ``True``, ``x`` is the distinguished generator of the polynomial ring. - - ``construct`` -- (default: False) boolean, unused. + - ``construct`` -- (default: ``False``) boolean, unused. EXAMPLES:: @@ -260,19 +262,20 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): OUTPUT: - - The monic gcd of ``self`` and ``other``. + The monic gcd of ``self`` and ``other``. See :meth:`Polynomial_absolute_number_field_dense.gcd` for more details. EXAMPLES:: - sage: N = QQ[sqrt(2), sqrt(3)] # optional - sage.symbolic - sage: s2, s3 = N.gens() # optional - sage.symbolic - sage: x = polygen(N) # optional - sage.symbolic - sage: f = x^4 - 5*x^2 + 6 # optional - sage.symbolic - sage: g = x^3 + (-2*s2 + s3)*x^2 + (-2*s3*s2 + 2)*x + 2*s3 # optional - sage.symbolic - sage: gcd(f, g) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: N = QQ[sqrt(2), sqrt(3)] + sage: s2, s3 = N.gens() + sage: x = polygen(N) + sage: f = x^4 - 5*x^2 + 6 + sage: g = x^3 + (-2*s2 + s3)*x^2 + (-2*s3*s2 + 2)*x + 2*s3 + sage: gcd(f, g) x^2 + (-sqrt2 + sqrt3)*x - sqrt3*sqrt2 sage: f.gcd(g) x^2 + (-sqrt2 + sqrt3)*x - sqrt3*sqrt2 @@ -305,6 +308,7 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): Test for hardcoded variables:: + sage: # needs sage.symbolic sage: R = N['sqrt2sqrt3'] sage: x = R.gen() sage: f = x^2 - 2 diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 85b8d380d8c..07d5e0cb837 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -1,22 +1,23 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.libs.pari """ Quotients of Univariate Polynomial Rings EXAMPLES:: sage: R. = QQ[] - sage: S = R.quotient(x**3 - 3*x + 1, 'alpha') # optional - sage.libs.pari - sage: S.gen()**2 in S # optional - sage.libs.pari + sage: S = R.quotient(x**3 - 3*x + 1, 'alpha') + sage: S.gen()**2 in S True - sage: x in S # optional - sage.libs.pari + sage: x in S True - sage: S.gen() in R # optional - sage.libs.pari + sage: S.gen() in R False - sage: 1 in S # optional - sage.libs.pari + sage: 1 in S True TESTS:: + sage: # needs sage.libs.flint sage: Pol. = CBF[] sage: Quo. = Pol.quotient(y^3) sage: CBF.zero()*y @@ -39,7 +40,6 @@ from . import polynomial_element import sage.rings.rational_field -import sage.rings.complex_mpfr from sage.rings.ring import Field, IntegralDomain, CommutativeRing @@ -81,25 +81,25 @@ class PolynomialQuotientRingFactory(UniqueFactory): sage: Z = IntegerRing() sage: R = PolynomialRing(Z, 'x'); x = R.gen() - sage: S = R.quotient(x^3 + 7, 'a'); a = S.gen() # optional - sage.libs.pari - sage: S # optional - sage.libs.pari + sage: S = R.quotient(x^3 + 7, 'a'); a = S.gen() + sage: S Univariate Quotient Polynomial Ring in a over Integer Ring with modulus x^3 + 7 - sage: a^3 # optional - sage.libs.pari + sage: a^3 -7 - sage: S.is_field() # optional - sage.libs.pari + sage: S.is_field() False - sage: a in S # optional - sage.libs.pari + sage: a in S True - sage: x in S # optional - sage.libs.pari + sage: x in S True - sage: a in R # optional - sage.libs.pari + sage: a in R False - sage: S.polynomial_ring() # optional - sage.libs.pari + sage: S.polynomial_ring() Univariate Polynomial Ring in x over Integer Ring - sage: S.modulus() # optional - sage.libs.pari + sage: S.modulus() x^3 + 7 - sage: S.degree() # optional - sage.libs.pari + sage: S.degree() 3 We create the "iterated" polynomial ring quotient @@ -110,16 +110,17 @@ class PolynomialQuotientRingFactory(UniqueFactory): :: - sage: A. = PolynomialRing(GF(2)); A # optional - sage.rings.finite_rings + sage: # needs sage.libs.ntl + sage: A. = PolynomialRing(GF(2)); A Univariate Polynomial Ring in y over Finite Field of size 2 (using GF2X) - sage: B = A.quotient(y^2 + y + 1, 'y2'); B # optional - sage.rings.finite_rings + sage: B = A.quotient(y^2 + y + 1, 'y2'); B Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 - sage: C = PolynomialRing(B, 'x'); x = C.gen(); C # optional - sage.rings.finite_rings + sage: C = PolynomialRing(B, 'x'); x = C.gen(); C Univariate Polynomial Ring in x over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 - sage: R = C.quotient(x^3 - 5); R # optional - sage.rings.finite_rings + sage: R = C.quotient(x^3 - 5); R Univariate Quotient Polynomial Ring in xbar over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 @@ -129,22 +130,21 @@ class PolynomialQuotientRingFactory(UniqueFactory): polynomial ring over `\QQ`:: sage: R = PolynomialRing(RationalField(), 'x'); x = R.gen() - sage: S = R.quotient(x^3 + 2*x - 5, 'a') # optional - sage.libs.pari - sage: S # optional - sage.libs.pari + sage: S = R.quotient(x^3 + 2*x - 5, 'a'); S Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5 - sage: S.is_field() # optional - sage.libs.pari + sage: S.is_field() True - sage: S.degree() # optional - sage.libs.pari + sage: S.degree() 3 There are conversion functions for easily going back and forth between quotients of polynomial rings over `\QQ` and number fields:: - sage: K = S.number_field(); K # optional - sage.libs.pari sage.rings.number_field + sage: K = S.number_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + 2*x - 5 - sage: K.polynomial_quotient_ring() # optional - sage.libs.pari sage.rings.number_field + sage: K.polynomial_quotient_ring() # needs sage.rings.number_field Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5 @@ -163,14 +163,14 @@ class PolynomialQuotientRingFactory(UniqueFactory): sage: R. = PolynomialRing(IntegerRing()) sage: f = x^2 + 1 - sage: R.quotient(f) # optional - sage.libs.pari + sage: R.quotient(f) Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 This shows that the issue at :trac:`5482` is solved:: sage: R. = PolynomialRing(QQ) sage: f = x^2 - 1 - sage: R.quotient_by_principal_ideal(f) # optional - sage.libs.pari + sage: R.quotient_by_principal_ideal(f) Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 """ @@ -195,19 +195,19 @@ def create_key(self, ring, polynomial, names=None): Consequently, you get two distinct objects:: - sage: S = PolynomialQuotientRing(R, x + 1); S # optional - sage.libs.pari + sage: S = PolynomialQuotientRing(R, x + 1); S Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x + 1 - sage: T = PolynomialQuotientRing(R, 2*x + 2); T # optional - sage.libs.pari + sage: T = PolynomialQuotientRing(R, 2*x + 2); T Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus 2*x + 2 - sage: S is T # optional - sage.libs.pari + sage: S is T False - sage: S == T # optional - sage.libs.pari + sage: S == T False In most applications this will not be a concern since the calling code takes care of normalizing the generators:: - sage: R.quo(x + 1) is R.quo(2*x + 2) # optional - sage.libs.pari + sage: R.quo(x + 1) is R.quo(2*x + 2) True """ @@ -236,7 +236,7 @@ def create_object(self, version, key): EXAMPLES:: sage: R. = QQ[] - sage: PolynomialQuotientRing.create_object((8, 0, 0), # optional - sage.libs.pari + sage: PolynomialQuotientRing.create_object((8, 0, 0), ....: (R, x^2 - 1, ('xbar'))) Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 @@ -292,19 +292,19 @@ class PolynomialQuotientRing_generic(QuotientRing_generic): :: sage: R. = PolynomialRing(ZZ) - sage: S = R.quo(x^2 - 4) # optional - sage.libs.pari - sage: f = S.hom([2]) # optional - sage.libs.pari - sage: f # optional - sage.libs.pari + sage: S = R.quo(x^2 - 4) + sage: f = S.hom([2]) + sage: f Ring morphism: From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 - 4 To: Integer Ring Defn: xbar |--> 2 - sage: f(x) # optional - sage.libs.pari + sage: f(x) 2 - sage: f(x^2 - 4) # optional - sage.libs.pari + sage: f(x^2 - 4) 0 - sage: f(x^2) # optional - sage.libs.pari + sage: f(x^2) 4 TESTS: @@ -320,8 +320,8 @@ class of the quotient ring and its newly created elements. Thus, in order to document that this works fine, we go into some detail:: sage: P. = QQ[] - sage: Q = P.quotient(x^2 + 2) # optional - sage.libs.pari - sage: Q.category() # optional - sage.libs.pari + sage: Q = P.quotient(x^2 + 2) + sage: Q.category() Category of commutative no zero divisors quotients of algebras over (number fields and quotient fields and metric spaces) @@ -330,24 +330,24 @@ class of the quotient ring and its newly created elements. class of the category, and store the current class of the quotient ring:: - sage: isinstance(Q.an_element(), Q.element_class) # optional - sage.libs.pari + sage: isinstance(Q.an_element(), Q.element_class) True - sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] # optional - sage.libs.pari + sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] ['cartesian_product', 'inverse', 'inverse_of_unit', 'is_idempotent', 'is_one', 'is_unit', 'lift', 'powers'] - sage: first_class = Q.__class__ # optional - sage.libs.pari + sage: first_class = Q.__class__ We try to find out whether `Q` is a field. Indeed it is, and thus its category, including its class and element class, is changed accordingly:: - sage: Q in Fields() # optional - sage.libs.pari + sage: Q in Fields() True - sage: Q.category() # optional - sage.libs.pari + sage: Q.category() Category of commutative division no zero divisors quotients of algebras over (number fields and quotient fields and metric spaces) - sage: first_class == Q.__class__ # optional - sage.libs.pari + sage: first_class == Q.__class__ False - sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] # optional - sage.libs.pari + sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] ['cartesian_product', 'euclidean_degree', 'factor', @@ -371,22 +371,22 @@ class of the category, and store the current class of the quotient new methods from the category of fields, thanks to :meth:`Element.__getattr__`:: - sage: e = Q.an_element() # optional - sage.libs.pari - sage: isinstance(e, Q.element_class) # optional - sage.libs.pari + sage: e = Q.an_element() + sage: isinstance(e, Q.element_class) False - sage: e.gcd(e + 1) # optional - sage.libs.pari + sage: e.gcd(e + 1) 1 The test suite passes. However, we have to skip the test for its elements, since `an_element` has been cached in the call above and its class does not match the new category's element class anymore:: - sage: TestSuite(Q).run(skip=['_test_elements']) # optional - sage.libs.pari + sage: TestSuite(Q).run(skip=['_test_elements']) # needs sage.rings.number_field Newly created elements are fine, though, and their test suite passes:: - sage: TestSuite(Q(x)).run() # optional - sage.libs.pari - sage: isinstance(Q(x), Q.element_class) # optional - sage.libs.pari + sage: TestSuite(Q(x)).run() + sage: isinstance(Q(x), Q.element_class) True """ Element = PolynomialQuotientRingElement @@ -396,18 +396,18 @@ def __init__(self, ring, polynomial, name=None, category=None): TESTS:: sage: R. = PolynomialRing(ZZ) - sage: S = R.quo(x^2 - 4) # optional - sage.libs.pari + sage: S = R.quo(x^2 - 4) sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic - sage: S == PolynomialQuotientRing_generic(R, x^2 - 4, 'xbar') # optional - sage.libs.pari + sage: S == PolynomialQuotientRing_generic(R, x^2 - 4, 'xbar') True Check that :trac:`26161` has been resolved:: - sage: R. = GF(2)[] # optional - sage.rings.finite_rings - sage: S = R.quo(x) # optional - sage.rings.finite_rings - sage: S in FiniteFields() # optional - sage.rings.finite_rings + sage: R. = GF(2)[] + sage: S = R.quo(x) # needs sage.rings.finite_rings + sage: S in FiniteFields() # needs sage.rings.finite_rings True - sage: type(S).mro() # optional - sage.rings.finite_rings + sage: type(S).mro() # needs sage.rings.finite_rings [, ... , @@ -453,18 +453,18 @@ def _element_constructor_(self, x): EXAMPLES:: sage: R. = PolynomialRing(QQ) - sage: S. = R.quotient(x^3 - 3*x + 1) # optional - sage.libs.pari - sage: S(x) # optional - sage.libs.pari + sage: S. = R.quotient(x^3 - 3*x + 1) + sage: S(x) alpha - sage: S(x^3) # optional - sage.libs.pari + sage: S(x^3) 3*alpha - 1 - sage: S([1,2]) # optional - sage.libs.pari + sage: S([1,2]) 2*alpha + 1 - sage: S([1,2,3,4,5]) # optional - sage.libs.pari + sage: S([1,2,3,4,5]) 18*alpha^2 + 9*alpha - 3 - sage: S(S.gen()+1) # optional - sage.libs.pari + sage: S(S.gen()+1) alpha + 1 - sage: S(S.gen()^10+1) # optional - sage.libs.pari + sage: S(S.gen()^10+1) 90*alpha^2 - 109*alpha + 28 TESTS: @@ -473,54 +473,54 @@ def _element_constructor_(self, x): This was fixed in :trac:`8800`:: sage: P. = QQ[] - sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) # optional - sage.libs.pari - sage: Q = P.quo([(x^2+1)^2]) # optional - sage.libs.pari - sage: Q1.has_coerce_map_from(Q) # optional - sage.libs.pari + sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) + sage: Q = P.quo([(x^2+1)^2]) + sage: Q1.has_coerce_map_from(Q) False - sage: Q1(Q.gen()) # optional - sage.libs.pari + sage: Q1(Q.gen()) xbar Here we test against several issues discussed in :trac:`8992`:: sage: P. = QQ[] - sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) # optional - sage.libs.pari - sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) # optional - sage.libs.pari - sage: p = Q1.gen() + Q2.gen() # optional - sage.libs.pari - sage: p # optional - sage.libs.pari + sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) + sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) + sage: p = Q1.gen() + Q2.gen() + sage: p 2*xbar - sage: p.parent() # optional - sage.libs.pari + sage: p.parent() Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1 - sage: p.parent()('xbar') # optional - sage.libs.pari + sage: p.parent()('xbar') xbar Note that the result of string conversion has the correct parent, even when the given string suggests an element of the cover ring or the base ring:: - sage: a = Q1('x'); a # optional - sage.libs.pari + sage: a = Q1('x'); a xbar - sage: a.parent() is Q1 # optional - sage.libs.pari + sage: a.parent() is Q1 True - sage: b = Q1('1'); b # optional - sage.libs.pari + sage: b = Q1('1'); b 1 - sage: b.parent() is Q1 # optional - sage.libs.pari + sage: b.parent() is Q1 True Conversion may lift an element of one quotient ring to the base ring of another quotient ring:: - sage: R. = P[] # optional - sage.libs.pari - sage: Q3 = R.quo([(y^2+1)]) # optional - sage.libs.pari - sage: Q3(Q1.gen()) # optional - sage.libs.pari + sage: R. = P[] + sage: Q3 = R.quo([(y^2+1)]) + sage: Q3(Q1.gen()) x - sage: Q3.has_coerce_map_from(Q1) # optional - sage.libs.pari + sage: Q3.has_coerce_map_from(Q1) False String conversion takes into account both the generators of the quotient ring and its base ring:: - sage: Q3('x*ybar^2') # optional - sage.libs.pari + sage: Q3('x*ybar^2') -x """ @@ -562,25 +562,25 @@ def _coerce_map_from_(self, R): TESTS:: - sage: P5. = GF(5)[] # optional - sage.rings.finite_rings - sage: Q = P5.quo([(x^2+1)^2]) # optional - sage.rings.finite_rings + sage: P5. = GF(5)[] + sage: Q = P5.quo([(x^2+1)^2]) sage: P. = ZZ[] - sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) # optional - sage.libs.pari - sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) # optional - sage.libs.pari - sage: Q.has_coerce_map_from(Q1) #indirect doctest # optional - sage.libs.pari sage.rings.finite_rings + sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) + sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) + sage: Q.has_coerce_map_from(Q1) #indirect doctest True - sage: Q1.has_coerce_map_from(Q) # optional - sage.libs.pari sage.rings.finite_rings + sage: Q1.has_coerce_map_from(Q) False - sage: Q1.has_coerce_map_from(Q2) # optional - sage.libs.pari sage.rings.finite_rings + sage: Q1.has_coerce_map_from(Q2) False The following tests against a bug fixed in :trac:`8992`:: sage: P. = QQ[] - sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) # optional - sage.libs.pari + sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) sage: R. = P[] - sage: Q2 = R.quo([(y^2 + 1)]) # optional - sage.libs.pari - sage: Q2.has_coerce_map_from(Q1) # optional - sage.libs.pari + sage: Q2 = R.quo([(y^2 + 1)]) + sage: Q2.has_coerce_map_from(Q1) False """ @@ -600,16 +600,17 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: T. = ZZ[] - sage: K. = NumberField(t^2 + 1) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient(x^2 - i) # optional - sage.rings.number_field - sage: Q8. = CyclotomicField(8) # optional - sage.rings.number_field - sage: S._is_valid_homomorphism_(Q8, [z]) # no coercion from K to Q8 # optional - sage.rings.number_field + sage: K. = NumberField(t^2 + 1) + sage: R. = K[] + sage: S. = R.quotient(x^2 - i) + sage: Q8. = CyclotomicField(8) + sage: S._is_valid_homomorphism_(Q8, [z]) # no coercion from K to Q8 False - sage: S._is_valid_homomorphism_(Q8, [z], K.hom([z^2])) # optional - sage.rings.number_field + sage: S._is_valid_homomorphism_(Q8, [z], K.hom([z^2])) True - sage: S._is_valid_homomorphism_(Q8, [1/z], K.hom([z^-2])) # optional - sage.rings.number_field + sage: S._is_valid_homomorphism_(Q8, [1/z], K.hom([z^-2])) True """ if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): @@ -659,12 +660,12 @@ def lift(self, x): EXAMPLES:: sage: P. = QQ[] - sage: Q = P.quotient(x^2 + 2) # optional - sage.libs.pari - sage: Q.lift(Q.0^3) # optional - sage.libs.pari + sage: Q = P.quotient(x^2 + 2) + sage: Q.lift(Q.0^3) -2*x - sage: Q(-2*x) # optional - sage.libs.pari + sage: Q(-2*x) -2*xbar - sage: Q.0^3 # optional - sage.libs.pari + sage: Q.0^3 -2*xbar """ @@ -680,14 +681,14 @@ def __eq__(self, other): sage: Ry. = PolynomialRing(QQ) sage: Rx == Ry False - sage: Qx = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: Qy = Ry.quotient(y^2 + 1) # optional - sage.libs.pari - sage: Qx == Qy # optional - sage.libs.pari + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) + sage: Qx == Qy False - sage: Qx == Qx # optional - sage.libs.pari + sage: Qx == Qx True - sage: Qz = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: Qz == Qx # optional - sage.libs.pari + sage: Qz = Rx.quotient(x^2 + 1) + sage: Qz == Qx True """ if not isinstance(other, PolynomialQuotientRing_generic): @@ -705,14 +706,14 @@ def __ne__(self, other): sage: Ry. = PolynomialRing(QQ) sage: Rx != Ry True - sage: Qx = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: Qy = Ry.quotient(y^2 + 1) # optional - sage.libs.pari - sage: Qx != Qy # optional - sage.libs.pari + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) + sage: Qx != Qy True - sage: Qx != Qx # optional - sage.libs.pari + sage: Qx != Qx False - sage: Qz = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: Qz != Qx # optional - sage.libs.pari + sage: Qz = Rx.quotient(x^2 + 1) + sage: Qz != Qx False """ return not (self == other) @@ -727,14 +728,14 @@ def __hash__(self): sage: Ry. = PolynomialRing(QQ) sage: hash(Rx) == hash(Ry) False - sage: Qx = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: Qy = Ry.quotient(y^2 + 1) # optional - sage.libs.pari - sage: hash(Qx) == hash(Qy) # optional - sage.libs.pari + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) + sage: hash(Qx) == hash(Qy) False - sage: hash(Qx) == hash(Qx) # optional - sage.libs.pari + sage: hash(Qx) == hash(Qx) True - sage: Qz = Rx.quotient(x^2 + 1) # optional - sage.libs.pari - sage: hash(Qz) == hash(Qx) # optional - sage.libs.pari + sage: Qz = Rx.quotient(x^2 + 1) + sage: hash(Qz) == hash(Qx) True """ return hash((self.polynomial_ring(), self.modulus())) @@ -746,8 +747,8 @@ def _singular_init_(self, S=None): TESTS:: sage: P. = QQ[] - sage: Q = P.quo([(x^2 + 1)]) # optional - sage.libs.pari - sage: singular(Q) # indirect doctest # optional - sage.libs.pari + sage: Q = P.quo([(x^2 + 1)]) + sage: singular(Q) # indirect doctest # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -756,7 +757,7 @@ def _singular_init_(self, S=None): // block 2 : ordering C // quotient ring from ideal _[1]=xbar^2+1 - sage: singular(Q.gen()) # optional - sage.libs.pari + sage: singular(Q.gen()) # needs sage.libs.singular xbar """ @@ -781,14 +782,14 @@ def construction(self): EXAMPLES:: sage: P. = ZZ[] - sage: Q = P.quo(5 + t^2) # optional - sage.libs.pari - sage: F, R = Q.construction() # optional - sage.libs.pari - sage: F(R) == Q # optional - sage.libs.pari + sage: Q = P.quo(5 + t^2) + sage: F, R = Q.construction() + sage: F(R) == Q True - sage: P. = GF(3)[] # optional - sage.rings.finite_rings - sage: Q = P.quo([2 + t^2]) # optional - sage.rings.finite_rings - sage: F, R = Q.construction() # optional - sage.rings.finite_rings - sage: F(R) == Q # optional - sage.rings.finite_rings + sage: P. = GF(3)[] + sage: Q = P.quo([2 + t^2]) + sage: F, R = Q.construction() + sage: F(R) == Q True AUTHOR: @@ -817,8 +818,8 @@ def base_ring(self): :: sage: R. = PolynomialRing(ZZ) - sage: S. = R.quo(z^3 + z^2 + z + 1) # optional - sage.libs.pari - sage: S.base_ring() # optional - sage.libs.pari + sage: S. = R.quo(z^3 + z^2 + z + 1) + sage: S.base_ring() Integer Ring Next we make a polynomial quotient ring over `S` and ask @@ -826,9 +827,9 @@ def base_ring(self): :: - sage: T. = PolynomialRing(S) # optional - sage.libs.pari - sage: W = T.quotient(t^99 + 99) # optional - sage.libs.pari - sage: W.base_ring() # optional - sage.libs.pari + sage: T. = PolynomialRing(S) + sage: W = T.quotient(t^99 + 99) + sage: W.base_ring() Univariate Quotient Polynomial Ring in beta over Integer Ring with modulus z^3 + z^2 + z + 1 """ @@ -845,22 +846,23 @@ def cardinality(self): sage: R. = ZZ[] sage: R.quo(1).cardinality() 1 - sage: R.quo(x^3 - 2).cardinality() # optional - sage.libs.pari + sage: R.quo(x^3 - 2).cardinality() +Infinity sage: R.quo(1).order() 1 - sage: R.quo(x^3 - 2).order() # optional - sage.libs.pari + sage: R.quo(x^3 - 2).order() +Infinity :: - sage: R. = GF(9, 'a')[] # optional - sage.rings.finite_rings - sage: R.quo(2*x^3 + x + 1).cardinality() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(9, 'a')[] + sage: R.quo(2*x^3 + x + 1).cardinality() 729 - sage: GF(9, 'a').extension(2*x^3 + x + 1).cardinality() # optional - sage.rings.finite_rings + sage: GF(9, 'a').extension(2*x^3 + x + 1).cardinality() 729 - sage: R.quo(2).cardinality() # optional - sage.rings.finite_rings + sage: R.quo(2).cardinality() 1 TESTS:: @@ -894,21 +896,21 @@ def is_finite(self): sage: R. = ZZ[] sage: R.quo(1).is_finite() True - sage: R.quo(x^3 - 2).is_finite() # optional - sage.libs.pari + sage: R.quo(x^3 - 2).is_finite() False :: - sage: R. = GF(9, 'a')[] # optional - sage.rings.finite_rings - sage: R.quo(2*x^3 + x + 1).is_finite() # optional - sage.rings.finite_rings + sage: R. = GF(9, 'a')[] # needs sage.rings.finite_rings + sage: R.quo(2*x^3 + x + 1).is_finite() # needs sage.rings.finite_rings True - sage: R.quo(2).is_finite() # optional - sage.rings.finite_rings + sage: R.quo(2).is_finite() # needs sage.rings.finite_rings True :: - sage: P. = GF(2)[] # optional - sage.rings.finite_rings - sage: P.quotient(v^2 - v).is_finite() # optional - sage.rings.finite_rings + sage: P. = GF(2)[] + sage: P.quotient(v^2 - v).is_finite() True """ f = self.modulus() @@ -924,9 +926,9 @@ def __iter__(self): r""" EXAMPLES:: - sage: R. = GF(3)[] # optional - sage.rings.finite_rings - sage: Q = R.quo(x^3 - x^2 - x - 1) # optional - sage.rings.finite_rings - sage: list(Q) # optional - sage.rings.finite_rings + sage: R. = GF(3)[] + sage: Q = R.quo(x^3 - x^2 - x - 1) + sage: list(Q) [0, 1, 2, @@ -937,7 +939,7 @@ def __iter__(self): ... 2*xbar^2 + 2*xbar + 1, 2*xbar^2 + 2*xbar + 2] - sage: len(_) == Q.cardinality() == 27 # optional - sage.rings.finite_rings + sage: len(_) == Q.cardinality() == 27 True """ if not self.is_finite(): @@ -958,12 +960,12 @@ def characteristic(self): EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: S. = R.quo(z - 19) # optional - sage.libs.pari - sage: S.characteristic() # optional - sage.libs.pari + sage: S. = R.quo(z - 19) + sage: S.characteristic() 0 - sage: R. = PolynomialRing(GF(9, 'a')) # optional - sage.rings.finite_rings - sage: S = R.quotient(x^3 + 1) # optional - sage.rings.finite_rings - sage: S.characteristic() # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(9, 'a')) # needs sage.rings.finite_rings + sage: S = R.quotient(x^3 + 1) # needs sage.rings.finite_rings + sage: S.characteristic() # needs sage.rings.finite_rings 3 """ return self.base_ring().characteristic() @@ -975,9 +977,9 @@ def degree(self): EXAMPLES:: - sage: R. = PolynomialRing(GF(3)) # optional - sage.rings.finite_rings - sage: S = R.quotient(x^2005 + 1) # optional - sage.rings.finite_rings - sage: S.degree() # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(3)) + sage: S = R.quotient(x^2005 + 1) + sage: S.degree() 2005 """ return self.modulus().degree() @@ -991,11 +993,11 @@ def discriminant(self, v=None): EXAMPLES:: sage: R. = PolynomialRing(QQ) - sage: S = R.quotient(x^3 + x^2 + x + 1) # optional - sage.libs.pari - sage: S.discriminant() # optional - sage.libs.pari + sage: S = R.quotient(x^3 + x^2 + x + 1) + sage: S.discriminant() -16 - sage: S = R.quotient((x + 1) * (x + 1)) # optional - sage.libs.pari - sage: S.discriminant() # optional - sage.libs.pari + sage: S = R.quotient((x + 1) * (x + 1)) + sage: S.discriminant() 0 The discriminant of the quotient polynomial ring need not equal the @@ -1003,10 +1005,10 @@ def discriminant(self, v=None): discriminant of a number field is by definition the discriminant of the ring of integers of the number field:: - sage: S = R.quotient(x^2 - 8) # optional - sage.libs.pari - sage: S.number_field().discriminant() # optional - sage.libs.pari + sage: S = R.quotient(x^2 - 8) + sage: S.number_field().discriminant() # needs sage.rings.number_field 8 - sage: S.discriminant() # optional - sage.libs.pari + sage: S.discriminant() 32 """ return self.modulus().discriminant() @@ -1019,8 +1021,8 @@ class of the image of the generator of the polynomial ring. EXAMPLES:: sage: R. = PolynomialRing(QQ) - sage: S = R.quotient(x^2 - 8, 'gamma') # optional - sage.libs.pari - sage: S.gen() # optional - sage.libs.pari + sage: S = R.quotient(x^2 - 8, 'gamma') + sage: S.gen() gamma """ if n != 0: @@ -1038,28 +1040,29 @@ def is_field(self, proof=True): EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: S = R.quo(z^2 - 2) # optional - sage.libs.pari - sage: S.is_field() # optional - sage.libs.pari + sage: S = R.quo(z^2 - 2) + sage: S.is_field() False sage: R. = PolynomialRing(QQ) - sage: S = R.quotient(x^2 - 2) # optional - sage.libs.pari - sage: S.is_field() # optional - sage.libs.pari + sage: S = R.quotient(x^2 - 2) + sage: S.is_field() True If proof is ``True``, requires the ``is_irreducible`` method of the modulus to be implemented:: - sage: R1. = Qp(2)[] # optional - sage.rings.padics - sage: F1 = R1.quotient_ring(x^2 + x + 1) # optional - sage.rings.padics - sage: R2. = F1[] # optional - sage.rings.padics - sage: F2 = R2.quotient_ring(x^2 + x + 1) # optional - sage.rings.padics - sage: F2.is_field() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: R1. = Qp(2)[] + sage: F1 = R1.quotient_ring(x^2 + x + 1) + sage: R2. = F1[] + sage: F2 = R2.quotient_ring(x^2 + x + 1) + sage: F2.is_field() Traceback (most recent call last): ... NotImplementedError: cannot rewrite Univariate Quotient Polynomial Ring in xbar over 2-adic Field with capped relative precision 20 with modulus (1 + O(2^20))*x^2 + (1 + O(2^20))*x + 1 + O(2^20) as an isomorphic ring - sage: F2.is_field(proof = False) # optional - sage.rings.padics + sage: F2.is_field(proof = False) False """ @@ -1084,21 +1087,21 @@ def is_integral_domain(self, proof=True): EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: S = R.quotient(z^2 - z) # optional - sage.libs.pari - sage: S.is_integral_domain() # optional - sage.libs.pari + sage: S = R.quotient(z^2 - z) + sage: S.is_integral_domain() False - sage: T = R.quotient(z^2 + 1) # optional - sage.libs.pari - sage: T.is_integral_domain() # optional - sage.libs.pari + sage: T = R.quotient(z^2 + 1) + sage: T.is_integral_domain() True sage: U = R.quotient(-1) sage: U.is_integral_domain() False sage: R2. = PolynomialRing(R) - sage: S2 = R2.quotient(z^2 - y^3) # optional - sage.libs.pari - sage: S2.is_integral_domain() # optional - sage.libs.pari + sage: S2 = R2.quotient(z^2 - y^3) + sage: S2.is_integral_domain() # needs sage.libs.singular True - sage: S3 = R2.quotient(z^2 - 2*y*z + y^2) # optional - sage.libs.pari - sage: S3.is_integral_domain() # optional - sage.libs.pari + sage: S3 = R2.quotient(z^2 - 2*y*z + y^2) + sage: S3.is_integral_domain() # needs sage.libs.singular False sage: R. = PolynomialRing(ZZ.quotient(4)) @@ -1112,15 +1115,16 @@ def is_integral_domain(self, proof=True): domain, even though the base ring is integral and the modulus is irreducible:: + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: B = ZZ.extension(x^2 - 5, 'a') # optional - sage.rings.number_field - sage: R. = PolynomialRing(B) # optional - sage.rings.number_field - sage: S = R.quotient(y^2 - y - 1) # optional - sage.libs.pari sage.rings.number_field - sage: S.is_integral_domain() # optional - sage.libs.pari sage.rings.number_field + sage: B = ZZ.extension(x^2 - 5, 'a') + sage: R. = PolynomialRing(B) + sage: S = R.quotient(y^2 - y - 1) + sage: S.is_integral_domain() Traceback (most recent call last): ... NotImplementedError - sage: S.is_integral_domain(proof=False) # optional - sage.libs.pari sage.rings.number_field + sage: S.is_integral_domain(proof=False) False The reason that the modulus y^2 - y - 1 is not prime is that it @@ -1169,11 +1173,11 @@ def krull_dimension(self): EXAMPLES:: sage: x = polygen(ZZ, 'x') - sage: R = PolynomialRing(ZZ, 'x').quotient(x**6 - 1) # optional - sage.libs.pari - sage: R.krull_dimension() # optional - sage.libs.pari + sage: R = PolynomialRing(ZZ, 'x').quotient(x**6 - 1) + sage: R.krull_dimension() 1 - sage: R = PolynomialRing(ZZ, 'x').quotient(1) # optional - sage.libs.pari - sage: R.krull_dimension() # optional - sage.libs.pari + sage: R = PolynomialRing(ZZ, 'x').quotient(1) + sage: R.krull_dimension() -1 """ if self.is_zero(): @@ -1186,9 +1190,9 @@ def modulus(self): EXAMPLES:: - sage: R. = PolynomialRing(GF(3)) # optional - sage.rings.finite_rings - sage: S = R.quotient(x^2 - 2) # optional - sage.rings.finite_rings - sage: S.modulus() # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(3)) + sage: S = R.quotient(x^2 - 2) + sage: S.modulus() x^2 + 1 """ return self.__polynomial @@ -1204,7 +1208,8 @@ def ngens(self): sage: S. = PolynomialRing(R) sage: T. = S.quotient(y + x) sage: T - Univariate Quotient Polynomial Ring in z over Univariate Polynomial Ring in x over Rational Field with modulus y + x + Univariate Quotient Polynomial Ring in z over + Univariate Polynomial Ring in x over Rational Field with modulus y + x sage: T.ngens() 1 """ @@ -1217,12 +1222,13 @@ def number_field(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: S. = R.quotient(x^29 - 17*x - 1) # optional - sage.libs.pari - sage: K = S.number_field(); K # optional - sage.libs.pari sage.rings.number_field + sage: S. = R.quotient(x^29 - 17*x - 1) + sage: K = S.number_field(); K Number Field in alpha with defining polynomial x^29 - 17*x - 1 - sage: alpha = K.gen() # optional - sage.libs.pari sage.rings.number_field - sage: alpha^29 # optional - sage.libs.pari sage.rings.number_field + sage: alpha = K.gen() + sage: alpha^29 17*alpha + 1 """ if self.characteristic() != 0: @@ -1240,8 +1246,8 @@ def polynomial_ring(self): EXAMPLES:: sage: R. = PolynomialRing(QQ) - sage: S = R.quotient(x^2 - 2) # optional - sage.libs.pari - sage: S.polynomial_ring() # optional - sage.libs.pari + sage: S = R.quotient(x^2 - 2) + sage: S.polynomial_ring() Univariate Polynomial Ring in x over Rational Field """ return self.__ring @@ -1264,10 +1270,11 @@ def random_element(self, *args, **kwds): EXAMPLES:: - sage: F1. = GF(2^7) # optional - sage.rings.finite_rings - sage: P1. = F1[] # optional - sage.rings.finite_rings - sage: F2 = F1.extension(x^2 + x + 1, 'u') # optional - sage.rings.finite_rings - sage: F2.random_element().parent() is F2 # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F1. = GF(2^7) + sage: P1. = F1[] + sage: F2 = F1.extension(x^2 + x + 1, 'u') + sage: F2.random_element().parent() is F2 True """ return self(self.polynomial_ring().random_element( @@ -1283,22 +1290,23 @@ def _S_decomposition(self, S): EXAMPLES:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) # optional - sage.rings.number_field - sage: fields, isos, iso_classes = S._S_decomposition(tuple(K.primes_above(3))) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: fields, isos, iso_classes = S._S_decomposition(tuple(K.primes_above(3))) Representatives of the number fields up to isomorphism that occur in the decomposition:: - sage: fields # optional - sage.rings.number_field + sage: fields # needs sage.rings.number_field [Number Field in x0 with defining polynomial x^2 + 23 over its base field, Number Field in x1 with defining polynomial x^2 + 31 over its base field] In this case, the isomorphisms of these representatives to the components are the identity maps:: - sage: isos # optional - sage.rings.number_field + sage: isos # needs sage.rings.number_field [(Ring endomorphism of Number Field in y0 with defining polynomial x^4 + 56*x^2 + 324 Defn: y0 |--> y0, 0), @@ -1309,9 +1317,9 @@ def _S_decomposition(self, S): There are four primes above 3 in the first component and two in the second component:: - sage: len(iso_classes[0][1]) # optional - sage.rings.number_field + sage: len(iso_classes[0][1]) # needs sage.rings.number_field 4 - sage: len(iso_classes[1][1]) # optional - sage.rings.number_field + sage: len(iso_classes[1][1]) # needs sage.rings.number_field 2 """ from sage.rings.number_field.number_field_base import NumberField @@ -1390,43 +1398,46 @@ def S_class_group(self, S, proof=True): A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its base:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient(x) # optional - sage.rings.number_field - sage: S.S_class_group([]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient(x) + sage: S.S_class_group([]) [((2, -a + 1), 2)] When we include the prime `(2, -a+1)`, the `S`-class group becomes trivial:: - sage: S.S_class_group([K.ideal(2, -a+1)]) # optional - sage.rings.number_field + sage: S.S_class_group([K.ideal(2, -a+1)]) # needs sage.rings.number_field [] Here is an example where the base and the extension both contribute to the class group:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: K.class_group() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: K.class_group() Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient(x^2 + 23) # optional - sage.rings.number_field - sage: S.S_class_group([]) # optional - sage.rings.number_field + sage: R. = K[] + sage: S. = R.quotient(x^2 + 23) + sage: S.S_class_group([]) [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)] - sage: S.S_class_group([K.ideal(3, a-1)]) # optional - sage.rings.number_field + sage: S.S_class_group([K.ideal(3, a-1)]) [] - sage: S.S_class_group([K.ideal(2, a+1)]) # optional - sage.rings.number_field + sage: S.S_class_group([K.ideal(2, a+1)]) [] - sage: S.S_class_group([K.ideal(a)]) # optional - sage.rings.number_field + sage: S.S_class_group([K.ideal(a)]) [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)] Now we take an example over a nontrivial base with two factors, each contributing to the class group:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) # optional - sage.rings.number_field - sage: S.S_class_group([]) # representation varies, not tested # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: S.S_class_group([]) # not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1447,7 +1458,7 @@ def S_class_group(self, S, proof=True): `x^2 + 31` from 12 to 2, i.e. we lose a generator of order 6 (this was fixed in :trac:`14489`):: - sage: S.S_class_group([K.ideal(a)]) # representation varies, not tested # optional - sage.rings.number_field + sage: S.S_class_group([K.ideal(a)]) # representation varies # not tested, needs sage.rings.number_field [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8), @@ -1459,21 +1470,23 @@ def S_class_group(self, S, proof=True): Note that all the returned values live where we expect them to:: - sage: CG = S.S_class_group([]) # optional - sage.rings.number_field - sage: type(CG[0][0][1]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: CG = S.S_class_group([]) + sage: type(CG[0][0][1]) - sage: type(CG[0][1]) # optional - sage.rings.number_field + sage: type(CG[0][1]) TESTS: We verify the above test, where the representation depends on the PARI version:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) # optional - sage.rings.number_field - sage: C = S.S_class_group([]) # optional - sage.rings.number_field - sage: C[:2] # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: C = S.S_class_group([]) + sage: C[:2] [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1484,21 +1497,21 @@ def S_class_group(self, S, proof=True): -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16, 1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8), 6)] - sage: C[2][1] # optional - sage.rings.number_field + sage: C[2][1] 2 - sage: gens = C[2][0] # optional - sage.rings.number_field - sage: expected_gens = ( # optional - sage.rings.number_field + sage: gens = C[2][0] + sage: expected_gens = ( ....: -5/4*xbar^2 - 115/4, ....: 1/4*a*xbar^2 + 23/4*a, ....: -1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16, ....: 1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a) - sage: gens[0] == expected_gens[0] # optional - sage.rings.number_field + sage: gens[0] == expected_gens[0] True - sage: gens[1] in (expected_gens[1], expected_gens[1]/2 + expected_gens[0]/2) # optional - sage.rings.number_field + sage: gens[1] in (expected_gens[1], expected_gens[1]/2 + expected_gens[0]/2) True - sage: gens[2] in (expected_gens[2], expected_gens[2] + expected_gens[0]/2) # optional - sage.rings.number_field + sage: gens[2] in (expected_gens[2], expected_gens[2] + expected_gens[0]/2) True - sage: gens[3] in (expected_gens[3], expected_gens[3] + expected_gens[0]/2) # optional - sage.rings.number_field + sage: gens[3] in (expected_gens[3], expected_gens[3] + expected_gens[0]/2) True """ fields, isos, iso_classes = self._S_decomposition(tuple(S)) @@ -1553,49 +1566,53 @@ def class_group(self, proof=True): EXAMPLES:: - sage: K. = QuadraticField(-3) # optional - sage.rings.number_field - sage: K.class_group() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-3) + sage: K.class_group() Class group of order 1 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I sage: x = polygen(QQ, 'x') - sage: K. = QQ['x'].quotient(x^2 + 3) # optional - sage.libs.pari sage.rings.number_field - sage: K.class_group() # optional - sage.libs.pari sage.rings.number_field + sage: K. = QQ['x'].quotient(x^2 + 3) + sage: K.class_group() [] A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its base:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient(x) # optional - sage.rings.number_field - sage: S.class_group() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient(x) + sage: S.class_group() [((2, -a + 1), 2)] The same algebra constructed in a different way:: sage: x = polygen(ZZ, 'x') - sage: K. = QQ['x'].quotient(x^2 + 5) # optional - sage.libs.pari - sage: K.class_group(()) # optional - sage.libs.pari + sage: K. = QQ['x'].quotient(x^2 + 5) + sage: K.class_group(()) # needs sage.rings.number_field [((2, a + 1), 2)] Here is an example where the base and the extension both contribute to the class group:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: K.class_group() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: K.class_group() Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient(x^2 + 23) # optional - sage.rings.number_field - sage: S.class_group() # optional - sage.rings.number_field + sage: R. = K[] + sage: S. = R.quotient(x^2 + 23) + sage: S.class_group() [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)] Here is an example of a product of number fields, both of which contribute to the class group:: - sage: R. = QQ[] # optional - sage.rings.number_field - sage: S. = R.quotient((x^2 + 23) * (x^2 + 47)) # optional - sage.rings.number_field - sage: S.class_group() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R. = QQ[] + sage: S. = R.quotient((x^2 + 23) * (x^2 + 47)) + sage: S.class_group() [((1/12*xbar^2 + 47/12, 1/48*xbar^3 - 1/48*xbar^2 + 47/48*xbar - 47/48), 3), @@ -1606,10 +1623,11 @@ def class_group(self, proof=True): Now we take an example over a nontrivial base with two factors, each contributing to the class group:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) # optional - sage.rings.number_field - sage: S.class_group() # representation varies, not tested # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: S.class_group() # not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1628,10 +1646,11 @@ def class_group(self, proof=True): Note that all the returned values live where we expect them to:: - sage: CG = S.class_group() # optional - sage.rings.number_field - sage: type(CG[0][0][1]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: CG = S.class_group() + sage: type(CG[0][0][1]) - sage: type(CG[0][1]) # optional - sage.rings.number_field + sage: type(CG[0][1]) """ @@ -1657,40 +1676,43 @@ def S_units(self, S, proof=True): EXAMPLES:: - sage: K. = QuadraticField(-3) # optional - sage.rings.number_field - sage: K.unit_group() # optional - sage.rings.number_field + sage: K. = QuadraticField(-3) # needs sage.rings.number_field + sage: K.unit_group() # needs sage.rings.number_field Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = QQ['x'].quotient(x^2 + 3) # optional - sage.libs.pari - sage: u, o = K.S_units([])[0]; o # optional - sage.libs.pari + sage: K. = QQ['x'].quotient(x^2 + 3) + sage: u, o = K.S_units([])[0]; o 6 - sage: 2*u - 1 in {a, -a} # optional - sage.libs.pari + sage: 2*u - 1 in {a, -a} True - sage: u^6 # optional - sage.libs.pari + sage: u^6 1 - sage: u^3 # optional - sage.libs.pari + sage: u^3 -1 - sage: 2*u^2 + 1 in {a, -a} # optional - sage.libs.pari + sage: 2*u^2 + 1 in {a, -a} True :: - sage: K. = QuadraticField(-3) # optional - sage.rings.number_field - sage: y = polygen(K) # optional - sage.rings.number_field - sage: L. = K['y'].quotient(y^3 + 5); L # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-3) + sage: y = polygen(K) + sage: L. = K['y'].quotient(y^3 + 5); L Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I with modulus y^3 + 5 - sage: [u for u, o in L.S_units([]) if o is Infinity] # optional - sage.rings.number_field + sage: [u for u, o in L.S_units([]) if o is Infinity] [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] - sage: [u for u, o in L.S_units([K.ideal(1/2*a - 3/2)]) # optional - sage.rings.number_field + sage: [u for u, o in L.S_units([K.ideal(1/2*a - 3/2)]) ....: if o is Infinity] [(-1/6*a - 1/2)*b^2 + (1/3*a - 1)*b + 4/3*a, (-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] - sage: [u for u, o in L.S_units([K.ideal(2)]) if o is Infinity] # optional - sage.rings.number_field + sage: [u for u, o in L.S_units([K.ideal(2)]) if o is Infinity] [(1/2*a - 1/2)*b^2 + (a + 1)*b + 3, (1/6*a + 1/2)*b^2 + (-1/3*a + 1)*b - 5/6*a + 1/2, (1/6*a + 1/2)*b^2 + (-1/3*a + 1)*b - 5/6*a - 1/2, @@ -1699,12 +1721,13 @@ def S_units(self, S, proof=True): Note that all the returned values live where we expect them to:: - sage: U = L.S_units([]) # optional - sage.rings.number_field - sage: type(U[0][0]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: U = L.S_units([]) + sage: type(U[0][0]) - sage: type(U[0][1]) # optional - sage.rings.number_field + sage: type(U[0][1]) - sage: type(U[1][1]) # optional - sage.rings.number_field + sage: type(U[1][1]) """ @@ -1748,56 +1771,60 @@ def units(self, proof=True): EXAMPLES:: - sage: K. = QuadraticField(-3) # optional - sage.rings.number_field - sage: K.unit_group() # optional - sage.rings.number_field + sage: K. = QuadraticField(-3) # needs sage.rings.number_field + sage: K.unit_group() # needs sage.rings.number_field Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + + sage: # needs sage.rings.number_field sage: x = polygen(ZZ, 'x') - sage: K. = QQ['x'].quotient(x^2 + 3) # optional - sage.libs.pari - sage: u = K.units()[0][0] # optional - sage.libs.pari - sage: 2*u - 1 in {a, -a} # optional - sage.libs.pari + sage: K. = QQ['x'].quotient(x^2 + 3) + sage: u = K.units()[0][0] + sage: 2*u - 1 in {a, -a} True - sage: u^6 # optional - sage.libs.pari + sage: u^6 1 - sage: u^3 # optional - sage.libs.pari + sage: u^3 -1 - sage: 2*u^2 + 1 in {a, -a} # optional - sage.libs.pari + sage: 2*u^2 + 1 in {a, -a} True sage: x = polygen(ZZ, 'x') - sage: K. = QQ['x'].quotient(x^2 + 5) # optional - sage.libs.pari - sage: K.units(()) # optional - sage.libs.pari + sage: K. = QQ['x'].quotient(x^2 + 5) + sage: K.units(()) [(-1, 2)] :: - sage: K. = QuadraticField(-3) # optional - sage.rings.number_field - sage: y = polygen(K) # optional - sage.rings.number_field - sage: L. = K['y'].quotient(y^3 + 5); L # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-3) + sage: y = polygen(K) + sage: L. = K['y'].quotient(y^3 + 5); L Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I with modulus y^3 + 5 - sage: [u for u, o in L.units() if o is Infinity] # optional - sage.rings.number_field + sage: [u for u, o in L.units() if o is Infinity] [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] - sage: L. = K.extension(y^3 + 5) # optional - sage.rings.number_field - sage: L.unit_group() # optional - sage.rings.number_field + sage: L. = K.extension(y^3 + 5) + sage: L.unit_group() Unit group with structure C6 x Z x Z of Number Field in b with defining polynomial x^3 + 5 over its base field - sage: L.unit_group().gens() # abstract generators # optional - sage.rings.number_field + sage: L.unit_group().gens() # abstract generators (u0, u1, u2) - sage: L.unit_group().gens_values()[1:] # optional - sage.rings.number_field + sage: L.unit_group().gens_values()[1:] [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] Note that all the returned values live where we expect them to:: - sage: L. = K['y'].quotient(y^3 + 5) # optional - sage.libs.pari - sage: U = L.units() # optional - sage.libs.pari - sage: type(U[0][0]) # optional - sage.libs.pari + sage: # needs sage.rings.number_field + sage: L. = K['y'].quotient(y^3 + 5) + sage: U = L.units() + sage: type(U[0][0]) - sage: type(U[0][1]) # optional - sage.libs.pari + sage: type(U[0][1]) - sage: type(U[1][1]) # optional - sage.libs.pari + sage: type(U[1][1]) """ @@ -1826,22 +1853,23 @@ def selmer_generators(self, S, m, proof=True): EXAMPLES:: - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: R. = K[] # optional - sage.rings.number_field - sage: D. = R.quotient(x) # optional - sage.rings.number_field - sage: D.selmer_generators((), 2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: D. = R.quotient(x) + sage: D.selmer_generators((), 2) [-1, 2] - sage: D.selmer_generators([K.ideal(2, -a + 1)], 2) # optional - sage.rings.number_field + sage: D.selmer_generators([K.ideal(2, -a + 1)], 2) [2, -1] - sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 2) # optional - sage.rings.number_field + sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 2) [2, a + 1, -1] - sage: D.selmer_generators((K.ideal(2, -a + 1), K.ideal(3, a + 1)), 4) # optional - sage.rings.number_field + sage: D.selmer_generators((K.ideal(2, -a + 1), K.ideal(3, a + 1)), 4) [2, a + 1, -1] - sage: D.selmer_generators([K.ideal(2, -a + 1)], 3) # optional - sage.rings.number_field + sage: D.selmer_generators([K.ideal(2, -a + 1)], 3) [2] - sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 3) # optional - sage.rings.number_field + sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 3) [2, a + 1] - sage: D.selmer_generators([K.ideal(2, -a + 1), # optional - sage.rings.number_field + sage: D.selmer_generators([K.ideal(2, -a + 1), ....: K.ideal(3, a + 1), ....: K.ideal(a)], 3) [2, a + 1, -a] @@ -1878,13 +1906,14 @@ def _factor_multivariate_polynomial(self, f, proof=True): TESTS:: - sage: k. = GF(4) # optional - sage.rings.finite_rings - sage: R. = k[] # optional - sage.rings.finite_rings - sage: l. = k.extension(b^2 + b + a) # optional - sage.rings.finite_rings - sage: K. = FunctionField(l) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: F = t * x # optional - sage.rings.finite_rings - sage: F.factor(proof=False) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(4) + sage: R. = k[] + sage: l. = k.extension(b^2 + b + a) + sage: K. = FunctionField(l) + sage: R. = K[] + sage: F = t * x + sage: F.factor(proof=False) (x) * t """ @@ -1905,17 +1934,18 @@ def _factor_univariate_polynomial(self, f): TESTS:: - sage: K = GF(2) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: L. = K.extension(x^2 + x + 1) # optional - sage.rings.finite_rings - sage: R. = L[] # optional - sage.rings.finite_rings - sage: M. = L.extension(y^2 + y + x) # optional - sage.rings.finite_rings - sage: R. = M[] # optional - sage.rings.finite_rings - sage: R(y).factor() # indirect doctest # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K = GF(2) + sage: R. = K[] + sage: L. = K.extension(x^2 + x + 1) + sage: R. = L[] + sage: M. = L.extension(y^2 + y + x) + sage: R. = M[] + sage: R(y).factor() # indirect doctest y - sage: (T^2 + T + x).factor() # indirect doctest # optional - sage.rings.finite_rings + sage: (T^2 + T + x).factor() # indirect doctest (T + y) * (T + y + 1) - sage: (y*T^2 + y*T + y*x).factor() # indirect doctest # optional - sage.rings.finite_rings + sage: (y*T^2 + y*T + y*x).factor() # indirect doctest (y) * (T + y) * (T + y + 1) """ @@ -1956,36 +1986,37 @@ def _isomorphic_ring(self): EXAMPLES:: - sage: K. = GF(4) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: L. = K.extension(b^2 + b + a); L # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(4) + sage: R. = K[] + sage: L. = K.extension(b^2 + b + a); L Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a - sage: from_M, to_M, M = L._isomorphic_ring(); M # optional - sage.rings.finite_rings + sage: from_M, to_M, M = L._isomorphic_ring(); M Finite Field in z4 of size 2^4 - sage: R. = L[] # optional - sage.rings.finite_rings - sage: M. = L.extension(c^2 + b*c + b); M # optional - sage.rings.finite_rings + sage: R. = L[] # needs sage.rings.finite_rings + sage: M. = L.extension(c^2 + b*c + b); M # needs sage.rings.finite_rings Univariate Quotient Polynomial Ring in c over Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a with modulus c^2 + b*c + b - sage: from_N, to_N, N = M._isomorphic_ring(); N # optional - sage.rings.finite_rings + sage: from_N, to_N, N = M._isomorphic_ring(); N # needs sage.rings.finite_rings Finite Field in z8 of size 2^8 sage: R. = QQ[] - sage: K = R.quo(x^2 + 1) # optional - sage.libs.pari - sage: from_L, to_L, L = K._isomorphic_ring() # optional - sage.libs.pari sage.rings.number_field - sage: L # optional - sage.libs.pari sage.rings.number_field + sage: K = R.quo(x^2 + 1) + sage: from_L, to_L, L = K._isomorphic_ring() # needs sage.rings.number_field + sage: L # needs sage.rings.number_field Number Field in xbar with defining polynomial x^2 + 1 TESTS: Verify that this works for trivial extensions:: - sage: K. = GF(4) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: from_L, to_L, L = R.quo(b)._isomorphic_ring(); L # optional - sage.rings.finite_rings + sage: K. = GF(4) # needs sage.rings.finite_rings + sage: R. = K[] # needs sage.rings.finite_rings + sage: from_L, to_L, L = R.quo(b)._isomorphic_ring(); L # needs sage.rings.finite_rings Finite Field in a of size 2^2 """ @@ -2102,13 +2133,14 @@ def _test_isomorphic_ring(self, **options): TESTS:: - sage: K. = GF(4) # optional - sage.rings.finite_rings - sage: R. = K[] # optional - sage.rings.finite_rings - sage: L. = K.extension(b^2 + b + a) # optional - sage.rings.finite_rings - sage: L._test_isomorphic_ring() # optional - sage.rings.finite_rings - sage: R. = L[] # optional - sage.rings.finite_rings - sage: M. = L.extension(c^2 + b*c + b) # optional - sage.rings.finite_rings - sage: M._test_isomorphic_ring() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(4) + sage: R. = K[] + sage: L. = K.extension(b^2 + b + a) + sage: L._test_isomorphic_ring() + sage: R. = L[] + sage: M. = L.extension(c^2 + b*c + b) + sage: M._test_isomorphic_ring() """ tester = self._tester(**options) @@ -2146,7 +2178,7 @@ class PolynomialQuotientRing_coercion(DefaultConvertMap_unique): sage: R. = ZZ[] sage: S. = QQ[] - sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)); f # optional - sage.libs.pari + sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)); f Coercion map: From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 @@ -2156,17 +2188,17 @@ class PolynomialQuotientRing_coercion(DefaultConvertMap_unique): TESTS:: sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_coercion - sage: isinstance(f, PolynomialQuotientRing_coercion) # optional - sage.libs.pari + sage: isinstance(f, PolynomialQuotientRing_coercion) True - sage: TestSuite(f).run(skip=['_test_pickling']) # optional - sage.libs.pari + sage: TestSuite(f).run(skip=['_test_pickling']) Pickling works:: - sage: g = loads(dumps(f)); g # optional - sage.libs.pari + sage: g = loads(dumps(f)); g Coercion map: From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 To: Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1 - sage: f == g # optional - sage.libs.pari + sage: f == g True """ @@ -2182,8 +2214,8 @@ def is_injective(self): sage: R. = ZZ[] sage: S. = QQ[] - sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)) # optional - sage.libs.pari - sage: f.is_injective() # optional - sage.libs.pari + sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)) + sage: f.is_injective() True """ @@ -2206,18 +2238,19 @@ def is_surjective(self): domain:: sage: R. = ZZ[] - sage: f = R.quo(x).coerce_map_from(R.quo(x^2)) # optional - sage.libs.pari - sage: f.is_surjective() # optional - sage.libs.pari + sage: f = R.quo(x).coerce_map_from(R.quo(x^2)) + sage: f.is_surjective() True If the modulus of the domain and the codomain is the same, then the map is surjective iff the underlying map on the constants is:: - sage: A. = ZqCA(9) # optional - sage.rings.padics - sage: R. = A[] # optional - sage.rings.padics - sage: S. = A.fraction_field()[] # optional - sage.rings.padics - sage: f = S.quo(x^2 + 2).coerce_map_from(R.quo(x^2 + 2)) # optional - sage.rings.padics - sage: f.is_surjective() # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: A. = ZqCA(9) + sage: R. = A[] + sage: S. = A.fraction_field()[] + sage: f = S.quo(x^2 + 2).coerce_map_from(R.quo(x^2 + 2)) + sage: f.is_surjective() False """ @@ -2236,15 +2269,15 @@ def _richcmp_(self, other, op): sage: R. = ZZ[] sage: S. = ZZ[] - sage: f = S.quo(x).coerce_map_from(R.quo(x^2)) # optional - sage.libs.pari - sage: g = S.quo(x).coerce_map_from(R.quo(x^3)) # optional - sage.libs.pari - sage: f == g # optional - sage.libs.pari + sage: f = S.quo(x).coerce_map_from(R.quo(x^2)) + sage: g = S.quo(x).coerce_map_from(R.quo(x^3)) + sage: f == g False - sage: f == f # optional - sage.libs.pari + sage: f == f True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.parent(), other.parent(), op) @@ -2254,13 +2287,13 @@ class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, IntegralDoma EXAMPLES:: sage: R. = PolynomialRing(ZZ) - sage: S. = R.quotient(x^2 + 1) # optional - sage.libs.pari - sage: S # optional - sage.libs.pari + sage: S. = R.quotient(x^2 + 1) + sage: S Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 - sage: loads(S.dumps()) == S # optional - sage.libs.pari + sage: loads(S.dumps()) == S True - sage: loads(xbar.dumps()) == xbar # optional - sage.libs.pari + sage: loads(xbar.dumps()) == xbar True """ def __init__(self, ring, polynomial, name=None, category=None): @@ -2270,21 +2303,21 @@ def __init__(self, ring, polynomial, name=None, category=None): TESTS:: sage: R. = PolynomialRing(ZZ) - sage: S. = R.quotient(x^2 + 1) # optional - sage.libs.pari - sage: TestSuite(S).run() # optional - sage.libs.pari + sage: S. = R.quotient(x^2 + 1) + sage: TestSuite(S).run() Check that :trac:`17450` is fixed:: - sage: S in IntegralDomains() # optional - sage.libs.pari + sage: S in IntegralDomains() True Check that :trac:`29017` is fixed:: sage: R. = ZZ[] - sage: Q = R.quo(x - 1) # optional - sage.libs.pari - sage: H = R.Hom(Q) # optional - sage.libs.pari - sage: h = R.hom(Q) # optional - sage.libs.pari - sage: h.parent() is H # optional - sage.libs.pari + sage: Q = R.quo(x - 1) + sage: H = R.Hom(Q) + sage: h = R.hom(Q) + sage: h.parent() is H True """ category = CommutativeAlgebras(ring.base_ring().category()).Quotients().NoZeroDivisors().or_subcategory(category) @@ -2308,22 +2341,23 @@ def field_extension(self, names): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(Rationals()) - sage: S. = R.quotient(x^3 - 2) # optional - sage.libs.pari - sage: F., f, g = S.field_extension() # optional - sage.libs.pari sage.rings.number_field - sage: F # optional - sage.libs.pari sage.rings.number_field + sage: S. = R.quotient(x^3 - 2) + sage: F., f, g = S.field_extension() + sage: F Number Field in b with defining polynomial x^3 - 2 - sage: a = F.gen() # optional - sage.libs.pari sage.rings.number_field - sage: f(alpha) # optional - sage.libs.pari sage.rings.number_field + sage: a = F.gen() + sage: f(alpha) b - sage: g(a) # optional - sage.libs.pari sage.rings.number_field + sage: g(a) alpha Note that the parent ring must be an integral domain:: - sage: R. = GF(25, 'f25')['x'] # optional - sage.rings.finite_rings - sage: S. = R.quo(x^3 - 2) # optional - sage.rings.finite_rings - sage: F, g, h = S.field_extension('b') # optional - sage.rings.finite_rings + sage: R. = GF(25, 'f25')['x'] # needs sage.rings.finite_rings + sage: S. = R.quo(x^3 - 2) # needs sage.rings.finite_rings + sage: F, g, h = S.field_extension('b') # needs sage.rings.finite_rings Traceback (most recent call last): ... AttributeError: 'PolynomialQuotientRing_generic_with_category' object has no attribute 'field_extension' @@ -2331,21 +2365,23 @@ def field_extension(self, names): Over a finite field, the corresponding field extension is not a number field:: - sage: R. = GF(25, 'a')['x'] # optional - sage.rings.finite_rings - sage: S. = R.quo(x^3 + 2*x + 1) # optional - sage.rings.finite_rings - sage: F, g, h = S.field_extension('b') # optional - sage.rings.finite_rings - sage: h(F.0^2 + 3) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(25, 'a')['x'] + sage: S. = R.quo(x^3 + 2*x + 1) + sage: F, g, h = S.field_extension('b') + sage: h(F.0^2 + 3) a^2 + 3 - sage: g(x^2 + 2) # optional - sage.rings.finite_rings + sage: g(x^2 + 2) b^2 + 2 We do an example involving a relative number field:: + sage: # needs sage.rings.number_field sage: R. = QQ['x'] - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: S. = K['X'] # optional - sage.rings.number_field - sage: Q. = S.quo(X^3 + 2*X + 1) # optional - sage.rings.number_field - sage: Q.field_extension('b') # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: S. = K['X'] + sage: Q. = S.quo(X^3 + 2*X + 1) + sage: Q.field_extension('b') (Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field, ... Defn: b |--> b, Relative number field morphism: From: Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field @@ -2357,20 +2393,21 @@ def field_extension(self, names): :: + sage: # needs sage.rings.number_field sage: R. = QQ['x'] - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: S. = K['X'] # optional - sage.rings.number_field - sage: f = (X+a)^3 + 2*(X+a) + 1 # optional - sage.rings.number_field - sage: f # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: S. = K['X'] + sage: f = (X+a)^3 + 2*(X+a) + 1 + sage: f X^3 + 3*a*X^2 + (3*a^2 + 2)*X + 2*a + 3 - sage: Q. = S.quo(f) # optional - sage.rings.number_field - sage: F., g, h = Q.field_extension() # optional - sage.rings.number_field - sage: c = g(z) # optional - sage.rings.number_field - sage: f(c) # optional - sage.rings.number_field + sage: Q. = S.quo(f) + sage: F., g, h = Q.field_extension() + sage: c = g(z) + sage: f(c) 0 - sage: h(g(z)) # optional - sage.rings.number_field + sage: h(g(z)) z - sage: g(h(w)) # optional - sage.rings.number_field + sage: g(h(w)) w AUTHORS: @@ -2387,14 +2424,15 @@ class PolynomialQuotientRing_field(PolynomialQuotientRing_domain, Field): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) - sage: S. = R.quotient(x^2 + 1) # optional - sage.rings.number_field - sage: S # optional - sage.rings.number_field + sage: S. = R.quotient(x^2 + 1) + sage: S Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1 - sage: loads(S.dumps()) == S # optional - sage.rings.number_field + sage: loads(S.dumps()) == S True - sage: loads(xbar.dumps()) == xbar # optional - sage.rings.number_field + sage: loads(xbar.dumps()) == xbar True """ def __init__(self, ring, polynomial, name=None, category=None): @@ -2413,17 +2451,19 @@ def complex_embeddings(self, prec=53): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = QQ[] sage: f = x^5 + x + 17 - sage: k = R.quotient(f) # optional - sage.rings.number_field - sage: v = k.complex_embeddings(100) # optional - sage.rings.number_field - sage: [phi(k.0^2) for phi in v] # optional - sage.rings.number_field + sage: k = R.quotient(f) + sage: v = k.complex_embeddings(100) + sage: [phi(k.0^2) for phi in v] [2.9757207403766761469671194565, -2.4088994371613850098316292196 + 1.9025410530350528612407363802*I, -2.4088994371613850098316292196 - 1.9025410530350528612407363802*I, 0.92103906697304693634806949137 - 3.0755331188457794473265418086*I, 0.92103906697304693634806949137 + 3.0755331188457794473265418086*I] """ - CC = sage.rings.complex_mpfr.ComplexField(prec) + from sage.rings.complex_mpfr import ComplexField + CC = ComplexField(prec) v = self.modulus().roots(multiplicities=False, ring=CC) return [self.hom([a], check=False) for a in v] diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 7dd4e836be1..2f7d825dbf8 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.pari +# sage.doctest: needs sage.libs.pari r""" Elements of Quotients of Univariate Polynomial Rings @@ -8,8 +8,8 @@ :: sage: R. = ZZ[] - sage: S. = R.quotient(x^3 + 3*x - 1) # optional - sage.libs.pari - sage: 2 * a^3 # optional - sage.libs.pari + sage: S. = R.quotient(x^3 + 3*x - 1) + sage: 2 * a^3 -6*a + 2 Next we make a univariate polynomial ring over @@ -17,24 +17,24 @@ :: - sage: S1. = S[] # optional - sage.libs.pari + sage: S1. = S[] And, we quotient out that by `y^2 + a`. :: - sage: T. = S1.quotient(y^2 + a) # optional - sage.libs.pari + sage: T. = S1.quotient(y^2 + a) In the quotient `z^2` is `-a`. :: - sage: z^2 # optional - sage.libs.pari + sage: z^2 -a And since `a^3 = -3x + 1`, we have:: - sage: z^6 # optional - sage.libs.pari + sage: z^6 3*a - 1 :: @@ -100,9 +100,9 @@ class PolynomialQuotientRingElement(polynomial_singular_interface.Polynomial_sin sage: Q. = P.quo([(x^2 + 1)]) sage: xi^2 -1 - sage: singular(xi) + sage: singular(xi) # needs sage.libs.singular xi - sage: (singular(xi)*singular(xi)).NF('std(0)') + sage: (singular(xi)*singular(xi)).NF('std(0)') # needs sage.libs.singular -1 """ @@ -161,16 +161,17 @@ def _im_gens_(self, codomain, im_gens, base_map=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: Zx. = ZZ[] - sage: K. = NumberField(x^2 + 1) # optional - sage.rings.number_field - sage: cc = K.hom([-i]) # optional - sage.rings.number_field - sage: S. = K[] # optional - sage.rings.number_field - sage: Q. = S.quotient(y^2*(y-1)*(y-i)) # optional - sage.rings.number_field - sage: T. = S.quotient(y*(y+1)) # optional - sage.rings.number_field - sage: phi = Q.hom([t+1], base_map=cc) # optional - sage.rings.number_field - sage: phi(q) # optional - sage.rings.number_field + sage: K. = NumberField(x^2 + 1) + sage: cc = K.hom([-i]) + sage: S. = K[] + sage: Q. = S.quotient(y^2*(y-1)*(y-i)) + sage: T. = S.quotient(y*(y+1)) + sage: phi = Q.hom([t+1], base_map=cc) + sage: phi(q) t + 1 - sage: phi(i*q) # optional - sage.rings.number_field + sage: phi(i*q) -i*t - i """ return self._polynomial._im_gens_(codomain, im_gens, base_map=base_map) @@ -468,52 +469,56 @@ def field_extension(self, names): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQ) sage: S. = R.quotient(x^3 - 2) - sage: F., f, g = alpha.field_extension() # optional - sage.rings.number_field - sage: F # optional - sage.rings.number_field + sage: F., f, g = alpha.field_extension() + sage: F Number Field in a with defining polynomial x^3 - 2 - sage: a = F.gen() # optional - sage.rings.number_field - sage: f(alpha) # optional - sage.rings.number_field + sage: a = F.gen() + sage: f(alpha) a - sage: g(a) # optional - sage.rings.number_field + sage: g(a) alpha Over a finite field, the corresponding field extension is not a number field:: - sage: R. = GF(25,'b')['x'] # optional - sage.rings.finite_rings - sage: S. = R.quo(x^3 + 2*x + 1) # optional - sage.rings.finite_rings - sage: F., g, h = a.field_extension() # optional - sage.rings.finite_rings - sage: h(b^2 + 3) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(25,'b')['x'] + sage: S. = R.quo(x^3 + 2*x + 1) + sage: F., g, h = a.field_extension() + sage: h(b^2 + 3) a^2 + 3 - sage: g(x^2 + 2) # optional - sage.rings.finite_rings + sage: g(x^2 + 2) b^2 + 2 We do an example involving a relative number field:: + sage: # needs sage.rings.number_field sage: R. = QQ['x'] - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: S. = K['X'] # optional - sage.rings.number_field - sage: Q. = S.quo(X^3 + 2*X + 1) # optional - sage.rings.number_field - sage: F, g, h = b.field_extension('c') # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: S. = K['X'] + sage: Q. = S.quo(X^3 + 2*X + 1) + sage: F, g, h = b.field_extension('c') Another more awkward example:: + sage: # needs sage.rings.number_field sage: R. = QQ['x'] - sage: K. = NumberField(x^3 - 2) # optional - sage.rings.number_field - sage: S. = K['X'] # optional - sage.rings.number_field - sage: f = (X+a)^3 + 2*(X+a) + 1 # optional - sage.rings.number_field - sage: f # optional - sage.rings.number_field + sage: K. = NumberField(x^3 - 2) + sage: S. = K['X'] + sage: f = (X+a)^3 + 2*(X+a) + 1 + sage: f X^3 + 3*a*X^2 + (3*a^2 + 2)*X + 2*a + 3 - sage: Q. = S.quo(f) # optional - sage.rings.number_field - sage: F., g, h = z.field_extension() # optional - sage.rings.number_field - sage: c = g(z) # optional - sage.rings.number_field - sage: f(c) # optional - sage.rings.number_field + sage: Q. = S.quo(f) + sage: F., g, h = z.field_extension() + sage: c = g(z) + sage: f(c) 0 - sage: h(g(z)) # optional - sage.rings.number_field + sage: h(g(z)) z - sage: g(h(w)) # optional - sage.rings.number_field + sage: g(h(w)) w AUTHORS: @@ -703,28 +708,30 @@ def minpoly(self): polynomial of a finite-field element over an intermediate extension, rather than the absolute minimal polynomial over the prime field:: - sage: F2. = GF((431,2), modulus=[1,0,1]) # optional - sage.rings.finite_rings - sage: F6. = F2.extension(3) # optional - sage.rings.finite_rings - sage: (u + 1).minpoly() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F2. = GF((431,2), modulus=[1,0,1]) + sage: F6. = F2.extension(3) + sage: (u + 1).minpoly() x^6 + 425*x^5 + 19*x^4 + 125*x^3 + 189*x^2 + 239*x + 302 - sage: ext = F6.over(F2) # optional - sage.rings.finite_rings - sage: ext(u + 1).minpoly() # indirect doctest # optional - sage.rings.finite_rings + sage: ext = F6.over(F2) + sage: ext(u + 1).minpoly() # indirect doctest x^3 + (396*i + 428)*x^2 + (80*i + 39)*x + 9*i + 178 TESTS: We make sure that the previous example works on random examples:: + sage: # needs sage.rings.finite_rings sage: p = random_prime(50) - sage: K. = GF((p, randrange(1,20))) # optional - sage.rings.finite_rings - sage: L. = K.extension(randrange(2,20)) # optional - sage.rings.finite_rings - sage: LK = L.over(K) # optional - sage.rings.finite_rings - sage: a = L.random_element() # optional - sage.rings.finite_rings - sage: poly = LK(a).minpoly() # indirect doctest # optional - sage.rings.finite_rings - sage: poly(a) # optional - sage.rings.finite_rings + sage: K. = GF((p, randrange(1,20))) + sage: L. = K.extension(randrange(2,20)) + sage: LK = L.over(K) + sage: a = L.random_element() + sage: poly = LK(a).minpoly() # indirect doctest + sage: poly(a) 0 - sage: abs_deg = a.minpoly().degree() # optional - sage.rings.finite_rings - sage: poly.degree() == abs_deg // gcd(abs_deg, K.degree()) # optional - sage.rings.finite_rings + sage: abs_deg = a.minpoly().degree() + sage: poly.degree() == abs_deg // gcd(abs_deg, K.degree()) True """ poly = self.lift() @@ -772,14 +779,15 @@ def rational_reconstruction(self, *args, **kwargs): EXAMPLES:: - sage: R. = GF(65537)[] # optional - sage.rings.finite_rings - sage: m = (x^11 + 25345*x^10 + 10956*x^9 + 13873*x^8 + 23962*x^7 # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(65537)[] + sage: m = (x^11 + 25345*x^10 + 10956*x^9 + 13873*x^8 + 23962*x^7 ....: + 17496*x^6 + 30348*x^5 + 7440*x^4 + 65438*x^3 + 7676*x^2 ....: + 54266*x + 47805) - sage: f = (20437*x^10 + 62630*x^9 + 63241*x^8 + 12820*x^7 + 42171*x^6 # optional - sage.rings.finite_rings + sage: f = (20437*x^10 + 62630*x^9 + 63241*x^8 + 12820*x^7 + 42171*x^6 ....: + 63091*x^5 + 15288*x^4 + 32516*x^3 + 2181*x^2 + 45236*x + 2447) - sage: f_mod_m = R.quotient(m)(f) # optional - sage.rings.finite_rings - sage: f_mod_m.rational_reconstruction() # optional - sage.rings.finite_rings + sage: f_mod_m = R.quotient(m)(f) + sage: f_mod_m.rational_reconstruction() (51388*x^5 + 29141*x^4 + 59341*x^3 + 7034*x^2 + 14152*x + 23746, x^5 + 15208*x^4 + 19504*x^3 + 20457*x^2 + 11180*x + 28352) """ diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 8dbe789a410..d0dd15522e9 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -1506,8 +1506,8 @@ cdef class Polynomial_rational_flint(Polynomial): Check that :trac:`28187` is fixed:: - sage: x = var("x") - sage: f._derivative(x) + sage: x = var("x") # needs sage.symbolic + sage: f._derivative(x) # needs sage.symbolic 4*x^3 - 1 """ cdef Polynomial_rational_flint der diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 094aa2a3623..fbe96d186c5 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -6,19 +6,20 @@ TESTS: Check that operations with numpy elements work well (see :trac:`18076` and :trac:`8426`):: - sage: import numpy # optional - numpy + sage: # needs numpy + sage: import numpy sage: x = polygen(RR) - sage: x * numpy.int32('1') # optional - numpy + sage: x * numpy.int32('1') x - sage: numpy.int32('1') * x # optional - numpy + sage: numpy.int32('1') * x x - sage: x * numpy.int64('1') # optional - numpy + sage: x * numpy.int64('1') x - sage: numpy.int64('1') * x # optional - numpy + sage: numpy.int64('1') * x x - sage: x * numpy.float32('1.5') # optional - numpy + sage: x * numpy.float32('1.5') 1.50000000000000*x - sage: numpy.float32('1.5') * x # optional - numpy + sage: numpy.float32('1.5') * x 1.50000000000000*x """ @@ -39,7 +40,11 @@ from sage.structure.element cimport parent from sage.structure.element import coerce_binop from sage.libs.mpfr cimport * -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + cdef class PolynomialRealDense(Polynomial): r""" @@ -72,7 +77,7 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: PolynomialRealDense(RR['x'], [1, int(2), RR(3), 4/1, pi]) # optional - sage.symbolic + sage: PolynomialRealDense(RR['x'], [1, int(2), RR(3), 4/1, pi]) # needs sage.symbolic 3.14159265358979*x^4 + 4.00000000000000*x^3 + 3.00000000000000*x^2 + 2.00000000000000*x + 1.00000000000000 sage: PolynomialRealDense(RR['x'], None) 0 @@ -81,13 +86,13 @@ cdef class PolynomialRealDense(Polynomial): Check that errors and interrupts are handled properly (see :trac:`10100`):: - sage: a = var('a') # optional - sage.symbolic - sage: PolynomialRealDense(RR['x'], [1,a]) # optional - sage.symbolic + sage: a = var('a') # needs sage.symbolic + sage: PolynomialRealDense(RR['x'], [1,a]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: cannot evaluate symbolic expression to a numeric value - sage: R. = SR[] # optional - sage.symbolic - sage: (x-a).change_ring(RR) # optional - sage.symbolic + sage: R. = SR[] # needs sage.symbolic + sage: (x-a).change_ring(RR) # needs sage.symbolic Traceback (most recent call last): ... TypeError: cannot evaluate symbolic expression to a numeric value @@ -96,9 +101,9 @@ cdef class PolynomialRealDense(Polynomial): Test that we don't clean up uninitialized coefficients (:trac:`9826`):: - sage: k. = GF(7^3) # optional - sage.rings.finite_rings - sage: P. = PolynomialRing(k) # optional - sage.rings.finite_rings - sage: (a*x).complex_roots() # optional - sage.rings.finite_rings + sage: k. = GF(7^3) # needs sage.rings.finite_rings + sage: P. = PolynomialRing(k) # needs sage.rings.finite_rings + sage: (a*x).complex_roots() # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert 'a' to a real number @@ -514,16 +519,16 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: f = PolynomialRealDense(RR['x'], [pi, 0, 2, 1]) # optional - sage.symbolic - sage: f.derivative() # optional - sage.symbolic + sage: f = PolynomialRealDense(RR['x'], [pi, 0, 2, 1]) # needs sage.symbolic + sage: f.derivative() # needs sage.symbolic 3.00000000000000*x^2 + 4.00000000000000*x TESTS:: - sage: x, y = var('x,y') # optional - sage.symbolic - sage: f.derivative(x) # optional - sage.symbolic + sage: x, y = var('x,y') # needs sage.symbolic + sage: f.derivative(x) # needs sage.symbolic 3.00000000000000*x^2 + 4.00000000000000*x - sage: f.derivative(y) # optional - sage.symbolic + sage: f.derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -542,8 +547,8 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: f = PolynomialRealDense(RR['x'], [3, pi, 1]) # optional - sage.symbolic - sage: f.integral() # optional - sage.symbolic + sage: f = PolynomialRealDense(RR['x'], [3, pi, 1]) # needs sage.symbolic + sage: f.integral() # needs sage.symbolic 0.333333333333333*x^3 + 1.57079632679490*x^2 + 3.00000000000000*x """ cdef mpfr_rnd_t rnd = self._base_ring.rnd @@ -567,19 +572,20 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: - sage: f = RR['x']([-3, pi, 0, 1]) # optional - sage.symbolic - sage: f.reverse() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: f = RR['x']([-3, pi, 0, 1]) + sage: f.reverse() -3.00000000000000*x^3 + 3.14159265358979*x^2 + 1.00000000000000 - sage: f.reverse(2) # optional - sage.symbolic + sage: f.reverse(2) -3.00000000000000*x^2 + 3.14159265358979*x - sage: f.reverse(5) # optional - sage.symbolic + sage: f.reverse(5) -3.00000000000000*x^5 + 3.14159265358979*x^4 + x^2 TESTS: We check that this implementation is compatible with the generic one:: - sage: all(f.reverse(d) == Polynomial.reverse(f, d) # optional - sage.symbolic + sage: all(f.reverse(d) == Polynomial.reverse(f, d) # needs sage.symbolic ....: for d in [None, 0, 1, 2, 3, 4, 5]) True """ @@ -619,10 +625,11 @@ cdef class PolynomialRealDense(Polynomial): sage: fg.quo_rem(g) (x^2 - 2.00000000000000, 0) + sage: # needs sage.symbolic sage: f = PolynomialRealDense(RR['x'], range(5)) - sage: g = PolynomialRealDense(RR['x'], [pi,3000,4]) # optional - sage.symbolic - sage: q, r = f.quo_rem(g) # optional - sage.symbolic - sage: g*q + r == f # optional - sage.symbolic + sage: g = PolynomialRealDense(RR['x'], [pi,3000,4]) + sage: q, r = f.quo_rem(g) + sage: g*q + r == f True TESTS: @@ -681,7 +688,7 @@ cdef class PolynomialRealDense(Polynomial): 2.00000000000000 sage: f(RealField(10)(2)) 2.0 - sage: f(pi) # optional - sage.symbolic + sage: f(pi) # needs sage.symbolic 1.00000000000000*pi^2 - 2.00000000000000 diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 5e4a52943fc..968330c9288 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -89,7 +89,6 @@ different base rings. In that situation, coercion works by means of the :func:`~sage.categories.pushout.pushout` formalism:: - sage: # needs sage.rings.finite_rings sage: R. = PolynomialRing(GF(5), sparse=True) sage: S. = PolynomialRing(ZZ) sage: R.has_coerce_map_from(S) @@ -108,7 +107,7 @@ to the default FLINT implementation, but not vice versa:: sage: R. = PolynomialRing(ZZ, implementation='NTL') # needs sage.libs.ntl - sage: S. = PolynomialRing(ZZ, implementation='FLINT') # needs sage.libs.flint + sage: S. = PolynomialRing(ZZ, implementation='FLINT') sage: (S.0 + R.0).parent() is S # needs sage.libs.flint sage.libs.ntl True sage: (R.0 + S.0).parent() is S # needs sage.libs.flint sage.libs.ntl @@ -151,13 +150,17 @@ import sage.rings.ring as ring from sage.structure.element import is_RingElement -import sage.rings.polynomial.polynomial_element_generic as polynomial_element_generic import sage.rings.rational_field as rational_field from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.rings.number_field.number_field_base import NumberField -from sage.libs.pari.all import pari_gen + +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + from sage.rings.polynomial.polynomial_ring_constructor import polynomial_default_category import sage.misc.latex as latex @@ -168,15 +171,12 @@ import sage.rings.abc from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.finite_rings.element_base import FiniteRingElement -from .polynomial_real_mpfr_dense import PolynomialRealDense -from .polynomial_integer_dense_flint import Polynomial_integer_dense_flint from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular +from sage.rings.power_series_ring_element import PowerSeries _CommutativeRings = categories.commutative_rings.CommutativeRings() -from . import cyclotomic - import sage.interfaces.abc @@ -212,11 +212,12 @@ def is_PolynomialRing(x): :: - sage: R. = PolynomialRing(ZZ, implementation="singular"); R # needs sage.libs.singular + sage: # needs sage.libs.singular + sage: R. = PolynomialRing(ZZ, implementation="singular"); R Multivariate Polynomial Ring in w over Integer Ring - sage: is_PolynomialRing(R) # needs sage.libs.singular + sage: is_PolynomialRing(R) False - sage: type(R) # needs sage.libs.singular + sage: type(R) """ return isinstance(x, PolynomialRing_general) @@ -245,7 +246,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, and Category of commutative algebras over (euclidean domains and infinite enumerated sets and metric spaces) and Category of infinite sets - sage: category(GF(7)['x']) # needs sage.rings.finite_rings + sage: category(GF(7)['x']) Join of Category of euclidean domains and Category of commutative algebras over (finite enumerated fields and subquotients of monoids and quotients of semigroups) and Category of infinite sets @@ -270,13 +271,13 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: Zmod(1)['x'].is_finite() True - sage: GF(7)['x'].is_finite() # needs sage.rings.finite_rings + sage: GF(7)['x'].is_finite() False sage: Zmod(1)['x']['y'].is_finite() True - sage: GF(7)['x']['y'].is_finite() # needs sage.rings.finite_rings + sage: GF(7)['x']['y'].is_finite() False """ @@ -292,10 +293,11 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, self._polynomial_class = element_class else: if sparse: - self._polynomial_class = polynomial_element_generic.Polynomial_generic_sparse + from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse + self._polynomial_class = Polynomial_generic_sparse else: - from sage.rings.polynomial import polynomial_element - self._polynomial_class = polynomial_element.Polynomial_generic_dense + from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense + self._polynomial_class = Polynomial_generic_dense self.Element = self._polynomial_class self.__cyclopoly_cache = {} self._has_singular = False @@ -379,16 +381,17 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, This shows that the issue at :trac:`4106` is fixed:: - sage: x = var('x') # needs sage.symbolic + sage: # needs sage.symbolic + sage: x = var('x') sage: R = IntegerModRing(4) - sage: S = R['x'] # needs sage.symbolic - sage: S(x) # needs sage.symbolic + sage: S = R['x'] + sage: S(x) x Throw a TypeError if any of the coefficients cannot be coerced into the base ring (:trac:`6777`):: - sage: RealField(300)['x']( [ 1, ComplexField(300).gen(), 0 ]) + sage: RealField(300)['x']( [ 1, ComplexField(300).gen(), 0 ]) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: unable to convert '1.00...00*I' to a real number @@ -466,7 +469,7 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, return self(x.polynomial()) except AttributeError: pass - elif isinstance(x, sage.rings.power_series_ring_element.PowerSeries): + elif isinstance(x, PowerSeries): x = x.truncate() return C(self, x, check, is_gen, construct=construct, **kwds) @@ -657,6 +660,7 @@ def completion(self, p=None, prec=20, extras=None): sage: 1 / g 1 - x + O(x^20) + sage: # needs sage.combinat sage: PP = P.completion(x, prec=oo); PP Lazy Taylor Series Ring in x over Rational Field sage: g = 1 / PP(f); g @@ -697,7 +701,7 @@ def _coerce_map_from_base_ring(self): Polynomial base injection morphism: From: Rational Field To: Univariate Polynomial Ring in x over Rational Field - sage: R.coerce_map_from(GF(7)) # needs sage.rings.finite_rings + sage: R.coerce_map_from(GF(7)) """ from .polynomial_element import PolynomialBaseringInjection @@ -765,6 +769,7 @@ def _coerce_map_from_(self, P): Over the integers, there is a coercion from the NTL and generic implementation to the default FLINT implementation:: + sage: del R, S # clear values from doctests above sage: R = PolynomialRing(ZZ, 't', implementation="NTL") # needs sage.libs.ntl sage: S = PolynomialRing(ZZ, 't', implementation="FLINT") # needs sage.libs.flint sage: T = PolynomialRing(ZZ, 't', implementation="generic") @@ -816,6 +821,10 @@ def _coerce_map_from_(self, P): elif base_ring is ZZ: # Over ZZ, only allow coercion from any ZZ['x'] # implementation to the default FLINT implementation + try: + from .polynomial_integer_dense_flint import Polynomial_integer_dense_flint + except ImportError: + return None if self.element_class is not Polynomial_integer_dense_flint: return None # Other rings: always allow coercion @@ -875,7 +884,7 @@ def _magma_init_(self, magma): sage: k. = GF(9) # needs sage.rings.finite_rings sage: R. = k[] # needs sage.rings.finite_rings - sage: magma(a^2*x^3 + (a+1)*x + a) # optional - magma, needs sage.rings.finite_rings + sage: magma(a^2*x^3 + (a+1)*x + a) # optional - magma # needs sage.rings.finite_rings a^2*x^3 + a^2*x + a """ B = magma(self.base_ring()) @@ -927,11 +936,11 @@ def _sage_input_(self, sib, coerced): EXAMPLES:: - sage: sage_input(GF(5)['x']['y'], verify=True) # needs sage.rings.finite_rings + sage: sage_input(GF(5)['x']['y'], verify=True) # Verified GF(5)['x']['y'] - sage: from sage.misc.sage_input import SageInputBuilder # needs sage.rings.finite_rings - sage: ZZ['z']._sage_input_(SageInputBuilder(), False) # needs sage.rings.finite_rings + sage: from sage.misc.sage_input import SageInputBuilder + sage: ZZ['z']._sage_input_(SageInputBuilder(), False) {constr_parent: {subscr: {atomic:ZZ}[{atomic:'z'}]} with gens: ('z',)} """ base = sib(self.base_ring()) @@ -970,7 +979,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): EXAMPLES:: sage: R. = QQ[] - sage: R._is_valid_homomorphism_(GF(7), [5]) # needs sage.rings.finite_rings + sage: R._is_valid_homomorphism_(GF(7), [5]) False sage: R._is_valid_homomorphism_(Qp(7), [5]) # needs sage.rings.padics True @@ -1023,6 +1032,7 @@ def base_extend(self, R): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R. = RR[]; R Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: R.base_extend(CC) @@ -1171,22 +1181,22 @@ def cyclotomic_polynomial(self, n): EXAMPLES:: sage: R = ZZ['x'] - sage: R.cyclotomic_polynomial(8) # needs sage.libs.pari + sage: R.cyclotomic_polynomial(8) x^4 + 1 - sage: R.cyclotomic_polynomial(12) # needs sage.libs.pari + sage: R.cyclotomic_polynomial(12) x^4 - x^2 + 1 - sage: S = PolynomialRing(FiniteField(7), 'x') # needs sage.rings.finite_rings - sage: S.cyclotomic_polynomial(12) # needs sage.rings.finite_rings + sage: S = PolynomialRing(FiniteField(7), 'x') + sage: S.cyclotomic_polynomial(12) x^4 + 6*x^2 + 1 - sage: S.cyclotomic_polynomial(1) # needs sage.rings.finite_rings + sage: S.cyclotomic_polynomial(1) x + 6 TESTS: Make sure it agrees with other systems for the trivial case:: - sage: ZZ['x'].cyclotomic_polynomial(1) # needs sage.libs.pari + sage: ZZ['x'].cyclotomic_polynomial(1) x - 1 sage: gp('polcyclo(1)') # needs sage.libs.pari x - 1 @@ -1196,7 +1206,8 @@ def cyclotomic_polynomial(self, n): elif n == 1: return self.gen() - 1 else: - return self(cyclotomic.cyclotomic_coeffs(n), check=True) + from .cyclotomic import cyclotomic_coeffs + return self(cyclotomic_coeffs(n), check=True) @cached_method def gen(self, n=0): @@ -1255,10 +1266,11 @@ def is_exact(self): def is_field(self, proof=True): """ - Return False, since polynomial rings are never fields. + Return ``False``, since polynomial rings are never fields. EXAMPLES:: + sage: # needs sage.libs.ntl sage: R. = Integers(2)[]; R Univariate Polynomial Ring in z over Ring of integers modulo 2 (using GF2X) sage: R.is_field() @@ -1401,13 +1413,13 @@ def random_element(self, degree=(-1,2), *args, **kwds): Check that :trac:`16682` is fixed:: - sage: R = PolynomialRing(GF(2), 'z') # needs sage.rings.finite_rings - sage: for _ in range(100): # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2), 'z') + sage: for _ in range(100): ....: d = randint(-1,20) ....: P = R.random_element(degree=d) ....: assert P.degree() == d, "problem with {} which has not degree {}".format(P,d) - sage: R.random_element(degree=-2) # needs sage.rings.finite_rings + sage: R.random_element(degree=-2) Traceback (most recent call last): ... ValueError: degree should be an integer greater or equal than -1 @@ -1515,9 +1527,13 @@ def _Karatsuba_threshold(self): base_ring = self.base_ring() if is_PolynomialRing(base_ring): return 0 - from sage.matrix.matrix_space import MatrixSpace - if isinstance(base_ring, MatrixSpace): - return 0 + try: + from sage.matrix.matrix_space import MatrixSpace + except ImportError: + pass + else: + if isinstance(base_ring, MatrixSpace): + return 0 from sage.rings.fraction_field import FractionField_generic if isinstance(base_ring, FractionField_generic): return 1 << 60 @@ -1578,7 +1594,6 @@ def polynomials( self, of_degree=None, max_degree=None ): EXAMPLES:: - sage: # needs sage.rings.finite_rings sage: P = PolynomialRing(GF(3), 'y') sage: for p in P.polynomials(of_degree=2): print(p) y^2 @@ -1740,9 +1755,9 @@ def quotient_by_principal_ideal(self, f, names=None, **kwds): Quotienting by the zero ideal returns ``self`` (:trac:`5978`):: sage: R = QQ['x'] - sage: R.quotient_by_principal_ideal(R.zero_ideal()) is R # needs sage.libs.pari + sage: R.quotient_by_principal_ideal(R.zero_ideal()) is R True - sage: R.quotient_by_principal_ideal(0) is R # needs sage.libs.pari + sage: R.quotient_by_principal_ideal(0) is R True """ from sage.rings.ideal import Ideal @@ -1760,9 +1775,9 @@ def weyl_algebra(self): EXAMPLES:: sage: R = QQ['x'] - sage: W = R.weyl_algebra(); W # needs sage.combinat sage.modules + sage: W = R.weyl_algebra(); W # needs sage.modules Differential Weyl algebra of polynomials in x over Rational Field - sage: W.polynomial_ring() == R # needs sage.combinat sage.modules + sage: W.polynomial_ring() == R # needs sage.modules True """ from sage.algebras.weyl_algebra import DifferentialWeylAlgebra @@ -2016,11 +2031,12 @@ def construction(self): sage: functor.implementation is None True - sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl + sage: # needs sage.libs.ntl + sage: R = PRing(ZZ, 'x', implementation='NTL'); R Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: functor, arg = R.construction(); functor, arg # needs sage.libs.ntl + sage: functor, arg = R.construction(); functor, arg (Poly[x], Integer Ring) - sage: functor.implementation # needs sage.libs.ntl + sage: functor.implementation 'NTL' """ implementation = None @@ -2051,22 +2067,23 @@ def __init__(self, base_ring, name="x", sparse=False, implementation=None, Sparse Univariate Polynomial Ring in x over Rational Field sage: type(R.gen()) - sage: R = PRing(CC, 'x'); R + sage: R = PRing(CC, 'x'); R # needs sage.rings.real_mpfr Univariate Polynomial Ring in x over Complex Field with 53 bits of precision - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.real_mpfr Demonstrate that :trac:`8762` is fixed:: sage: R. = PolynomialRing(GF(next_prime(10^20)), sparse=True) # needs sage.rings.finite_rings - sage: x^(10^20) # this should be fast # needs sage.rings.finite_rings + sage: x^(10^20) # this should be fast # needs sage.rings.finite_rings x^100000000000000000000 """ def _element_class(): if element_class: return element_class if sparse: - return polynomial_element_generic.Polynomial_generic_sparse_field + from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_field + return Polynomial_generic_sparse_field if isinstance(base_ring, rational_field.RationalField): try: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint @@ -2105,8 +2122,8 @@ def _ideal_class_(self, n=0): EXAMPLES:: - sage: R. = GF(5)[] # needs sage.rings.finite_rings - sage: R._ideal_class_() # needs sage.rings.finite_rings + sage: R. = GF(5)[] + sage: R._ideal_class_() """ from sage.rings.polynomial.ideal import Ideal_1poly_field @@ -2281,9 +2298,10 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r -17/42*x^2 - 83/42*x + 53/7, -23/84*x^3 - 11/84*x^2 + 13/7*x + 1] - sage: R = PolynomialRing(GF(2**3, 'a'), 'x') # needs sage.rings.finite_rings - sage: a = R.base_ring().gen() # needs sage.rings.finite_rings - sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)], # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2**3, 'a'), 'x') + sage: a = R.base_ring().gen() + sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)], ....: algorithm="neville") [a^2 + a + 1, x + a + 1, a^2*x^2 + a^2*x + a^2] @@ -2343,10 +2361,10 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r Check that base fields of positive characteristic are treated correctly (see :trac:`9787`):: - sage: R. = GF(101)[] # needs sage.rings.finite_rings - sage: R.lagrange_polynomial([[1, 0], [2, 0]]) # needs sage.rings.finite_rings + sage: R. = GF(101)[] + sage: R.lagrange_polynomial([[1, 0], [2, 0]]) 0 - sage: R.lagrange_polynomial([[1, 0], [2, 0], [3, 0]]) # needs sage.rings.finite_rings + sage: R.lagrange_polynomial([[1, 0], [2, 0], [3, 0]]) 0 """ # Perhaps we should be slightly stricter on the input and use @@ -2432,8 +2450,8 @@ def fraction_field(self): EXAMPLES:: - sage: R. = GF(5)[] # needs sage.rings.finite_rings - sage: R.fraction_field() # needs sage.rings.finite_rings + sage: R. = GF(5)[] + sage: R.fraction_field() Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 @@ -2459,9 +2477,13 @@ def fraction_field(self): R = self.base_ring() p = R.characteristic() if p != 0 and R.is_prime_field(): - from sage.rings.fraction_field_FpT import FpT - if 2 < p and p < FpT.INTEGER_LIMIT: - return FpT(self) + try: + from sage.rings.fraction_field_FpT import FpT + except ImportError: + pass + else: + if 2 < p and p < FpT.INTEGER_LIMIT: + return FpT(self) from sage.rings.fraction_field import FractionField_1poly_field return FractionField_1poly_field(self) @@ -2485,8 +2507,8 @@ def __init__(self, base_ring, name="x", element_class=None, implementation=None) sage: type(R(0)) - sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') # needs sage.rings.finite_rings - sage: type(S(0)) # needs sage.rings.finite_rings + sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') # needs sage.libs.ntl sage.rings.finite_rings + sage: type(S(0)) # needs sage.libs.ntl sage.rings.finite_rings sage: S = PolynomialRing_dense_finite_field(GF(64), implementation='superfast') # needs sage.rings.finite_rings @@ -2863,10 +2885,10 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=False, algor Check that :trac:`23639` is fixed:: - sage: R = GF(3)['x']['y'] # needs sage.rings.finite_rings - sage: R.one().roots(multiplicities=False) # needs sage.rings.finite_rings + sage: R = GF(3)['x']['y'] + sage: R.one().roots(multiplicities=False) [] - sage: R.zero().roots(multiplicities=False) # needs sage.rings.finite_rings + sage: R.zero().roots(multiplicities=False) Traceback (most recent call last): ... ArithmeticError: roots of 0 are not defined @@ -2911,7 +2933,8 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: isinstance(S, PolynomialRing_cdvr) False - sage: S. = Zp(5)[] # needs sage.rings.padics + sage: # needs sage.rings.padics + sage: S. = Zp(5)[] sage: isinstance(S, PolynomialRing_cdvr) True """ @@ -3121,7 +3144,7 @@ def __init__(self, base_ring, name=None, element_class=None, sage: type(R.gen()) # needs sage.libs.ntl - sage: R = PRing(Zmod(2**63*3), 'x', implementation='FLINT') # needs sage.libs.flint + sage: R = PRing(Zmod(2**63*3), 'x', implementation='FLINT') Traceback (most recent call last): ... ValueError: FLINT does not support modulus 27670116110564327424 @@ -3231,7 +3254,7 @@ def residue_field(self, ideal, names=None): EXAMPLES:: - sage: # needs sage.rings.finite_rings + sage: # needs sage.libs.ntl sage: R. = GF(2)[] sage: k. = R.residue_field(t^3 + t + 1); k Residue field in a @@ -3255,15 +3278,16 @@ def residue_field(self, ideal, names=None): Non-maximal ideals are not accepted:: - sage: R.residue_field(t^2 + 1) # needs sage.rings.finite_rings + sage: # needs sage.libs.ntl + sage: R.residue_field(t^2 + 1) Traceback (most recent call last): ... ArithmeticError: ideal is not maximal - sage: R.residue_field(0) # needs sage.rings.finite_rings + sage: R.residue_field(0) Traceback (most recent call last): ... ArithmeticError: ideal is not maximal - sage: R.residue_field(1) # needs sage.rings.finite_rings + sage: R.residue_field(1) Traceback (most recent call last): ... ArithmeticError: ideal is not maximal @@ -3281,35 +3305,37 @@ def __init__(self, base_ring, name="x", implementation=None, element_class=None, """ TESTS:: - sage: P = GF(2)['x']; P # needs sage.rings.finite_rings + sage: P = GF(2)['x']; P # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: type(P.gen()) # needs sage.rings.finite_rings + sage: type(P.gen()) # needs sage.libs.ntl - sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_p # needs sage.rings.finite_rings - sage: P = PolynomialRing_dense_mod_p(GF(5), 'x'); P # needs sage.rings.finite_rings + sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_p + sage: P = PolynomialRing_dense_mod_p(GF(5), 'x'); P Univariate Polynomial Ring in x over Finite Field of size 5 - sage: type(P.gen()) # needs sage.rings.finite_rings + sage: type(P.gen()) # needs sage.libs.flint - sage: P = PolynomialRing_dense_mod_p(GF(5), 'x', implementation='NTL'); P # needs sage.rings.finite_rings + sage: # needs sage.libs.ntl + sage: P = PolynomialRing_dense_mod_p(GF(5), 'x', implementation='NTL'); P Univariate Polynomial Ring in x over Finite Field of size 5 (using NTL) - sage: type(P.gen()) # needs sage.rings.finite_rings + sage: type(P.gen()) - sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x'); P # needs sage.rings.finite_rings + sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x'); P # needs sage.libs.ntl sage.rings.finite_rings Univariate Polynomial Ring in x over Finite Field of size 9223372036854775837 (using NTL) - sage: type(P.gen()) # needs sage.rings.finite_rings + sage: type(P.gen()) # needs sage.libs.ntl sage.rings.finite_rings This caching bug was fixed in :trac:`24264`:: + sage: # needs sage.rings.finite_rings sage: p = 2^64 + 13 - sage: A = GF(p^2) # needs sage.rings.finite_rings - sage: B = GF(p^3) # needs sage.rings.finite_rings - sage: R = A.modulus().parent() # needs sage.rings.finite_rings - sage: S = B.modulus().parent() # needs sage.rings.finite_rings - sage: R is S # needs sage.rings.finite_rings + sage: A = GF(p^2) + sage: B = GF(p^3) + sage: R = A.modulus().parent() + sage: S = B.modulus().parent() + sage: R is S True """ if element_class is None: @@ -3351,19 +3377,20 @@ def _implementation_names_impl(implementation, base_ring, sparse): """ TESTS:: - sage: # needs sage.rings.finite_rings + sage: # needs sage.libs.ntl sage: PolynomialRing(GF(2), 'x', implementation="GF2X") Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: PolynomialRing(GF(2), 'x', implementation="NTL") Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: PolynomialRing(GF(2), 'x', implementation=None) Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: PolynomialRing(GF(2), 'x', implementation="FLINT") - Univariate Polynomial Ring in x over Finite Field of size 2 sage: PolynomialRing(GF(3), 'x', implementation="GF2X") Traceback (most recent call last): ... ValueError: GF2X only supports modulus 2 + + sage: PolynomialRing(GF(2), 'x', implementation="FLINT") # needs sage.libs.flint + Univariate Polynomial Ring in x over Finite Field of size 2 """ if sparse: return NotImplemented @@ -3474,9 +3501,6 @@ def irreducible_element(self, n, algorithm=None): from sage.libs.pari.all import pari from sage.rings.finite_rings.conway_polynomials import (conway_polynomial, exists_conway_polynomial) - from .polynomial_gf2x import (GF2X_BuildIrred_list, - GF2X_BuildSparseIrred_list, - GF2X_BuildRandomIrred_list) p = self.characteristic() n = int(n) @@ -3489,7 +3513,12 @@ def irreducible_element(self, n, algorithm=None): elif exists_conway_polynomial(p, n): algorithm = "conway" elif p == 2: - algorithm = "minimal_weight" + try: + from .polynomial_gf2x import GF2X_BuildSparseIrred_list + except ImportError: + algorithm = "adleman-lenstra" + else: + algorithm = "minimal_weight" else: algorithm = "adleman-lenstra" elif algorithm == "primitive": @@ -3504,6 +3533,7 @@ def irreducible_element(self, n, algorithm=None): return self(conway_polynomial(p, n)) elif algorithm == "first_lexicographic": if p == 2: + from .polynomial_gf2x import GF2X_BuildIrred_list return self(GF2X_BuildIrred_list(n)) else: # Fallback to PolynomialRing_dense_finite_field.irreducible_element @@ -3512,11 +3542,13 @@ def irreducible_element(self, n, algorithm=None): return self(pari(p).ffinit(n).ffgen().ffprimroot().charpoly()) elif algorithm == "minimal_weight": if p == 2: + from .polynomial_gf2x import GF2X_BuildSparseIrred_list return self(GF2X_BuildSparseIrred_list(n)) else: raise NotImplementedError("'minimal_weight' option only implemented for p = 2") elif algorithm == "random": if p == 2: + from .polynomial_gf2x import GF2X_BuildRandomIrred_list return self(GF2X_BuildRandomIrred_list(n)) else: pass diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 08968a5795b..acaea2e3a16 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -22,7 +22,15 @@ # **************************************************************************** from sage.structure.category_object import normalize_names import sage.rings.ring as ring -import sage.rings.padics.padic_base_leaves as padic_base_leaves + +try: + import sage.rings.padics.padic_base_leaves as padic_base_leaves +except ImportError: + class padic_base_leaves: + pAdicFieldCappedRelative = () + pAdicRingCappedRelative = () + pAdicRingCappedAbsolute = () + pAdicRingFixedMod = () import sage.rings.abc from sage.rings.integer import Integer @@ -144,7 +152,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R. = PolynomialRing(QQ, sparse=True); R Sparse Univariate Polynomial Ring in abc over Rational Field - sage: R. = PolynomialRing(PolynomialRing(GF(7),'k')); R # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(PolynomialRing(GF(7),'k')); R Univariate Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 @@ -180,32 +188,32 @@ def PolynomialRing(base_ring, *args, **kwds): like 2^1000000 * x^1000000 in FLINT may be unwise. :: - sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); ZxNTL # optional - sage.libs.ntl + sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); ZxNTL # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); ZxFLINT # optional - sage.libs.flint + sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); ZxFLINT # needs sage.libs.flint Univariate Polynomial Ring in x over Integer Ring - sage: ZxFLINT is ZZ['x'] # optional - sage.libs.flint + sage: ZxFLINT is ZZ['x'] # needs sage.libs.flint True - sage: ZxFLINT is PolynomialRing(ZZ, 'x') # optional - sage.libs.flint + sage: ZxFLINT is PolynomialRing(ZZ, 'x') # needs sage.libs.flint True - sage: xNTL = ZxNTL.gen() # optional - sage.libs.ntl - sage: xFLINT = ZxFLINT.gen() # optional - sage.libs.flint - sage: xNTL.parent() # optional - sage.libs.ntl + sage: xNTL = ZxNTL.gen() # needs sage.libs.ntl + sage: xFLINT = ZxFLINT.gen() # needs sage.libs.flint + sage: xNTL.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: xFLINT.parent() # optional - sage.libs.flint + sage: xFLINT.parent() # needs sage.libs.flint Univariate Polynomial Ring in x over Integer Ring There is a coercion from the non-default to the default implementation, so the values can be mixed in a single expression:: - sage: (xNTL + xFLINT^2) # optional - sage.libs.flint sage.libs.ntl + sage: (xNTL + xFLINT^2) # needs sage.libs.flint sage.libs.ntl x^2 + x The result of such an expression will use the default, i.e., the FLINT implementation:: - sage: (xNTL + xFLINT^2).parent() # optional - sage.libs.flint sage.libs.ntl + sage: (xNTL + xFLINT^2).parent() # needs sage.libs.flint sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring The generic implementation uses neither NTL nor FLINT:: @@ -260,9 +268,9 @@ def PolynomialRing(base_ring, *args, **kwds): The Singular implementation always returns a multivariate ring, even for 1 variable:: - sage: PolynomialRing(QQ, "x", implementation="singular") # optional - sage.libs.singular + sage: PolynomialRing(QQ, "x", implementation="singular") # needs sage.libs.singular Multivariate Polynomial Ring in x over Rational Field - sage: P. = PolynomialRing(QQ, implementation="singular"); P # optional - sage.libs.singular + sage: P. = PolynomialRing(QQ, implementation="singular"); P # needs sage.libs.singular Multivariate Polynomial Ring in x over Rational Field **3. PolynomialRing(base_ring, n, names, ...)** (where the arguments @@ -279,7 +287,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: PolynomialRing(QQ, 2, 'alpha0') Multivariate Polynomial Ring in alpha00, alpha01 over Rational Field - sage: PolynomialRing(GF(7), 'y', 5) # optional - sage.rings.finite_rings + sage: PolynomialRing(GF(7), 'y', 5) Multivariate Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7 sage: PolynomialRing(QQ, 'y', 3, sparse=True) @@ -299,7 +307,7 @@ def PolynomialRing(base_ring, *args, **kwds): example, here is a ring with generators labeled by the primes less than 100:: - sage: R = PolynomialRing(ZZ, ['x%s'%p for p in primes(100)]); R # optional - sage.libs.pari + sage: R = PolynomialRing(ZZ, ['x%s'%p for p in primes(100)]); R # needs sage.libs.pari Multivariate Polynomial Ring in x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 over Integer Ring @@ -308,10 +316,10 @@ def PolynomialRing(base_ring, *args, **kwds): :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: - sage: R.inject_variables() # optional - sage.libs.pari + sage: R.inject_variables() # needs sage.libs.pari Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 - sage: (x2 + x41 + x71)^2 # optional - sage.libs.pari + sage: (x2 + x41 + x71)^2 # needs sage.libs.pari x2^2 + 2*x2*x41 + x41^2 + 2*x2*x71 + 2*x41*x71 + x71^2 **4. PolynomialRing(base_ring, n, ..., var_array=var_array, ...)** @@ -347,6 +355,7 @@ def PolynomialRing(base_ring, *args, **kwds): You can alternatively create a polynomial ring over a ring `R` with square brackets:: + sage: # needs sage.rings.real_mpfr sage: RR["x"] Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: RR["x,y"] @@ -399,9 +408,9 @@ def PolynomialRing(base_ring, *args, **kwds): Check uniqueness if the same implementation is used for different values of the ``"implementation"`` keyword:: - sage: R = PolynomialRing(QQbar, 'j', implementation="generic") - sage: S = PolynomialRing(QQbar, 'j', implementation=None) - sage: R is S + sage: R = PolynomialRing(QQbar, 'j', implementation="generic") # needs sage.rings.number_field + sage: S = PolynomialRing(QQbar, 'j', implementation=None) # needs sage.rings.number_field + sage: R is S # needs sage.rings.number_field True sage: R = PolynomialRing(ZZ['t'], 'j', implementation="generic") @@ -409,11 +418,13 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R is S True + sage: # needs sage.rings.number_field sage: R = PolynomialRing(QQbar, 'j,k', implementation="generic") sage: S = PolynomialRing(QQbar, 'j,k', implementation=None) sage: R is S True + sage: # needs sage.libs.singular sage: R = PolynomialRing(ZZ, 'j,k', implementation="singular") sage: S = PolynomialRing(ZZ, 'j,k', implementation=None) sage: R is S @@ -426,14 +437,14 @@ def PolynomialRing(base_ring, *args, **kwds): The generic implementation is different in some cases:: - sage: R = PolynomialRing(GF(2), 'j', implementation="generic"); TestSuite(R).run(skip=['_test_construction', '_test_pickling']); type(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(2), 'j', implementation="generic"); TestSuite(R).run(skip=['_test_construction', '_test_pickling']); type(R) - sage: S = PolynomialRing(GF(2), 'j'); TestSuite(S).run(); type(S) # optional - sage.rings.finite_rings + sage: S = PolynomialRing(GF(2), 'j'); TestSuite(S).run(); type(S) - sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) + sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) # needs sage.libs.singular - sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) + sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) # needs sage.libs.singular Sparse univariate polynomials only support a generic @@ -441,7 +452,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R = PolynomialRing(ZZ, 'j', sparse=True); TestSuite(R).run(); type(R) - sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # needs sage.rings.finite_rings If the requested implementation is not known or not supported for @@ -451,7 +462,7 @@ def PolynomialRing(base_ring, *args, **kwds): Traceback (most recent call last): ... ValueError: unknown implementation 'Foo' for dense polynomial rings over Integer Ring - sage: R. = PolynomialRing(GF(2), implementation='GF2X', sparse=True) # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(2), implementation='GF2X', sparse=True) Traceback (most recent call last): ... ValueError: unknown implementation 'GF2X' for sparse polynomial rings over Finite Field of size 2 @@ -459,7 +470,7 @@ def PolynomialRing(base_ring, *args, **kwds): Traceback (most recent call last): ... ValueError: unknown implementation 'FLINT' for multivariate polynomial rings - sage: R. = PolynomialRing(QQbar, implementation="whatever") + sage: R. = PolynomialRing(QQbar, implementation="whatever") # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: unknown implementation 'whatever' for dense polynomial rings over Algebraic Field @@ -471,7 +482,7 @@ def PolynomialRing(base_ring, *args, **kwds): Traceback (most recent call last): ... ValueError: unknown implementation 'whatever' for multivariate polynomial rings - sage: PolynomialRing(RR, name="x", implementation="singular") + sage: PolynomialRing(RR, name="x", implementation="singular") # needs sage.libs.singular Traceback (most recent call last): ... NotImplementedError: polynomials over Real Field with 53 bits of precision are not supported in Singular @@ -486,18 +497,20 @@ def PolynomialRing(base_ring, *args, **kwds): We verify that :trac:`13187` is fixed:: - sage: var('t') + sage: var('t') # needs sage.symbolic t - sage: PolynomialRing(ZZ, name=t) == PolynomialRing(ZZ, name='t') + sage: PolynomialRing(ZZ, name=t) == PolynomialRing(ZZ, name='t') # needs sage.symbolic True We verify that polynomials with interval coefficients from :trac:`7712` and :trac:`13760` are fixed:: + sage: # needs sage.rings.real_interval_field sage: P. = PolynomialRing(RealIntervalField(2)) sage: TestSuite(P).run(skip=['_test_elements', '_test_elements_eq_transitive']) sage: Q. = PolynomialRing(P) - sage: TestSuite(Q).run(skip=['_test_additive_associativity', '_test_associativity', '_test_distributivity', '_test_prod']) + sage: TestSuite(Q).run(skip=['_test_additive_associativity', '_test_associativity', + ....: '_test_distributivity', '_test_prod']) sage: C = (y-x)^3 sage: C(y/2) 1.?*y^3 @@ -563,7 +576,7 @@ def PolynomialRing(base_ring, *args, **kwds): We run the testsuite for various polynomial rings, skipping tests that currently fail:: - sage: R. = PolynomialRing(PolynomialRing(GF(7),'k')); TestSuite(R).run(); R # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(PolynomialRing(GF(7),'k')); TestSuite(R).run(); R Univariate Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); TestSuite(ZxNTL).run(skip='_test_pickling'); ZxNTL Univariate Polynomial Ring in x over Integer Ring (using NTL) @@ -579,23 +592,24 @@ def PolynomialRing(base_ring, *args, **kwds): Multivariate Polynomial Ring in x, y, z over Rational Field sage: Q0 = PolynomialRing(QQ,[]); TestSuite(Q0).run(skip=['_test_elements', '_test_elements_eq_transitive', '_test_gcd_vs_xgcd', '_test_quo_rem']); Q0 Multivariate Polynomial Ring in no variables over Rational Field - sage: P. = PolynomialRing(QQ, implementation="singular"); TestSuite(P).run(skip=['_test_construction', '_test_elements', '_test_euclidean_degree', '_test_quo_rem']); P + sage: P. = PolynomialRing(QQ, implementation="singular"); TestSuite(P).run(skip=['_test_construction', '_test_elements', # needs sage.libs.singular + ....: '_test_euclidean_degree', '_test_quo_rem']); P Multivariate Polynomial Ring in x over Rational Field sage: Q1 = PolynomialRing(QQ,"x",1); TestSuite(Q1).run(skip=['_test_construction', '_test_elements', '_test_euclidean_degree', '_test_quo_rem']); Q1 Multivariate Polynomial Ring in x over Rational Field sage: Q0 = PolynomialRing(QQ,"x",0); TestSuite(Q0).run(skip=['_test_elements', '_test_elements_eq_transitive', '_test_gcd_vs_xgcd', '_test_quo_rem']); Q0 Multivariate Polynomial Ring in no variables over Rational Field - sage: R = PolynomialRing(GF(2), 'j', implementation="generic"); TestSuite(R).run(skip=['_test_construction', '_test_pickling']); type(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(2), 'j', implementation="generic"); TestSuite(R).run(skip=['_test_construction', '_test_pickling']); type(R) - sage: S = PolynomialRing(GF(2), 'j'); TestSuite(S).run(); type(S) # optional - sage.rings.finite_rings + sage: S = PolynomialRing(GF(2), 'j'); TestSuite(S).run(); type(S) sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) - sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) + sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) # needs sage.libs.singular sage: R = PolynomialRing(ZZ, 'j', sparse=True); TestSuite(R).run(); type(R) - sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # needs sage.rings.finite_rings sage: P. = PolynomialRing(RealIntervalField(2)) sage: TestSuite(P).run(skip=['_test_elements', '_test_elements_eq_transitive']) @@ -942,42 +956,42 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order="lex"): EXAMPLES:: - sage: R. = BooleanPolynomialRing(); R # indirect doctest # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(); R # indirect doctest Boolean PolynomialRing in x, y, z - - sage: p = x*y + x*z + y*z # optional - sage.rings.polynomial.pbori - sage: x*p # optional - sage.rings.polynomial.pbori + sage: p = x*y + x*z + y*z + sage: x*p x*y*z + x*y + x*z - - sage: R.term_order() # optional - sage.rings.polynomial.pbori + sage: R.term_order() Lexicographic term order - sage: R = BooleanPolynomialRing(5, 'x', order='deglex(3),deglex(2)') # optional - sage.rings.polynomial.pbori - sage: R.term_order() # optional - sage.rings.polynomial.pbori + sage: R = BooleanPolynomialRing(5, 'x', order='deglex(3),deglex(2)') # needs sage.rings.polynomial.pbori + sage: R.term_order() # needs sage.rings.polynomial.pbori Block term order with blocks: (Degree lexicographic term order of length 3, Degree lexicographic term order of length 2) - sage: R = BooleanPolynomialRing(3, 'x', order='degneglex') # optional - sage.rings.polynomial.pbori - sage: R.term_order() # optional - sage.rings.polynomial.pbori + sage: R = BooleanPolynomialRing(3, 'x', order='degneglex') # needs sage.rings.polynomial.pbori + sage: R.term_order() # needs sage.rings.polynomial.pbori Degree negative lexicographic term order - sage: BooleanPolynomialRing(names=('x','y')) # optional - sage.rings.polynomial.pbori + sage: BooleanPolynomialRing(names=('x','y')) # needs sage.rings.polynomial.pbori Boolean PolynomialRing in x, y - sage: BooleanPolynomialRing(names='x,y') # optional - sage.rings.polynomial.pbori + sage: BooleanPolynomialRing(names='x,y') # needs sage.rings.polynomial.pbori Boolean PolynomialRing in x, y TESTS:: - sage: P. = BooleanPolynomialRing(2, order='deglex') # optional - sage.rings.polynomial.pbori - sage: x > y # optional - sage.rings.polynomial.pbori + sage: P. = BooleanPolynomialRing(2, order='deglex') # needs sage.rings.polynomial.pbori + sage: x > y # needs sage.rings.polynomial.pbori True - sage: P. = BooleanPolynomialRing(4, order='deglex(2),deglex(2)') # optional - sage.rings.polynomial.pbori - sage: x0 > x1 # optional - sage.rings.polynomial.pbori + sage: # needs sage.rings.polynomial.pbori + sage: P. = BooleanPolynomialRing(4, order='deglex(2),deglex(2)') + sage: x0 > x1 True - sage: x2 > x3 # optional - sage.rings.polynomial.pbori + sage: x2 > x3 True """ if isinstance(n, str): diff --git a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx index 4b55fa8c778..7e3e27dd520 100644 --- a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx +++ b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx @@ -55,7 +55,7 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): sage: g = QQ.hom(RR) sage: G = PolynomialRingHomomorphism_from_base(A.Hom(B), g) sage: G(A.gen()^1000000) - 1.00000000000000*x^1000000 + 1.0...*x^1000000 """ P = self.codomain() @@ -73,18 +73,19 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): sage: from sage.rings.polynomial.polynomial_ring_homomorphism import PolynomialRingHomomorphism_from_base sage: R. = ZZ[] - sage: S = GF(5)['x'] # optional - sage.rings.finite_rings - sage: f = ZZ.hom(GF(5)) # optional - sage.rings.finite_rings - sage: F = PolynomialRingHomomorphism_from_base(R.Hom(S), f) # optional - sage.rings.finite_rings - sage: F(2 * x, check=True) # optional - sage.rings.finite_rings + sage: S = GF(5)['x'] + sage: f = ZZ.hom(GF(5)) + sage: F = PolynomialRingHomomorphism_from_base(R.Hom(S), f) + sage: F(2 * x, check=True) 2*x - sage: k = GF(49, 'z') # optional - sage.rings.finite_rings - sage: A = PolynomialRing(GF(7), 'x', sparse=True) # optional - sage.rings.finite_rings - sage: B = PolynomialRing(k, 'x', sparse=True) # optional - sage.rings.finite_rings - sage: g = GF(7).hom(k) # optional - sage.rings.finite_rings - sage: G = PolynomialRingHomomorphism_from_base(A.Hom(B), g) # optional - sage.rings.finite_rings - sage: G(A.gen()^1000000, True, construct=False) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k = GF(49, 'z') + sage: A = PolynomialRing(GF(7), 'x', sparse=True) + sage: B = PolynomialRing(k, 'x', sparse=True) + sage: g = GF(7).hom(k) + sage: G = PolynomialRingHomomorphism_from_base(A.Hom(B), g) + sage: G(A.gen()^1000000, True, construct=False) x^1000000 """ diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index d725046ccdf..257eaf4c267 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -10,11 +10,11 @@ TESTS:: - sage: R = PolynomialRing(GF(2**8,'a'), 10, 'x', order='invlex') # optional - sage.rings.finite_rings - sage: R == loads(dumps(R)) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(2**8,'a'), 10, 'x', order='invlex') # needs sage.rings.finite_rings + sage: R == loads(dumps(R)) # needs sage.rings.finite_rings True - sage: P. = PolynomialRing(GF(7), 2) # optional - sage.rings.finite_rings - sage: f = (a^3 + 2*b^2*a)^7; f # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(7), 2) + sage: f = (a^3 + 2*b^2*a)^7; f a^21 + 2*a^7*b^14 """ @@ -41,7 +41,11 @@ import sage.rings.abc import sage.rings.number_field as number_field -from sage.interfaces.singular import singular +try: + from sage.interfaces.singular import singular +except ImportError: + singular = None + from sage.rings.rational_field import is_RationalField from sage.rings.function_field.function_field_rational import RationalFunctionField from sage.rings.finite_rings.finite_field_base import FiniteField @@ -61,7 +65,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): TESTS:: sage: from sage.rings.polynomial.polynomial_singular_interface import _do_singular_init_ - sage: _do_singular_init_(singular, ZZ, 0, 'X', 'dp') # optional - sage.libs.singular + sage: _do_singular_init_(singular, ZZ, 0, 'X', 'dp') # needs sage.libs.singular (polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 1 @@ -163,7 +167,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): return singular(f"std(ideal({base_ring.__minpoly}))", type='qring'), None - elif isinstance(base_ring, sage.rings.function_field.function_field_rational.RationalFunctionField) \ + elif isinstance(base_ring, RationalFunctionField) \ and base_ring.constant_field().is_prime_field(): gen = str(base_ring.gen()) return make_ring(f"({base_ring.characteristic()},{gen})"), None @@ -194,8 +198,8 @@ def _singular_(self, singular=singular): EXAMPLES:: - sage: R. = PolynomialRing(CC) - sage: singular(R) + sage: R. = PolynomialRing(CC) # needs sage.rings.real_mpfr + sage: singular(R) # needs sage.libs.singular sage.rings.real_mpfr polynomial ring, over a field, global ordering // coefficients: real[I](complex:15 digits, additional 0 digits)/(I^2+1) // number of vars : 2 @@ -203,8 +207,8 @@ def _singular_(self, singular=singular): // : names x y // block 2 : ordering C - sage: R. = PolynomialRing(RealField(100)) - sage: singular(R) + sage: R. = PolynomialRing(RealField(100)) # needs sage.rings.real_mpfr + sage: singular(R) # needs sage.libs.singular sage.rings.real_mpfr polynomial ring, over a field, global ordering // coefficients: Float() // number of vars : 2 @@ -213,8 +217,8 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: w = polygen(ZZ, 'w') - sage: R. = PolynomialRing(NumberField(w^2 + 1, 's')) # optional - sage.rings.number_field - sage: singular(R) # optional - sage.rings.number_field + sage: R. = PolynomialRing(NumberField(w^2 + 1, 's')) # needs sage.rings.number_field + sage: singular(R) # needs sage.libs.singular sage.rings.number_field polynomial ring, over a field, global ordering // coefficients: QQ[s]/(s^2+1) // number of vars : 1 @@ -222,8 +226,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(GF(127), 'x', implementation="singular") # optional - sage.rings.finite_rings - sage: singular(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(127), 'x', implementation="singular") # needs sage.libs.singular + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -231,8 +235,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(QQ, 'x', implementation="singular") - sage: singular(R) + sage: R = PolynomialRing(QQ, 'x', implementation="singular") # needs sage.libs.singular + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -241,7 +245,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = PolynomialRing(QQ,'x') - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -249,8 +253,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(GF(127), 'x') # optional - sage.rings.finite_rings - sage: singular(R) # optional - sage.rings.finite_rings + sage: R = PolynomialRing(GF(127), 'x') + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -259,7 +263,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = Frac(ZZ['a,b'])['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ(a, b) // number of vars : 2 @@ -269,7 +273,7 @@ def _singular_(self, singular=singular): sage: R = IntegerModRing(1024)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/(2^10) // number of vars : 2 @@ -278,7 +282,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = IntegerModRing(15)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/...(15) // number of vars : 2 @@ -287,7 +291,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = ZZ['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 2 @@ -296,7 +300,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = ZZ['x'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 1 @@ -304,11 +308,12 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: k. = FiniteField(25) # optional - sage.rings.finite_rings - sage: R = k['x'] # optional - sage.rings.finite_rings - sage: K = R.fraction_field() # optional - sage.rings.finite_rings - sage: S = K['y'] # optional - sage.rings.finite_rings - sage: singular(S) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = FiniteField(25) + sage: R = k['x'] + sage: K = R.fraction_field() + sage: S = K['y'] + sage: singular(S) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/5(x) // number of vars : 2 @@ -349,7 +354,7 @@ def _singular_init_(self, singular=singular): EXAMPLES:: - sage: PolynomialRing(QQ,'u_ba')._singular_init_() # optional - sage.libs.singular + sage: PolynomialRing(QQ,'u_ba')._singular_init_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -399,23 +404,25 @@ def can_convert_to_singular(R): Avoid non absolute number fields (see :trac:`23535`):: sage: x = polygen(ZZ, 'x') - sage: K. = NumberField([x^2 - 2, x^2 - 5]) # optional - sage.rings.number_field - sage: can_convert_to_singular(K['s,t']) # optional - sage.rings.number_field + sage: K. = NumberField([x^2 - 2, x^2 - 5]) # needs sage.rings.number_field + sage: can_convert_to_singular(K['s,t']) # needs sage.rings.number_field False Check for :trac:`33319`:: - sage: R. = GF((2^31-1)^3)[] # optional - sage.rings.finite_rings - sage: R._has_singular # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF((2^31-1)^3)[] + sage: R._has_singular True - sage: R. = GF((2^31+11)^2)[] # optional - sage.rings.finite_rings - sage: R._has_singular # optional - sage.rings.finite_rings + sage: R. = GF((2^31+11)^2)[] + sage: R._has_singular False - sage: R. = GF(10^20 - 11)[] # optional - sage.rings.finite_rings - sage: R._has_singular # optional - sage.rings.finite_rings + sage: R. = GF(10^20 - 11)[] + sage: R._has_singular True - sage: R. = Zmod(10^20 + 1)[] # optional - sage.libs.pari - sage: R._has_singular # optional - sage.libs.pari + + sage: R. = Zmod(10^20 + 1)[] + sage: R._has_singular True """ if R.ngens() == 0: @@ -470,25 +477,27 @@ def _singular_func(self, singular=singular): EXAMPLES:: - sage: P. = PolynomialRing(GF(7), 2) # optional - sage.rings.finite_rings - sage: f = (a^3 + 2*b^2*a)^7; f # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(7), 2) + sage: f = (a^3 + 2*b^2*a)^7; f a^21 + 2*a^7*b^14 - sage: h = f._singular_(); h # optional - sage.rings.finite_rings + sage: h = f._singular_(); h a^21+2*a^7*b^14 - sage: P(h) # optional - sage.rings.finite_rings + sage: P(h) a^21 + 2*a^7*b^14 - sage: P(h^20) == f^20 # optional - sage.rings.finite_rings + sage: P(h^20) == f^20 True - sage: R. = PolynomialRing(GF(7)) # optional - sage.rings.finite_rings - sage: f = (x^3 + 2*x^2*x)^7 # optional - sage.rings.finite_rings - sage: f # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular + sage: R. = PolynomialRing(GF(7)) + sage: f = (x^3 + 2*x^2*x)^7 + sage: f 3*x^21 - sage: h = f._singular_(); h # optional - sage.rings.finite_rings + sage: h = f._singular_(); h 3*x^21 - sage: R(h) # optional - sage.rings.finite_rings + sage: R(h) 3*x^21 - sage: R(h^20) == f^20 # optional - sage.rings.finite_rings + sage: R(h^20) == f^20 True """ self.parent()._singular_(singular).set_ring() # this is expensive diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 7419e9ebb4a..ada39527536 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -214,6 +214,7 @@ cdef class Polynomial_template(Polynomial): The following has been a problem in a preliminary version of :trac:`12313`:: + sage: # needs sage.rings.finite_rings sage: K. = GF(4) sage: P. = K[] sage: del P @@ -778,7 +779,7 @@ cdef class Polynomial_template(Polynomial): sage: P. = PolynomialRing(GF(7)) sage: f = 3*x^2 + 2*x + 5 - sage: singular(f) + sage: singular(f) # needs sage.libs.singular 3*x^2+2*x-2 """ self.parent()._singular_(singular).set_ring() # this is expensive diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index ca5d32e2903..d7d8473b563 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.ntl sage.rings.finite_rings +# sage.doctest: needs sage.libs.ntl sage.rings.finite_rings # distutils: libraries = NTL_LIBRARIES gmp # distutils: extra_compile_args = NTL_CFLAGS # distutils: include_dirs = NTL_INCDIR @@ -237,7 +237,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): sage: F. = GF(4) sage: P. = F[] sage: p = y^4 + x*y^3 + y^2 + (x + 1)*y + x + 1 - sage: SR(p) # optional - sage.symbolic + sage: SR(p) # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index 55363a1c00c..4b5ebac6d8e 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -435,7 +435,7 @@ dr_cache = {} cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): """ - This is the subclass of interval_bernstein_polynomial where + This is the subclass of :class:`interval_bernstein_polynomial` where polynomial coefficients are represented using integers. In this integer representation, each coefficient is represented by @@ -443,8 +443,8 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): E (which is a machine integer). These represent the coefficients A*2^n <= c < (A+E)*2^n. - (Note that mk_ibpi is a simple helper function for creating - elements of interval_bernstein_polynomial_integer in doctests.) + (Note that :func:`mk_ibpi is a simple helper` function for creating + elements of :class:`interval_bernstein_polynomial_integer` in doctests.) EXAMPLES:: @@ -455,11 +455,13 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): sage: bp.variations() (0, 0) - sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) + sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, # needs sage.symbolic + ....: error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) degree 5 IBP with 2-bit coefficients - sage: bp - - sage: bp.variations() + sage: bp # needs sage.symbolic + + sage: bp.variations() # needs sage.symbolic (3, 3) """ @@ -1330,7 +1332,7 @@ def intvec_to_doublevec(Vector_integer_dense b, long err): cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): """ - This is the subclass of interval_bernstein_polynomial where + This is the subclass of :class:`interval_bernstein_polynomial` where polynomial coefficients are represented using floating-point numbers. In the floating-point representation, each coefficient is represented @@ -1341,8 +1343,8 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): Note that we always have E1 <= 0 <= E2. Also, each floating-point coefficient has absolute value less than one. - (Note that mk_ibpf is a simple helper function for creating - elements of interval_bernstein_polynomial_float in doctests.) + (Note that :func:`mk_ibpf` is a simple helper function for creating + elements of :class:`interval_bernstein_polynomial_float` in doctests.) EXAMPLES:: @@ -1353,11 +1355,14 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): sage: bp.variations() (0, 0) - sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], lower=1, upper=5/4, usign=1, pos_err=0.2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) + sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], # needs sage.symbolic + ....: lower=1, upper=5/4, usign=1, pos_err=0.2, + ....: scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) degree 5 IBP with floating-point coefficients - sage: bp - - sage: bp.variations() + sage: bp # needs sage.symbolic + + sage: bp.variations() # needs sage.symbolic (3, 3) """ @@ -1560,13 +1565,13 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): INPUT: - - ``mid`` -- where to split the Bernstein basis region; 0 < mid < 1 - - ``msign`` -- default 0 (unknown); the sign of this polynomial at mid + - ``mid`` -- where to split the Bernstein basis region; ``0 < mid < 1`` + - ``msign`` -- default 0 (unknown); the sign of this polynomial at ``mid`` OUTPUT: - ``bp1``, ``bp2`` -- the new interval Bernstein polynomials - - ``ok`` -- a boolean; True if the sign of the original polynomial at mid is known + - ``ok`` -- a boolean; ``True`` if the sign of the original polynomial at ``mid`` is known EXAMPLES:: @@ -1679,7 +1684,7 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): def mk_ibpf(coeffs, lower=0, upper=1, lsign=0, usign=0, neg_err=0, pos_err=0, scale_log2=0, level=0, slope_err=RIF(0)): """ - A simple wrapper for creating interval_bernstein_polynomial_float + A simple wrapper for creating :class:`interval_bernstein_polynomial_float` objects with coercions, defaults, etc. For use in doctests. diff --git a/src/sage/rings/polynomial/refine_root.pyx b/src/sage/rings/polynomial/refine_root.pyx index 082bf810881..32a9ce8c8e4 100644 --- a/src/sage/rings/polynomial/refine_root.pyx +++ b/src/sage/rings/polynomial/refine_root.pyx @@ -38,6 +38,7 @@ def refine_root(ip, ipd, irt, fld): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.rings.polynomial.refine_root import refine_root sage: x = polygen(ZZ) sage: p = x^9 - 1 diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index dea7f1ea027..6ab57e1f7c5 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings r""" Univariate dense skew polynomials over a field with a finite order automorphism diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 9f499430d59..2ae48556880 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -116,12 +116,13 @@ def _minimal_vanishing_polynomial(R, eval_pts): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.skew_polynomial_ring import _minimal_vanishing_polynomial - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob] # optional - sage.rings.finite_rings - sage: eval_pts = [1, t, t^2] # optional - sage.rings.finite_rings - sage: b = _minimal_vanishing_polynomial(S, eval_pts); b # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: eval_pts = [1, t, t^2] + sage: b = _minimal_vanishing_polynomial(S, eval_pts); b doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/13215 for details. @@ -171,24 +172,25 @@ def _lagrange_polynomial(R, eval_pts, values): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.skew_polynomial_ring import _lagrange_polynomial - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - sage: eval_pts = [t , t^2] # optional - sage.rings.finite_rings - sage: values = [3*t^2 + 4*t + 4, 4*t] # optional - sage.rings.finite_rings - sage: d = _lagrange_polynomial(S, eval_pts, values); d # optional - sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: eval_pts = [t , t^2] + sage: values = [3*t^2 + 4*t + 4, 4*t] + sage: d = _lagrange_polynomial(S, eval_pts, values); d x + t - sage: d.multi_point_evaluation(eval_pts) == values # optional - sage.rings.finite_rings + sage: d.multi_point_evaluation(eval_pts) == values True The following restrictions are impossible to satisfy because the evaluation points are linearly dependent over the fixed field of the twisting morphism, and the corresponding values do not match:: - sage: eval_pts = [t, 2*t] # optional - sage.rings.finite_rings - sage: values = [1, 3] # optional - sage.rings.finite_rings - sage: _lagrange_polynomial(S, eval_pts, values) # optional - sage.rings.finite_rings + sage: eval_pts = [t, 2*t] # needs sage.rings.finite_rings + sage: values = [1, 3] + sage: _lagrange_polynomial(S, eval_pts, values) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: the given evaluation points are linearly dependent over the fixed field of the twisting morphism, @@ -275,26 +277,27 @@ def minimal_vanishing_polynomial(self, eval_pts): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - sage: eval_pts = [1, t, t^2] # optional - sage.rings.finite_rings - sage: b = S.minimal_vanishing_polynomial(eval_pts); b # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: eval_pts = [1, t, t^2] + sage: b = S.minimal_vanishing_polynomial(eval_pts); b x^3 + 4 The minimal vanishing polynomial evaluates to 0 at each of the evaluation points:: - sage: eval = b.multi_point_evaluation(eval_pts); eval # optional - sage.rings.finite_rings + sage: eval = b.multi_point_evaluation(eval_pts); eval # needs sage.rings.finite_rings [0, 0, 0] If the evaluation points are linearly dependent over the fixed field of the twisting morphism, then the returned polynomial has lower degree than the number of evaluation points:: - sage: S.minimal_vanishing_polynomial([t]) # optional - sage.rings.finite_rings + sage: S.minimal_vanishing_polynomial([t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t - sage: S.minimal_vanishing_polynomial([t, 3*t]) # optional - sage.rings.finite_rings + sage: S.minimal_vanishing_polynomial([t, 3*t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t """ return _minimal_vanishing_polynomial(_base_ring_to_fraction_field(self), eval_pts) @@ -328,11 +331,12 @@ def lagrange_polynomial(self, points): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - sage: points = [(t, 3*t^2 + 4*t + 4), (t^2, 4*t)] # optional - sage.rings.finite_rings - sage: d = S.lagrange_polynomial(points); d # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: points = [(t, 3*t^2 + 4*t + 4), (t^2, 4*t)] + sage: d = S.lagrange_polynomial(points); d x + t sage: R. = ZZ[] @@ -379,12 +383,13 @@ class SectionSkewPolynomialCenterInjection(Section): TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: sigma = iota.section() # optional - sage.rings.finite_rings - sage: TestSuite(sigma).run(skip=['_test_category']) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: sigma = iota.section() + sage: TestSuite(sigma).run(skip=['_test_category']) """ def _call_(self, x): r""" @@ -392,14 +397,15 @@ def _call_(self, x): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: sigma = iota.section() # optional - sage.rings.finite_rings - sage: sigma(x^3) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: sigma = iota.section() + sage: sigma(x^3) z - sage: sigma(x^2) # optional - sage.rings.finite_rings + sage: sigma(x^2) Traceback (most recent call last): ... ValueError: x^2 is not in the center @@ -426,18 +432,20 @@ def _richcmp_(self, right, op): TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: sigma = iota.section() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: sigma = iota.section() - sage: s = loads(dumps(sigma)) # optional - sage.rings.finite_rings - sage: s == sigma # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: s = loads(dumps(sigma)) + sage: s == sigma True - sage: s != sigma # optional - sage.rings.finite_rings + sage: s != sigma False - sage: s is sigma # optional - sage.rings.finite_rings + sage: s is sigma False """ if op == op_EQ: @@ -454,11 +462,12 @@ class SkewPolynomialCenterInjection(RingHomomorphism): TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: TestSuite(iota).run(skip=['_test_category']) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: TestSuite(iota).run(skip=['_test_category']) """ def __init__(self, domain, codomain, embed, order): r""" @@ -466,10 +475,11 @@ def __init__(self, domain, codomain, embed, order): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: S.convert_map_from(Z) # indirect doctest # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: S.convert_map_from(Z) # indirect doctest Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring """ RingHomomorphism.__init__(self, Hom(domain, codomain)) @@ -484,13 +494,14 @@ def _repr_(self): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: iota # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: iota Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring - sage: iota._repr_() # optional - sage.rings.finite_rings + sage: iota._repr_() 'Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring' """ return "Embedding of the center of %s into this ring" % self._codomain @@ -501,12 +512,13 @@ def _call_(self, x): TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z. = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z. = S.center() + sage: iota = S.convert_map_from(Z) - sage: iota(z) # optional - sage.rings.finite_rings + sage: iota(z) # needs sage.rings.finite_rings x^3 """ k = self._codomain.base_ring() @@ -522,17 +534,19 @@ def _richcmp_(self, right, op): TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) - sage: i = loads(dumps(iota)) # optional - sage.rings.finite_rings - sage: i == iota # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: i = loads(dumps(iota)) + sage: i == iota True - sage: i != iota # optional - sage.rings.finite_rings + sage: i != iota False - sage: i is iota # optional - sage.rings.finite_rings + sage: i is iota False """ if op == op_EQ: @@ -547,12 +561,13 @@ def section(self): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) # optional - sage.rings.finite_rings - sage: Z = S.center() # optional - sage.rings.finite_rings - sage: iota = S.convert_map_from(Z) # optional - sage.rings.finite_rings - sage: sigma = iota.section() # optional - sage.rings.finite_rings - sage: sigma(x^3) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) + sage: Z = S.center() + sage: iota = S.convert_map_from(Z) + sage: sigma = iota.section() + sage: sigma(x^3) z """ return self._section @@ -574,26 +589,28 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) TESTS:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob]; S # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob]; S Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - sage: S.category() # optional - sage.rings.finite_rings + sage: S.category() Category of algebras over Finite Field in t of size 5^3 - sage: TestSuite(S).run() # optional - sage.rings.finite_rings + sage: TestSuite(S).run() # needs sage.rings.finite_rings We check that a call to the method :meth:`sage.rings.polynomial.skew_polynomial_finite_order.SkewPolynomial_finite_order.is_central` does not affect the behaviour of default central variable names:: - sage: k. = GF(7^4) # optional - sage.rings.finite_rings - sage: phi = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', phi] # optional - sage.rings.finite_rings - sage: (x^4).is_central() # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(7^4) + sage: phi = k.frobenius_endomorphism() + sage: S. = k['x', phi] + sage: (x^4).is_central() True - sage: Z. = S.center() # optional - sage.rings.finite_rings - sage: S.center() is Z # optional - sage.rings.finite_rings + sage: Z. = S.center() + sage: S.center() is Z True """ if self.Element is None: @@ -639,57 +656,57 @@ def center(self, name=None, names=None, default=False): EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x',Frob]; S # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob]; S Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - - sage: Z = S.center(); Z # optional - sage.rings.finite_rings + sage: Z = S.center(); Z Univariate Polynomial Ring in z over Finite Field of size 5 - sage: Z.gen() # optional - sage.rings.finite_rings + sage: Z.gen() z We can pass in another variable name:: - sage: S.center(name='y') # optional - sage.rings.finite_rings + sage: S.center(name='y') # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 or use the bracket notation:: - sage: Zy. = S.center(); Zy # optional - sage.rings.finite_rings + sage: Zy. = S.center(); Zy # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 - sage: y.parent() is Zy # optional - sage.rings.finite_rings + sage: y.parent() is Zy # needs sage.rings.finite_rings True A coercion map from the center to the skew polynomial ring is set:: - sage: S.has_coerce_map_from(Zy) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: S.has_coerce_map_from(Zy) True - - sage: P = y + x; P # optional - sage.rings.finite_rings + sage: P = y + x; P x^3 + x - sage: P.parent() # optional - sage.rings.finite_rings + sage: P.parent() Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - sage: P.parent() is S # optional - sage.rings.finite_rings + sage: P.parent() is S True together with a conversion map in the reverse direction:: - sage: Zy(x^6 + 2*x^3 + 3) # optional - sage.rings.finite_rings + sage: Zy(x^6 + 2*x^3 + 3) # needs sage.rings.finite_rings y^2 + 2*y + 3 - sage: Zy(x^2) # optional - sage.rings.finite_rings + sage: Zy(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: x^2 is not in the center Two different skew polynomial rings can share the same center:: - sage: S1. = k['x1', Frob] # optional - sage.rings.finite_rings - sage: S2. = k['x2', Frob] # optional - sage.rings.finite_rings - sage: S1.center() is S2.center() # optional - sage.rings.finite_rings + sage: S1. = k['x1', Frob] # needs sage.rings.finite_rings + sage: S2. = k['x2', Frob] # needs sage.rings.finite_rings + sage: S1.center() is S2.center() # needs sage.rings.finite_rings True .. RUBRIC:: About the default name of the central variable @@ -699,32 +716,33 @@ def center(self, name=None, names=None, default=False): However, a variable name is given the first time this method is called, the given name become the default for the next calls:: - sage: K. = GF(11^3) # optional - sage.rings.finite_rings - sage: phi = K.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: A. = K['X', phi] # optional - sage.rings.finite_rings - - sage: C. = A.center() # first call # optional - sage.rings.finite_rings - sage: C # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(11^3) + sage: phi = K.frobenius_endomorphism() + sage: A. = K['X', phi] + sage: C. = A.center() # first call + sage: C Univariate Polynomial Ring in u over Finite Field of size 11 - sage: A.center() # second call: the variable name is still u # optional - sage.rings.finite_rings + sage: A.center() # second call: the variable name is still u Univariate Polynomial Ring in u over Finite Field of size 11 - sage: A.center() is C # optional - sage.rings.finite_rings + sage: A.center() is C True We can update the default variable name by passing in the argument ``default=True``:: - sage: D. = A.center(default=True) # optional - sage.rings.finite_rings - sage: D # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: D. = A.center(default=True) + sage: D Univariate Polynomial Ring in v over Finite Field of size 11 - sage: A.center() # optional - sage.rings.finite_rings + sage: A.center() Univariate Polynomial Ring in v over Finite Field of size 11 - sage: A.center() is D # optional - sage.rings.finite_rings + sage: A.center() is D True TESTS:: - sage: C. = S.center() # optional - sage.rings.finite_rings + sage: C. = S.center() # needs sage.rings.finite_rings Traceback (most recent call last): ... IndexError: the number of names must equal the number of generators @@ -796,9 +814,9 @@ def __init__(self, base_ring, morphism, derivation, names, sparse, category=None EXAMPLES:: - sage: k. = GF(5^3) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: T. = k['x', Frob]; T # optional - sage.rings.finite_rings + sage: k. = GF(5^3) # needs sage.rings.finite_rings + sage: Frob = k.frobenius_endomorphism() # needs sage.rings.finite_rings + sage: T. = k['x', Frob]; T # needs sage.rings.finite_rings Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ if self.Element is None: @@ -823,21 +841,22 @@ def _new_retraction_map(self, seed=None): TESTS:: - sage: k. = GF(11^4) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - - sage: S._new_retraction_map() # optional - sage.rings.finite_rings - sage: S._matrix_retraction # random # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(11^4) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: S._new_retraction_map() + sage: S._matrix_retraction # random [ 9 4 10 4] We can specify a seed:: - sage: S._new_retraction_map(seed=a) # optional - sage.rings.finite_rings - sage: S._matrix_retraction # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: S._new_retraction_map(seed=a) + sage: S._matrix_retraction [ 0 6 3 10] - sage: S._new_retraction_map(seed=a) # optional - sage.rings.finite_rings - sage: S._matrix_retraction # optional - sage.rings.finite_rings + sage: S._new_retraction_map(seed=a) + sage: S._matrix_retraction [ 0 6 3 10] """ k = self.base_ring() @@ -875,27 +894,27 @@ def _retraction(self, x, newmap=False, seed=None): TESTS:: - sage: k. = GF(11^4) # optional - sage.rings.finite_rings - sage: Frob = k.frobenius_endomorphism() # optional - sage.rings.finite_rings - sage: S. = k['x', Frob] # optional - sage.rings.finite_rings - - sage: S._retraction(a) # random # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: k. = GF(11^4) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: S._retraction(a) # random 6 Note that a retraction map has been automatically created:: - sage: S._matrix_retraction # random # optional - sage.rings.finite_rings + sage: S._matrix_retraction # random # needs sage.rings.finite_rings [ 0 6 3 10] If we call again the method :meth:`_retraction`, the same retraction map is used:: - sage: S._retraction(a) # random # optional - sage.rings.finite_rings + sage: S._retraction(a) # random # needs sage.rings.finite_rings 6 We can specify a seed:: - sage: S._retraction(a^2, seed=a) # random # optional - sage.rings.finite_rings + sage: S._retraction(a^2, seed=a) # random # needs sage.rings.finite_rings 10 """ # Better to return the retraction map but more difficult diff --git a/src/sage/rings/polynomial/symmetric_ideal.py b/src/sage/rings/polynomial/symmetric_ideal.py index 4905e5d87a6..84138cd8975 100644 --- a/src/sage/rings/polynomial/symmetric_ideal.py +++ b/src/sage/rings/polynomial/symmetric_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular """ Symmetric Ideals of Infinite Polynomial Rings @@ -23,13 +24,14 @@ Note that ``I`` is not a symmetric Groebner basis:: - sage: G = R * I.groebner_basis() # optional - sage.combinat - sage: G # optional - sage.combinat + sage: # needs sage.combinat + sage: G = R * I.groebner_basis() + sage: G Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of Infinite polynomial ring in x over Rational Field - sage: Q = R.quotient(G) # optional - sage.combinat - sage: p = x[3]*x[1] + x[2]^2 + 3 # optional - sage.combinat - sage: Q(p) # optional - sage.combinat + sage: Q = R.quotient(G) + sage: p = x[3]*x[1] + x[2]^2 + 3 + sage: Q(p) -2*x_1 + 3 By the second generator of ``G``, variable `x_n` is equal to `x_1` for @@ -37,7 +39,7 @@ equal to `x_1` in ``Q``. Indeed, we have :: - sage: Q(p)*x[2] == Q(p)*x[1]*x[3]*x[5] # optional - sage.combinat + sage: Q(p)*x[2] == Q(p)*x[1]*x[3]*x[5] # needs sage.combinat True """ @@ -118,7 +120,7 @@ class SymmetricIdeal(Ideal_generic): The default ordering is lexicographic. We now compute a Groebner basis:: - sage: J = I.groebner_basis(); J # about 3 seconds # optional - sage.combinat + sage: J = I.groebner_basis(); J # about 3 seconds # needs sage.combinat [x_1*y_2*y_1 + 2*x_1*y_2, x_2*y_2*y_1 + 2*x_2*y_1, x_2*x_1*y_1^2 + 2*x_2*x_1*y_1, x_2*x_1*y_2 - x_2*x_1*y_1] @@ -127,17 +129,18 @@ class SymmetricIdeal(Ideal_generic): four elements. Ideal membership in ``I`` can now be tested by commuting symmetric reduction modulo ``J``:: - sage: I.reduce(J) # optional - sage.combinat + sage: I.reduce(J) # needs sage.combinat Symmetric Ideal (0) of Infinite polynomial ring in x, y over Rational Field The Groebner basis is not point-wise invariant under permutation:: - sage: P = Permutation([2, 1]) # optional - sage.combinat - sage: J[2] # optional - sage.combinat + sage: # needs sage.combinat + sage: P = Permutation([2, 1]) + sage: J[2] x_2*x_1*y_1^2 + 2*x_2*x_1*y_1 - sage: J[2]^P # optional - sage.combinat + sage: J[2]^P x_2*x_1*y_2^2 + 2*x_2*x_1*y_2 - sage: J[2]^P in J # optional - sage.combinat + sage: J[2]^P in J False However, any element of ``J`` has symmetric reduction zero even @@ -145,13 +148,13 @@ class SymmetricIdeal(Ideal_generic): permutations involve higher variable indices than the ones occurring in ``J``:: - sage: [[(p^P).reduce(J) for p in J] for P in Permutations(3)] # optional - sage.combinat + sage: [[(p^P).reduce(J) for p in J] for P in Permutations(3)] # needs sage.combinat [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] Since ``I`` is not a Groebner basis, it is no surprise that it cannot detect ideal membership:: - sage: [p.reduce(I) for p in J] # optional - sage.combinat + sage: [p.reduce(I) for p in J] # needs sage.combinat [0, x_2*y_2*y_1 + 2*x_2*y_1, x_2*x_1*y_1^2 + 2*x_2*x_1*y_1, x_2*x_1*y_2 - x_2*x_1*y_1] Note that we give no guarantee that the computation of a symmetric @@ -164,13 +167,13 @@ class SymmetricIdeal(Ideal_generic): :: sage: I = X * (x[1]) - sage: I * I # optional - sage.combinat + sage: I * I # needs sage.combinat Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I^3 # optional - sage.combinat + sage: I^3 # needs sage.combinat Symmetric Ideal (x_1^3, x_2*x_1^2, x_2^2*x_1, x_3*x_2*x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I * I == X * (x[1]^2) # optional - sage.combinat + sage: I * I == X * (x[1]^2) # needs sage.combinat False """ @@ -235,11 +238,11 @@ def _contains_(self, p): sage: R. = InfinitePolynomialRing(QQ) sage: I = R.ideal([x[1]*x[2] + x[3]]) - sage: I = R * I.groebner_basis() # optional - sage.combinat - sage: I # optional - sage.combinat + sage: I = R * I.groebner_basis() # needs sage.combinat + sage: I # needs sage.combinat Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of Infinite polynomial ring in x over Rational Field - sage: x[2]^2 + x[3] in I # indirect doctest # optional - sage.combinat + sage: x[2]^2 + x[3] in I # indirect doctest # needs sage.combinat True """ try: @@ -260,7 +263,7 @@ def __mul__(self, other): sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1]) - sage: I*I # indirect doctest # optional - sage.combinat + sage: I*I # indirect doctest # needs sage.combinat Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x over Rational Field """ @@ -300,7 +303,7 @@ def __pow__(self, n): sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1]) - sage: I^2 # indirect doctest # optional - sage.combinat + sage: I^2 # indirect doctest # needs sage.combinat Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x over Rational Field """ @@ -329,20 +332,20 @@ def is_maximal(self): sage: R. = InfinitePolynomialRing(QQ) sage: I = R.ideal([x[1] + y[2], x[2] - y[1]]) - sage: I = R * I.groebner_basis(); I # optional - sage.combinat + sage: I = R * I.groebner_basis(); I # needs sage.combinat Symmetric Ideal (y_1, x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I = R.ideal([x[1] + y[2], x[2] - y[1]]) # optional - sage.combinat - sage: I.is_maximal() # optional - sage.combinat + sage: I = R.ideal([x[1] + y[2], x[2] - y[1]]) # needs sage.combinat + sage: I.is_maximal() # needs sage.combinat False The preceding answer is wrong, since it is not the case that ``I`` is given by a symmetric Groebner basis:: - sage: I = R * I.groebner_basis(); I # optional - sage.combinat + sage: I = R * I.groebner_basis(); I # needs sage.combinat Symmetric Ideal (y_1, x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I.is_maximal() # optional - sage.combinat + sage: I.is_maximal() # needs sage.combinat True """ @@ -398,7 +401,7 @@ def reduce(self, I, tailreduce=False): reduction by ``x[2]^2*y[1]`` works, since one can change variable index 1 into 2 and 2 into 3:: - sage: I.reduce([x[2]^2*y[1]]) # optional - sage.combinat + sage: I.reduce([x[2]^2*y[1]]) # needs sage.combinat Symmetric Ideal (y_3*y_1^2) of Infinite polynomial ring in x, y over Rational Field @@ -410,7 +413,7 @@ def reduce(self, I, tailreduce=False): sage: I.reduce(J) Symmetric Ideal (x_3^2*y_1 + y_3*y_1^2) of Infinite polynomial ring in x, y over Rational Field - sage: I.reduce(J, tailreduce=True) # optional - sage.combinat + sage: I.reduce(J, tailreduce=True) # needs sage.combinat Symmetric Ideal (x_3^2*y_1) of Infinite polynomial ring in x, y over Rational Field @@ -455,13 +458,13 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1] + x[2], x[1]*x[2]) - sage: I.interreduction() + sage: I.interreduction() # needs sage.combinat Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field Here, we show the ``report`` option:: - sage: I.interreduction(report=True) # optional - sage.combinat + sage: I.interreduction(report=True) # needs sage.combinat Symmetric interreduction [1/2] > [2/2] :> @@ -480,18 +483,19 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None Last, we demonstrate the use of the optional parameter ``RStrat``:: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy - sage: R = SymmetricReductionStrategy(X) - sage: R - Symmetric Reduction Strategy in Infinite polynomial ring in x over Rational Field - sage: I.interreduction(RStrat=R) # optional - sage.combinat + sage: R = SymmetricReductionStrategy(X); R + Symmetric Reduction Strategy in + Infinite polynomial ring in x over Rational Field + sage: I.interreduction(RStrat=R) # needs sage.combinat Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field - sage: R - Symmetric Reduction Strategy in Infinite polynomial ring in x over Rational Field, modulo + sage: R # needs sage.combinat + Symmetric Reduction Strategy in + Infinite polynomial ring in x over Rational Field, modulo x_1^2, x_2 + x_1 sage: R = SymmetricReductionStrategy(X, [x[1]^2]) - sage: I.interreduction(RStrat=R) + sage: I.interreduction(RStrat=R) # needs sage.combinat Symmetric Ideal (x_2 + x_1) of Infinite polynomial ring in x over Rational Field """ @@ -573,7 +577,7 @@ def interreduced_basis(self): sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1] + x[2], x[1]*x[2]) - sage: I.interreduced_basis() # optional - sage.combinat + sage: I.interreduced_basis() # needs sage.combinat [-x_1^2, x_2 + x_1] """ @@ -620,12 +624,12 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1] + x[2], x[1]*x[2]) - sage: I.symmetrisation() # optional - sage.combinat + sage: I.symmetrisation() # needs sage.combinat Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field - sage: I.symmetrisation(N=3) # optional - sage.combinat + sage: I.symmetrisation(N=3) # needs sage.combinat Symmetric Ideal (-2*x_1) of Infinite polynomial ring in x over Rational Field - sage: I.symmetrisation(N=3, use_full_group=True) # optional - sage.combinat + sage: I.symmetrisation(N=3, use_full_group=True) # needs sage.combinat Symmetric Ideal (-2*x_1) of Infinite polynomial ring in x over Rational Field """ @@ -680,7 +684,7 @@ def symmetric_basis(self): sage: X. = InfinitePolynomialRing(QQ) sage: I = X * (x[1] + x[2], x[1]*x[2]) - sage: I.symmetric_basis() # optional - sage.combinat + sage: I.symmetric_basis() # needs sage.combinat [x_1^2, x_2 + x_1] """ @@ -807,10 +811,10 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= sage: X. = InfinitePolynomialRing(QQ) sage: I1 = X * (x[1] + x[2], x[1]*x[2]) - sage: I1.groebner_basis() # optional - sage.combinat + sage: I1.groebner_basis() # needs sage.combinat [x_1] sage: I2 = X * (y[1]^2*y[3] + y[1]*x[3]) - sage: I2.groebner_basis() # optional - sage.combinat + sage: I2.groebner_basis() # needs sage.combinat [x_1*y_2 + y_2^2*y_1, x_2*y_1 + y_2*y_1^2] Note that a symmetric Groebner basis of a principal ideal is @@ -820,13 +824,13 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= and Hillar, the result is the same, but the computation takes much longer:: - sage: I2.groebner_basis(use_full_group=True) # optional - sage.combinat + sage: I2.groebner_basis(use_full_group=True) # needs sage.combinat [x_1*y_2 + y_2^2*y_1, x_2*y_1 + y_2*y_1^2] Last, we demonstrate how the report on the progress of computations looks like:: - sage: I1.groebner_basis(report=True, reduced=True) # optional - sage.combinat + sage: I1.groebner_basis(report=True, reduced=True) # needs sage.combinat Symmetric interreduction [1/2] > [2/2] :> @@ -899,7 +903,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= sage: R. = InfinitePolynomialRing(ZZ) sage: I = R * [x[1] + x[2], y[1]] - sage: I.groebner_basis() # optional - sage.combinat + sage: I.groebner_basis() # needs sage.combinat Traceback (most recent call last): ... TypeError: The base ring (= Integer Ring) must be a field @@ -908,19 +912,19 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= In an earlier version, the following examples failed:: - sage: X. = InfinitePolynomialRing(GF(5), order='degrevlex') # optional - sage.rings.finite_rings + sage: X. = InfinitePolynomialRing(GF(5), order='degrevlex') sage: I = ['-2*y_0^2 + 2*z_0^2 + 1', ....: '-y_0^2 + 2*y_0*z_0 - 2*z_0^2 - 2*z_0 - 1', ....: 'y_0*z_0 + 2*z_0^2 - 2*z_0 - 1', ....: 'y_0^2 + 2*y_0*z_0 - 2*z_0^2 + 2*z_0 - 2', ....: '-y_0^2 - 2*y_0*z_0 - z_0^2 + y_0 - 1'] * X - sage: I.groebner_basis() # optional - sage.combinat sage.rings.finite_rings + sage: I.groebner_basis() # needs sage.combinat [1] - sage: Y. = InfinitePolynomialRing(GF(3), order='degrevlex', # optional - sage.rings.finite_rings + sage: Y. = InfinitePolynomialRing(GF(3), order='degrevlex', ....: implementation='sparse') sage: I = ['-y_3'] * Y - sage: I.groebner_basis() # optional - sage.combinat sage.rings.finite_rings + sage: I.groebner_basis() # needs sage.combinat [y_1] """ diff --git a/src/sage/rings/polynomial/symmetric_reduction.pyx b/src/sage/rings/polynomial/symmetric_reduction.pyx index 4e5c8b6cf35..6cc00047de8 100644 --- a/src/sage/rings/polynomial/symmetric_reduction.pyx +++ b/src/sage/rings/polynomial/symmetric_reduction.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Symmetric Reduction of Infinite Polynomials @@ -79,15 +80,15 @@ change variable index 1 into 2 and 2 into 3. So, we add this to Infinite polynomial ring in x, y over Rational Field, modulo x_2*y_1^2, x_1*y_2^2 - sage: S.reduce(p) # optional - sage.combinat + sage: S.reduce(p) # needs sage.combinat y_3*y_1 The next example shows that tail reduction is not done, unless it is explicitly advised:: - sage: S.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # optional - sage.combinat + sage: S.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 + 2*x_2*y_1^2 + 3*x_1*y_2^2 - sage: S.tailreduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # optional - sage.combinat + sage: S.tailreduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 However, it is possible to ask for tailreduction already when the @@ -100,7 +101,7 @@ Symmetric Reduction Strategy is created:: x_2*y_1^2, x_1*y_2^2 with tailreduction - sage: S2.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # optional - sage.combinat + sage: S2.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 """ @@ -145,7 +146,7 @@ cdef class SymmetricReductionStrategy: sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1],y[1]^2*y[2]], good_input=True) sage: S.reduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) y_3 + 3*y_2^2*y_1 + 2*y_2*y_1^2 - sage: S.tailreduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) # optional - sage.combinat + sage: S.tailreduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) # needs sage.combinat y_3 """ @@ -439,8 +440,8 @@ cdef class SymmetricReductionStrategy: Note that the first added polynomial will be simplified when adding a suitable second polynomial:: - sage: S.add_generator(x[2] + x[1]) # optional - sage.combinat - sage: S # optional - sage.combinat + sage: S.add_generator(x[2] + x[1]) # needs sage.combinat + sage: S # needs sage.combinat Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo y_3, @@ -450,17 +451,18 @@ cdef class SymmetricReductionStrategy: polynomial. This can be avoided by specifying the optional parameter 'good_input':: - sage: S.add_generator(y[2] + y[1]*x[2]) # optional - sage.combinat - sage: S # optional - sage.combinat + sage: # needs sage.combinat + sage: S.add_generator(y[2] + y[1]*x[2]) + sage: S Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo y_3, x_1*y_1 - y_2, x_2 + x_1 - sage: S.reduce(x[3] + x[2]) # optional - sage.combinat + sage: S.reduce(x[3] + x[2]) -2*x_1 - sage: S.add_generator(x[3] + x[2], good_input=True) # optional - sage.combinat - sage: S # optional - sage.combinat + sage: S.add_generator(x[3] + x[2], good_input=True) + sage: S Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo y_3, @@ -637,7 +639,7 @@ cdef class SymmetricReductionStrategy: sage: S = SymmetricReductionStrategy(X, [y[3]]) sage: S.reduce(y[4]*x[1] + y[1]*x[4]) x_4*y_1 + x_1*y_4 - sage: S.tailreduce(y[4]*x[1] + y[1]*x[4]) # optional - sage.combinat + sage: S.tailreduce(y[4]*x[1] + y[1]*x[4]) # needs sage.combinat x_4*y_1 Last, we demonstrate the 'report' option:: @@ -651,7 +653,7 @@ cdef class SymmetricReductionStrategy: y_3 + y_2, x_2 + y_1, x_1*y_2 + y_4 + y_1^2 - sage: S.tailreduce(x[3] + x[1]*y[3] + x[1]*y[1], report=True) # optional - sage.combinat + sage: S.tailreduce(x[3] + x[1]*y[3] + x[1]*y[1], report=True) # needs sage.combinat T[3]:::> T[3]:> x_1*y_1 - y_2 + y_1^2 - y_1 diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 39c103e215d..a3321cf1bb2 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -272,22 +272,23 @@ EXAMPLES:: - sage: m = matrix(2, [2,3,0,1]); m # optional - sage.modules + sage: # needs sage.modules + sage: m = matrix(2, [2,3,0,1]); m [2 3] [0 1] - sage: T = TermOrder(m); T # optional - sage.modules + sage: T = TermOrder(m); T Matrix term order with matrix [2 3] [0 1] - sage: P. = PolynomialRing(QQ, 2, order=T) # optional - sage.modules - sage: P # optional - sage.modules + sage: P. = PolynomialRing(QQ, 2, order=T) + sage: P Multivariate Polynomial Ring in a, b over Rational Field - sage: a > b # optional - sage.modules + sage: a > b False - sage: a^3 < b^2 # optional - sage.modules + sage: a^3 < b^2 True - sage: S = TermOrder('M(2,3,0,1)') # optional - sage.modules - sage: T == S # optional - sage.modules + sage: S = TermOrder('M(2,3,0,1)') + sage: T == S True Additionally all these monomial orders may be combined to product or block @@ -657,7 +658,7 @@ def __init__(self, name='lex', n=0, force=False): sage: T = TermOrder('degrevlex') sage: R. = PolynomialRing(QQ, order=T) - sage: R._singular_() # optional - sage.libs.singular + sage: R._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 3 @@ -673,7 +674,7 @@ def __init__(self, name='lex', n=0, force=False): sage: S = R.change_ring(order=T2) sage: S == T False - sage: S._singular_() # optional - sage.libs.singular + sage: S._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 3 @@ -683,11 +684,11 @@ def __init__(self, name='lex', n=0, force=False): Check that :trac:`29635` is fixed:: - sage: T = PolynomialRing(GF(101^5), 'u,v,w', # optional - sage.rings.finite_rings + sage: T = PolynomialRing(GF(101^5), 'u,v,w', # needs sage.rings.finite_rings ....: order=TermOrder('degneglex')).term_order() - sage: T.singular_str() # optional - sage.rings.finite_rings + sage: T.singular_str() # needs sage.rings.finite_rings '(a(1:3),ls(3))' - sage: (T + T).singular_str() # optional - sage.rings.finite_rings + sage: (T + T).singular_str() # needs sage.rings.finite_rings '(a(1:3),ls(3),a(1:3),ls(3))' """ if isinstance(name, TermOrder): @@ -930,10 +931,10 @@ def sortkey_matrix(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # optional - sage.rings.number_field - sage: y > x^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # needs sage.rings.number_field + sage: y > x^2 # indirect doctest # needs sage.rings.number_field True - sage: y > x^3 # optional - sage.rings.number_field + sage: y > x^3 # needs sage.rings.number_field False """ return tuple(sum(l * r for l, r in zip(row, f)) @@ -950,10 +951,10 @@ def sortkey_lex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='lex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='lex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field True """ return f @@ -969,10 +970,10 @@ def sortkey_invlex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='invlex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='invlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field True """ return f.reversed() @@ -988,10 +989,10 @@ def sortkey_deglex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='deglex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='deglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field True """ @@ -1008,10 +1009,10 @@ def sortkey_degrevlex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='degrevlex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='degrevlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field True """ @@ -1030,10 +1031,10 @@ def sortkey_neglex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='neglex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='neglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field False """ return tuple(-v for v in f) @@ -1049,10 +1050,10 @@ def sortkey_negdegrevlex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='negdegrevlex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='negdegrevlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field False """ return (-sum(f.nonzero_values(sort=False)), @@ -1069,10 +1070,10 @@ def sortkey_negdeglex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='negdeglex') # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='negdeglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 # optional - sage.rings.number_field + sage: x > 1 # needs sage.rings.number_field False """ return (-sum(f.nonzero_values(sort=False)), f) @@ -1088,10 +1089,10 @@ def sortkey_degneglex(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='degneglex') # optional - sage.rings.number_field - sage: x*y > y*z # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='degneglex') # needs sage.rings.number_field + sage: x*y > y*z # indirect doctest # needs sage.rings.number_field False - sage: x*y > x # optional - sage.rings.number_field + sage: x*y > x # needs sage.rings.number_field True """ return (sum(f.nonzero_values(sort=False)), tuple(-v for v in f)) @@ -1108,10 +1109,10 @@ def sortkey_wdegrevlex(self, f): EXAMPLES:: sage: t = TermOrder('wdegrevlex',(3,2)) - sage: P. = PolynomialRing(QQbar, 2, order=t) # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x^2 > y^3 # optional - sage.rings.number_field + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (sum(l * r for (l, r) in zip(f, self._weights)), @@ -1129,10 +1130,10 @@ def sortkey_wdeglex(self, f): EXAMPLES:: sage: t = TermOrder('wdeglex',(3,2)) - sage: P. = PolynomialRing(QQbar, 2, order=t) # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > y # optional - sage.rings.number_field + sage: x > y # needs sage.rings.number_field True """ return (sum(l * r for (l, r) in zip(f, self._weights)), f) @@ -1149,10 +1150,10 @@ def sortkey_negwdeglex(self, f): EXAMPLES:: sage: t = TermOrder('negwdeglex',(3,2)) - sage: P. = PolynomialRing(QQbar, 2, order=t) # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x^2 > y^3 # optional - sage.rings.number_field + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (-sum(l * r for (l, r) in zip(f, self._weights)), f) @@ -1169,10 +1170,10 @@ def sortkey_negwdegrevlex(self, f): EXAMPLES:: sage: t = TermOrder('negwdegrevlex',(3,2)) - sage: P. = PolynomialRing(QQbar, 2, order=t) # optional - sage.rings.number_field - sage: x > y^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x^2 > y^3 # optional - sage.rings.number_field + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (-sum(l * r for (l, r) in zip(f, self._weights)), @@ -1189,19 +1190,19 @@ def sortkey_block(self, f): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 6, # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 6, # needs sage.rings.number_field ....: order='degrevlex(3),degrevlex(3)') - sage: a > c^4 # indirect doctest # optional - sage.rings.number_field + sage: a > c^4 # indirect doctest # needs sage.rings.number_field False - sage: a > e^4 # optional - sage.rings.number_field + sage: a > e^4 # needs sage.rings.number_field True TESTS: Check that the issue in :trac:`27139` is fixed:: - sage: R. = PolynomialRing(AA, order='lex(2),lex(2)') # optional - sage.rings.number_field - sage: x > y # optional - sage.rings.number_field + sage: R. = PolynomialRing(AA, order='lex(2),lex(2)') # needs sage.rings.number_field + sage: x > y # needs sage.rings.number_field True """ key = tuple() @@ -1225,10 +1226,10 @@ def greater_tuple_matrix(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # optional - sage.rings.number_field - sage: y > x^2 # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # needs sage.rings.number_field + sage: y > x^2 # indirect doctest # needs sage.rings.number_field True - sage: y > x^3 # optional - sage.rings.number_field + sage: y > x^3 # needs sage.rings.number_field False """ for row in self._matrix: @@ -1254,8 +1255,8 @@ def greater_tuple_lex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='lex') # optional - sage.rings.number_field - sage: f = x + y^2; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='lex') # needs sage.rings.number_field + sage: f = x + y^2; f.lm() # indirect doctest # needs sage.rings.number_field x This method is called by the lm/lc/lt methods of @@ -1276,10 +1277,10 @@ def greater_tuple_invlex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='invlex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='invlex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = y + x^2; f.lm() # optional - sage.rings.number_field + sage: f = y + x^2; f.lm() # needs sage.rings.number_field y This method is called by the lm/lc/lt methods of @@ -1300,10 +1301,10 @@ def greater_tuple_deglex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='deglex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='deglex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field x - sage: f = x + y^2*z; f.lm() # optional - sage.rings.number_field + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1326,10 +1327,10 @@ def greater_tuple_degrevlex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='degrevlex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='degrevlex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field x - sage: f = x + y^2*z; f.lm() # optional - sage.rings.number_field + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1352,12 +1353,13 @@ def greater_tuple_negdegrevlex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='negdegrevlex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='negdegrevlex') + sage: f = x + y; f.lm() # indirect doctest x - sage: f = x + x^2; f.lm() # optional - sage.rings.number_field + sage: f = x + x^2; f.lm() x - sage: f = x^2*y*z^2 + x*y^3*z; f.lm() # optional - sage.rings.number_field + sage: f = x^2*y*z^2 + x*y^3*z; f.lm() x*y^3*z This method is called by the lm/lc/lt methods of @@ -1380,12 +1382,13 @@ def greater_tuple_negdeglex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='negdeglex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='negdeglex') + sage: f = x + y; f.lm() # indirect doctest x - sage: f = x + x^2; f.lm() # optional - sage.rings.number_field + sage: f = x + x^2; f.lm() x - sage: f = x^2*y*z^2 + x*y^3*z; f.lm() # optional - sage.rings.number_field + sage: f = x^2*y*z^2 + x*y^3*z; f.lm() x^2*y*z^2 This method is called by the lm/lc/lt methods of @@ -1408,10 +1411,10 @@ def greater_tuple_degneglex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 3, order='degneglex') # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order='degneglex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x + y^2*z; f.lm() # optional - sage.rings.number_field + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1437,11 +1440,11 @@ def greater_tuple_neglex(self,f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 6, # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 6, # needs sage.rings.number_field ....: order='degrevlex(3),degrevlex(3)') - sage: f = a + c^4; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: f = a + c^4; f.lm() # indirect doctest # needs sage.rings.number_field c^4 - sage: g = a + e^4; g.lm() # optional - sage.rings.number_field + sage: g = a + e^4; g.lm() # needs sage.rings.number_field a """ return (f < g) and f or g @@ -1460,10 +1463,10 @@ def greater_tuple_wdeglex(self,f,g): EXAMPLES:: sage: t = TermOrder('wdeglex',(1,2,3)) - sage: P. = PolynomialRing(QQbar, 3, order=t) # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order=t) # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x*y + z; f.lm() # optional - sage.rings.number_field + sage: f = x*y + z; f.lm() # needs sage.rings.number_field x*y This method is called by the lm/lc/lt methods of @@ -1487,10 +1490,10 @@ def greater_tuple_wdegrevlex(self,f,g): EXAMPLES:: sage: t = TermOrder('wdegrevlex',(1,2,3)) - sage: P. = PolynomialRing(QQbar, 3, order=t) # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order=t) # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x + y^2*z; f.lm() # optional - sage.rings.number_field + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1513,13 +1516,14 @@ def greater_tuple_negwdeglex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: t = TermOrder('negwdeglex',(1,2,3)) - sage: P. = PolynomialRing(QQbar, 3, order=t) # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order=t) + sage: f = x + y; f.lm() # indirect doctest x - sage: f = x + x^2; f.lm() # optional - sage.rings.number_field + sage: f = x + x^2; f.lm() x - sage: f = x^3 + z; f.lm() # optional - sage.rings.number_field + sage: f = x^3 + z; f.lm() x^3 This method is called by the lm/lc/lt methods of @@ -1542,13 +1546,14 @@ def greater_tuple_negwdegrevlex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: t = TermOrder('negwdegrevlex',(1,2,3)) - sage: P. = PolynomialRing(QQbar, 3, order=t) # optional - sage.rings.number_field - sage: f = x + y; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 3, order=t) + sage: f = x + y; f.lm() # indirect doctest x - sage: f = x + x^2; f.lm() # optional - sage.rings.number_field + sage: f = x + x^2; f.lm() x - sage: f = x^3 + z; f.lm() # optional - sage.rings.number_field + sage: f = x^3 + z; f.lm() x^3 This method is called by the lm/lc/lt methods of @@ -1574,11 +1579,11 @@ def greater_tuple_block(self, f,g): EXAMPLES:: - sage: P. = PolynomialRing(QQbar, 6, # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, 6, # needs sage.rings.number_field ....: order='degrevlex(3),degrevlex(3)') - sage: f = a + c^4; f.lm() # indirect doctest # optional - sage.rings.number_field + sage: f = a + c^4; f.lm() # indirect doctest # needs sage.rings.number_field c^4 - sage: g = a + e^4; g.lm() # optional - sage.rings.number_field + sage: g = a + e^4; g.lm() # needs sage.rings.number_field a """ n = 0 @@ -1605,8 +1610,8 @@ def tuple_weight(self, f): EXAMPLES:: sage: t = TermOrder('wdeglex',(1,2,3)) - sage: P. = PolynomialRing(QQbar, order=t) # optional - sage.rings.number_field - sage: P.term_order().tuple_weight([3,2,1]) # optional - sage.rings.number_field + sage: P. = PolynomialRing(QQbar, order=t) # needs sage.rings.number_field + sage: P.term_order().tuple_weight([3,2,1]) # needs sage.rings.number_field 10 """ return sum(l*r for (l,r) in zip(f,self._weights)) @@ -1651,12 +1656,12 @@ def singular_str(self): EXAMPLES:: - sage: P = PolynomialRing(GF(127), 10, names='x', # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 10, names='x', ....: order='lex(3),deglex(5),lex(2)') - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.singular_str() # optional - sage.rings.finite_rings + sage: T = P.term_order() + sage: T.singular_str() '(lp(3),Dp(5),lp(2))' - sage: P._singular_() # optional - sage.rings.finite_rings + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 10 @@ -1682,7 +1687,7 @@ def singular_str(self): sage: T = P.term_order() sage: T.singular_str() '(a(1:2),ls(2),a(1:2),ls(2))' - sage: P._singular_() # optional - sage.libs.singular + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1704,7 +1709,7 @@ def singular_str(self): sage: T = TermOrder("degneglex", 2) + TermOrder("degneglex", 2) sage: T._singular_ringorder_column = 0 sage: P = PolynomialRing(QQ, 4, names='x', order=T) - sage: P._singular_() # optional - sage.libs.singular + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1722,7 +1727,7 @@ def singular_str(self): sage: T._singular_ringorder_column = 1 sage: P = PolynomialRing(QQ, 4, names='y', order=T) - sage: P._singular_() # optional - sage.libs.singular + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1740,7 +1745,7 @@ def singular_str(self): sage: T._singular_ringorder_column = 2 sage: P = PolynomialRing(QQ, 4, names='z', order=T) - sage: P._singular_() # optional - sage.libs.singular + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1779,20 +1784,20 @@ def singular_moreblocks(self): EXAMPLES:: - sage: P = PolynomialRing(GF(127), 10, names='x', # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 10, names='x', ....: order='lex(3),deglex(5),lex(2)') - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.singular_moreblocks() # optional - sage.rings.finite_rings + sage: T = P.term_order() + sage: T.singular_moreblocks() 0 - sage: P = PolynomialRing(GF(127), 10, names='x', # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 10, names='x', ....: order='lex(3),degneglex(5),lex(2)') - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.singular_moreblocks() # optional - sage.rings.finite_rings + sage: T = P.term_order() + sage: T.singular_moreblocks() 1 - sage: P = PolynomialRing(GF(127), 10, names='x', # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 10, names='x', ....: order='degneglex(5),degneglex(5)') - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.singular_moreblocks() # optional - sage.rings.finite_rings + sage: T = P.term_order() + sage: T.singular_moreblocks() 2 TESTS: @@ -1822,12 +1827,11 @@ def macaulay2_str(self): EXAMPLES:: - sage: P = PolynomialRing(GF(127), 8, names='x', # optional - sage.rings.finite_rings - ....: order='degrevlex(3),lex(5)') - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.macaulay2_str() # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 8, names='x', order='degrevlex(3),lex(5)') + sage: T = P.term_order() + sage: T.macaulay2_str() '{GRevLex => 3,Lex => 5}' - sage: P._macaulay2_().options()['MonomialOrder'] # optional - macaulay2 # optional - sage.rings.finite_rings + sage: P._macaulay2_().options()['MonomialOrder'] # optional - macaulay2 {MonomialSize => 16 } {GRevLex => {1, 1, 1}} {Lex => 5 } @@ -1843,16 +1847,16 @@ def magma_str(self): EXAMPLES:: - sage: P = PolynomialRing(GF(127), 10, names='x', order='degrevlex') # optional - sage.rings.finite_rings - sage: magma(P) # optional - magma # optional - sage.rings.finite_rings + sage: P = PolynomialRing(GF(127), 10, names='x', order='degrevlex') + sage: magma(P) # optional - magma Polynomial ring of rank 10 over GF(127) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 :: - sage: T = P.term_order() # optional - sage.rings.finite_rings - sage: T.magma_str() # optional - sage.rings.finite_rings + sage: T = P.term_order() + sage: T.magma_str() '"grevlex"' """ return self._magma_str @@ -1884,8 +1888,8 @@ def matrix(self): EXAMPLES:: - sage: t = TermOrder("M(1,2,0,1)") # optional - sage.modules - sage: t.matrix() # optional - sage.modules + sage: t = TermOrder("M(1,2,0,1)") # needs sage.modules + sage: t.matrix() # needs sage.modules [1 2] [0 1] @@ -2165,9 +2169,9 @@ def termorder_from_singular(S): EXAMPLES:: sage: from sage.rings.polynomial.term_order import termorder_from_singular - sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)') # optional - sage.libs.singular + sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)') # needs sage.libs.singular '' - sage: termorder_from_singular(singular) # optional - sage.libs.singular + sage: termorder_from_singular(singular) # needs sage.libs.singular Block term order with blocks: (Matrix term order with matrix [1 2] @@ -2179,7 +2183,8 @@ def termorder_from_singular(S): This information is reflected in ``_singular_ringorder_column`` attribute of the term order. :: - sage: singular.ring(0, '(x,y,z,w)', '(C,dp(2),lp(2))') # optional - sage.libs.singular + sage: # needs sage.libs.singular + sage: singular.ring(0, '(x,y,z,w)', '(C,dp(2),lp(2))') polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -2188,15 +2193,16 @@ def termorder_from_singular(S): // : names x y // block 3 : ordering lp // : names z w - sage: T = termorder_from_singular(singular) # optional - sage.libs.singular - sage: T # optional - sage.libs.singular + sage: T = termorder_from_singular(singular) + sage: T Block term order with blocks: (Degree reverse lexicographic term order of length 2, Lexicographic term order of length 2) - sage: T._singular_ringorder_column # optional - sage.libs.singular + sage: T._singular_ringorder_column 0 - sage: singular.ring(0, '(x,y,z,w)', '(c,dp(2),lp(2))') # optional - sage.libs.singular + sage: # needs sage.libs.singular + sage: singular.ring(0, '(x,y,z,w)', '(c,dp(2),lp(2))') polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -2205,12 +2211,12 @@ def termorder_from_singular(S): // : names x y // block 3 : ordering lp // : names z w - sage: T = termorder_from_singular(singular) # optional - sage.libs.singular - sage: T # optional - sage.libs.singular + sage: T = termorder_from_singular(singular) + sage: T Block term order with blocks: (Degree reverse lexicographic term order of length 2, Lexicographic term order of length 2) - sage: T._singular_ringorder_column # optional - sage.libs.singular + sage: T._singular_ringorder_column 1 TESTS: @@ -2218,16 +2224,17 @@ def termorder_from_singular(S): Check that ``degneglex`` term orders are converted correctly (:trac:`29635`):: - sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:4),ls(4))') # optional - sage.libs.singular - sage: termorder_from_singular(singular).singular_str() # optional - sage.libs.singular + sage: # needs sage.libs.singular + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:4),ls(4))') + sage: termorder_from_singular(singular).singular_str() '(a(1:4),ls(4))' - sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),a(1:2),ls(2))') # optional - sage.libs.singular - sage: termorder_from_singular(singular).singular_str() # optional - sage.libs.singular + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),a(1:2),ls(2))') + sage: termorder_from_singular(singular).singular_str() '(a(1:2),ls(2),a(1:2),ls(2))' - sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),C,a(1:2),ls(2))') # optional - sage.libs.singular - sage: termorder_from_singular(singular).singular_str() # optional - sage.libs.singular + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),C,a(1:2),ls(2))') + sage: termorder_from_singular(singular).singular_str() '(a(1:2),ls(2),C,a(1:2),ls(2))' - sage: PolynomialRing(QQ, 'x,y', order='degneglex')('x^2')._singular_().sage() # optional - sage.libs.singular + sage: PolynomialRing(QQ, 'x,y', order='degneglex')('x^2')._singular_().sage() x^2 """ from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/polynomial/toy_buchberger.py b/src/sage/rings/polynomial/toy_buchberger.py index c70cf1f90aa..4edd2491b6d 100644 --- a/src/sage/rings/polynomial/toy_buchberger.py +++ b/src/sage/rings/polynomial/toy_buchberger.py @@ -23,41 +23,42 @@ Consider Katsura-6 with respect to a ``degrevlex`` ordering. :: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: from sage.rings.polynomial.toy_buchberger import * - sage: P. = PolynomialRing(GF(32003)) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P, 6) # optional - sage.rings.finite_rings - - sage: g1 = buchberger(I) # optional - sage.rings.finite_rings - sage: g2 = buchberger_improved(I) # optional - sage.rings.finite_rings - sage: g3 = I.groebner_basis() # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(32003)) + sage: I = sage.rings.ideal.Katsura(P, 6) + sage: g1 = buchberger(I) + sage: g2 = buchberger_improved(I) + sage: g3 = I.groebner_basis() All algorithms actually compute a Groebner basis:: - sage: Ideal(g1).basis_is_groebner() # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: Ideal(g1).basis_is_groebner() True - sage: Ideal(g2).basis_is_groebner() # optional - sage.rings.finite_rings + sage: Ideal(g2).basis_is_groebner() True - sage: Ideal(g3).basis_is_groebner() # optional - sage.rings.finite_rings + sage: Ideal(g3).basis_is_groebner() True The results are correct:: - sage: Ideal(g1) == Ideal(g2) == Ideal(g3) # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: Ideal(g1) == Ideal(g2) == Ideal(g3) True If ``get_verbose()`` is `\ge 1`, a protocol is provided:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(1) - sage: P. = PolynomialRing(GF(127)) # optional - sage.rings.finite_rings - sage: I = sage.rings.ideal.Katsura(P) # optional - sage.rings.finite_rings + sage: P. = PolynomialRing(GF(127)) + sage: I = sage.rings.ideal.Katsura(P) // sage... ideal - - sage: I # optional - sage.rings.finite_rings + sage: I Ideal (a + 2*b + 2*c - 1, a^2 + 2*b^2 + 2*c^2 - a, 2*a*b + 2*b*c - b) of Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - - sage: buchberger(I) # random # optional - sage.rings.finite_rings + sage: buchberger(I) # random (a + 2*b + 2*c - 1, a^2 + 2*b^2 + 2*c^2 - a) => -2*b^2 - 6*b*c - 6*c^2 + b + 2*c G: set([a + 2*b + 2*c - 1, 2*a*b + 2*b*c - b, a^2 + 2*b^2 + 2*c^2 - a, -2*b^2 - 6*b*c - 6*c^2 + b + 2*c]) @@ -118,17 +119,19 @@ The original Buchberger algorithm performs 15 useless reductions to zero for this example:: - sage: gb = buchberger(I) # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: gb = buchberger(I) ... 15 reductions to zero. The 'improved' Buchberger algorithm in contrast only performs 1 reduction to zero:: - sage: gb = buchberger_improved(I) # optional - sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: gb = buchberger_improved(I) ... 1 reductions to zero. - sage: sorted(gb) # optional - sage.rings.finite_rings + sage: sorted(gb) [a + 2*b + 2*c - 1, b*c + 52*c^2 + 38*b + 25*c, b^2 - 26*c^2 - 51*b + 51*c, c^3 + 22*c^2 - 55*b + 49*c] @@ -193,10 +196,10 @@ def buchberger(F): sage: R. = PolynomialRing(QQ) sage: I = R.ideal([x^2 - z - 1, z^2 - y - 1, x*y^2 - x - 1]) sage: set_verbose(0) - sage: gb = buchberger(I) # optional - sage.libs.singular - sage: gb.is_groebner() # optional - sage.libs.singular + sage: gb = buchberger(I) # needs sage.libs.singular + sage: gb.is_groebner() # needs sage.libs.singular True - sage: gb.ideal() == I # optional - sage.libs.singular + sage: gb.ideal() == I # needs sage.libs.singular True """ G = set(F.gens()) @@ -251,7 +254,7 @@ def buchberger_improved(F): sage: from sage.rings.polynomial.toy_buchberger import buchberger_improved sage: R. = PolynomialRing(QQ) sage: set_verbose(0) - sage: sorted(buchberger_improved(R.ideal([x^4 - y - z, x*y*z - 1]))) # optional - sage.libs.singular + sage: sorted(buchberger_improved(R.ideal([x^4 - y - z, x*y*z - 1]))) # needs sage.libs.singular [x*y*z - 1, x^3 - y^2*z - y*z^2, y^3*z^2 + y^2*z^3 - x^2] """ F = inter_reduction(F.gens()) @@ -421,10 +424,10 @@ def inter_reduction(Q): :: sage: P. = QQ[] - sage: reduced = inter_reduction(set([x^2 - 5*y^2, x^3])) # optional - sage.libs.singular - sage: reduced == set([x*y^2, x^2 - 5*y^2]) # optional - sage.libs.singular + sage: reduced = inter_reduction(set([x^2 - 5*y^2, x^3])) # needs sage.libs.singular + sage: reduced == set([x*y^2, x^2 - 5*y^2]) # needs sage.libs.singular True - sage: reduced == inter_reduction(set([2*(x^2 - 5*y^2), x^3])) # optional - sage.libs.singular + sage: reduced == inter_reduction(set([2*(x^2 - 5*y^2), x^3])) # needs sage.libs.singular True """ if not Q: diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index 660922aaf64..393eb0452b2 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -25,7 +25,7 @@ sage: fx = f.derivative(x) sage: fy = f.derivative(y) sage: I = B.ideal([B(f), B(fx), B(fy)]) - sage: I.groebner_basis() # optional - sage.libs.singular + sage: I.groebner_basis() # needs sage.libs.singular [1] Since the output is 1, we know that there are no generic @@ -102,7 +102,7 @@ sage: I.change_ring(P.change_ring(GF(103))).groebner_basis() [z - 18, y + 8, x + 39] - sage: I.change_ring( P.change_ring(GF(27173681))).groebner_basis() + sage: I.change_ring( P.change_ring(GF(27173681))).groebner_basis() # needs sage.libs.pari [z + 10380032, y + 3186055, x - 536027] Of course, modulo any other prime the Groebner basis is trivial so diff --git a/src/sage/rings/polynomial/toy_variety.py b/src/sage/rings/polynomial/toy_variety.py index 16ccfb6cf8c..5b51dc5eb00 100644 --- a/src/sage/rings/polynomial/toy_variety.py +++ b/src/sage/rings/polynomial/toy_variety.py @@ -100,7 +100,7 @@ def coefficient_matrix(polys): sage: from sage.rings.polynomial.toy_variety import coefficient_matrix sage: R. = PolynomialRing(QQ) - sage: coefficient_matrix([x^2 + 1, y^2 + 1, x*y + 1]) # optional - sage.modules + sage: coefficient_matrix([x^2 + 1, y^2 + 1, x*y + 1]) # needs sage.modules [1 0 0 1] [0 0 1 1] [0 1 0 1] @@ -159,12 +159,12 @@ def is_linearly_dependent(polys) -> bool: sage: R. = PolynomialRing(QQ) sage: B = [x^2 + 1, y^2 + 1, x*y + 1] sage: p = 3*B[0] - 2*B[1] + B[2] - sage: is_linearly_dependent(B + [p]) # optional - sage.modules + sage: is_linearly_dependent(B + [p]) # needs sage.modules True - sage: p = x*B[0] # optional - sage.modules - sage: is_linearly_dependent(B + [p]) # optional - sage.modules + sage: p = x*B[0] + sage: is_linearly_dependent(B + [p]) # needs sage.modules False - sage: is_linearly_dependent([]) # optional - sage.modules + sage: is_linearly_dependent([]) # needs sage.modules False """ if not polys: @@ -203,11 +203,12 @@ def linear_representation(p, polys): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: from sage.rings.polynomial.toy_variety import linear_representation - sage: R. = PolynomialRing(GF(32003)) # optional - sage.rings.finite_rings - sage: B = [x^2 + 1, y^2 + 1, x*y + 1] # optional - sage.rings.finite_rings - sage: p = 3*B[0] - 2*B[1] + B[2] # optional - sage.rings.finite_rings - sage: linear_representation(p, B) # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(32003)) + sage: B = [x^2 + 1, y^2 + 1, x*y + 1] + sage: p = 3*B[0] - 2*B[1] + B[2] + sage: linear_representation(p, B) [3, 32001, 1] """ from sage.matrix.constructor import diagonal_matrix @@ -240,15 +241,16 @@ def triangular_factorization(B, n=-1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(0) sage: from sage.rings.polynomial.toy_variety import triangular_factorization - sage: R. = PolynomialRing(GF(32003)) # optional - sage.rings.finite_rings - sage: p1 = x^2*(x-1)^3*y^2*(z-3)^3 # optional - sage.rings.finite_rings - sage: p2 = z^2 - z # optional - sage.rings.finite_rings - sage: p3 = (x-2)^2*(y-1)^3 # optional - sage.rings.finite_rings - sage: I = R.ideal(p1,p2,p3) # optional - sage.rings.finite_rings - sage: triangular_factorization(I.groebner_basis()) # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(32003)) + sage: p1 = x^2*(x-1)^3*y^2*(z-3)^3 + sage: p2 = z^2 - z + sage: p3 = (x-2)^2*(y-1)^3 + sage: I = R.ideal(p1,p2,p3) + sage: triangular_factorization(I.groebner_basis()) # needs sage.libs.singular [[x^2 - 4*x + 4, y, z], [x^5 - 3*x^4 + 3*x^3 - x^2, y - 1, z], [x^2 - 4*x + 4, y, z - 1], @@ -314,15 +316,16 @@ def elim_pol(B, n=-1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(0) sage: from sage.rings.polynomial.toy_variety import elim_pol - sage: R. = PolynomialRing(GF(32003)) # optional - sage.rings.finite_rings - sage: p1 = x^2*(x-1)^3*y^2*(z-3)^3 # optional - sage.rings.finite_rings - sage: p2 = z^2 - z # optional - sage.rings.finite_rings - sage: p3 = (x-2)^2*(y-1)^3 # optional - sage.rings.finite_rings - sage: I = R.ideal(p1,p2,p3) # optional - sage.rings.finite_rings - sage: elim_pol(I.groebner_basis()) # optional - sage.rings.finite_rings + sage: R. = PolynomialRing(GF(32003)) + sage: p1 = x^2*(x-1)^3*y^2*(z-3)^3 + sage: p2 = z^2 - z + sage: p3 = (x-2)^2*(y-1)^3 + sage: I = R.ideal(p1,p2,p3) + sage: elim_pol(I.groebner_basis()) # needs sage.libs.singular z^2 - z """ # type checking in a probably vain attempt to avoid stupid errors diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 85ad48798eb..54314d538ed 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -101,7 +101,6 @@ from .infinity import infinity, is_Infinite from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -import sage.rings.polynomial.polynomial_element import sage.misc.misc import sage.arith.all as arith import sage.misc.latex @@ -112,9 +111,6 @@ from sage.categories.fields import Fields _Fields = Fields() from sage.misc.derivative import multi_derivative - -Polynomial = sage.rings.polynomial.polynomial_element.Polynomial_generic_dense - from sage.structure.element cimport AlgebraElement, RingElement from sage.structure.richcmp cimport richcmp diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index f8eaf63c934..4ffa5704e83 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -560,6 +560,7 @@ from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.misc.lazy_string import lazy_string +from sage.misc.misc import increase_recursion_limit from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical from sage.structure.sage_object import SageObject from sage.structure.richcmp import (richcmp, richcmp_method, @@ -8543,9 +8544,7 @@ def exactify(self): sage: sys.setrecursionlimit(old_recursion_limit) """ import sys - old_recursion_limit = sys.getrecursionlimit() - sys.setrecursionlimit(old_recursion_limit + 10) - try: + with increase_recursion_limit(10): left = self._left right = self._right left.exactify() @@ -8560,8 +8559,7 @@ def exactify(self): return ANRational(value) else: return ANExtensionElement(gen, value) - finally: - sys.setrecursionlimit(old_recursion_limit) + # These are the functions used to add, subtract, multiply, and divide # algebraic numbers. Basically, we try to compute exactly if both diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 40425b3dbe8..c0e78efaf95 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -12,6 +12,7 @@ Discrete valuations can be created on a variety of rings:: + sage: # needs sage.rings.padics sage: ZZ.valuation(2) 2-adic valuation sage: GaussianIntegers().valuation(3) @@ -34,15 +35,15 @@ :: sage: R. = QQ[] - sage: v = QQ.valuation(2) - sage: w = GaussValuation(R, v) - sage: w.augmentation(x, 3) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: w.augmentation(x, 3) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = 3 ] We can also define discrete pseudo-valuations, i.e., discrete valuations that send more than just zero to infinity:: - sage: w.augmentation(x, infinity) + sage: w.augmentation(x, infinity) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = +Infinity ] """ # **************************************************************************** @@ -71,12 +72,12 @@ class DiscretePseudoValuation(Morphism): EXAMPLES:: - sage: v = ZZ.valuation(2); v # indirect doctest + sage: v = ZZ.valuation(2); v # indirect doctest 2-adic valuation TESTS:: - sage: TestSuite(v).run() # long time + sage: TestSuite(v).run() # long time """ def __init__(self, parent): @@ -84,7 +85,7 @@ def __init__(self, parent): TESTS:: sage: from sage.rings.valuation.valuation import DiscretePseudoValuation - sage: isinstance(ZZ.valuation(2), DiscretePseudoValuation) + sage: isinstance(ZZ.valuation(2), DiscretePseudoValuation) # needs sage.rings.padics True """ @@ -96,6 +97,7 @@ def is_equivalent(self, f, g): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: v.is_equivalent(2, 1) False @@ -124,8 +126,8 @@ def __hash__(self): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: hash(v) == hash(v) # indirect doctest + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: hash(v) == hash(v) # indirect doctest # needs sage.rings.padics True """ @@ -145,8 +147,8 @@ def _hash_(self): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: hash(v) == hash(v) # indirect doctest + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: hash(v) == hash(v) # indirect doctest # needs sage.rings.padics True """ @@ -167,6 +169,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: v == v True @@ -227,8 +230,8 @@ def _le_(self, other): EXAMPLES:: sage: v = valuations.TrivialValuation(QQ) - sage: w = QQ.valuation(2) - sage: v <= w + sage: w = QQ.valuation(2) # needs sage.rings.padics + sage: v <= w # needs sage.rings.padics True """ return other >= self @@ -244,8 +247,8 @@ def _ge_(self, other): EXAMPLES:: sage: v = valuations.TrivialValuation(QQ) - sage: w = QQ.valuation(2) - sage: v >= w + sage: w = QQ.valuation(2) # needs sage.rings.padics + sage: v >= w # needs sage.rings.padics False """ if self == other: @@ -269,7 +272,7 @@ def _test_valuation_inheritance(self, **options): EXAMPLES:: - sage: QQ.valuation(2)._test_valuation_inheritance() + sage: QQ.valuation(2)._test_valuation_inheritance() # needs sage.rings.padics """ tester = self._tester(**options) tester.assertNotEqual(isinstance(self, InfiniteDiscretePseudoValuation), @@ -283,18 +286,18 @@ class InfiniteDiscretePseudoValuation(DiscretePseudoValuation): EXAMPLES:: - sage: v = QQ.valuation(2) + sage: v = QQ.valuation(2) # needs sage.rings.padics sage: R. = QQ[] - sage: v = GaussValuation(R, v) - sage: w = v.augmentation(x, infinity); w # indirect doctest + sage: v = GaussValuation(R, v) # needs sage.rings.padics + sage: w = v.augmentation(x, infinity); w # indirect doctest # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = +Infinity ] TESTS:: sage: from sage.rings.valuation.valuation import InfiniteDiscretePseudoValuation - sage: isinstance(w, InfiniteDiscretePseudoValuation) + sage: isinstance(w, InfiniteDiscretePseudoValuation) # needs sage.rings.padics True - sage: TestSuite(w).run() # long time + sage: TestSuite(w).run() # long time # needs sage.rings.padics """ def is_discrete_valuation(self): @@ -303,6 +306,7 @@ def is_discrete_valuation(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: R. = QQ[] sage: v = GaussValuation(R, v) @@ -341,7 +345,8 @@ def is_negative_pseudo_valuation(self): EXAMPLES:: sage: R. = QQ[] - sage: v = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x, infinity) + sage: u = GaussValuation(R, valuations.TrivialValuation(QQ)) + sage: v = u.augmentation(x, infinity) sage: v.is_negative_pseudo_valuation() False sage: K. = FunctionField(QQ) @@ -359,18 +364,18 @@ class DiscreteValuation(DiscretePseudoValuation): EXAMPLES:: - sage: v = QQ.valuation(2) + sage: v = QQ.valuation(2) # needs sage.rings.padics sage: R. = QQ[] - sage: v = GaussValuation(R, v) - sage: w = v.augmentation(x, 1337); w # indirect doctest + sage: v = GaussValuation(R, v) # needs sage.rings.padics + sage: w = v.augmentation(x, 1337); w # indirect doctest # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = 1337 ] TESTS:: sage: from sage.rings.valuation.valuation import DiscreteValuation - sage: isinstance(w, DiscreteValuation) + sage: isinstance(w, DiscreteValuation) # needs sage.rings.padics True - sage: TestSuite(w).run() # long time + sage: TestSuite(w).run() # long time # needs sage.rings.padics """ def is_discrete_valuation(self): @@ -431,12 +436,14 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: R. = QQ[] sage: v.mac_lane_approximants(x^2 + 1) [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]] sage: v.mac_lane_approximants(x^2 + 1, required_precision=infinity) - [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, v(x^2 + 1) = +Infinity ]] + [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, + v(x^2 + 1) = +Infinity ]] sage: v.mac_lane_approximants(x^2 + x + 1) [[ Gauss valuation induced by 2-adic valuation, v(x^2 + x + 1) = +Infinity ]] @@ -444,13 +451,13 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru factor `x + 1` and an approximate factor `x + 1` (which is an approximation to `x - 1`):: - sage: v.mac_lane_approximants(x^2 - 1) + sage: v.mac_lane_approximants(x^2 - 1) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ], [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ]] However, it needs to be squarefree:: - sage: v.mac_lane_approximants(x^2) + sage: v.mac_lane_approximants(x^2) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: G must be squarefree @@ -459,19 +466,20 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Some difficult cases provided by Mark van Hoeij:: + sage: # needs sage.rings.finite_rings sage: k = GF(2) sage: K. = FunctionField(k) sage: R. = K[] sage: F = y^21 + x*y^20 + (x^3 + x + 1)*y^18 + (x^3 + 1)*y^17 + (x^4 + x)*y^16 + (x^7 + x^6 + x^3 + x + 1)*y^15 + x^7*y^14 + (x^8 + x^7 + x^6 + x^4 + x^3 + 1)*y^13 + (x^9 + x^8 + x^4 + 1)*y^12 + (x^11 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2)*y^11 + (x^12 + x^9 + x^8 + x^7 + x^5 + x^3 + x + 1)*y^10 + (x^14 + x^13 + x^10 + x^9 + x^8 + x^7 + x^6 + x^3 + x^2 + 1)*y^9 + (x^13 + x^9 + x^8 + x^6 + x^4 + x^3 + x)*y^8 + (x^16 + x^15 + x^13 + x^12 + x^11 + x^7 + x^3 + x)*y^7 + (x^17 + x^16 + x^13 + x^9 + x^8 + x)*y^6 + (x^17 + x^16 + x^12 + x^7 + x^5 + x^2 + x + 1)*y^5 + (x^19 + x^16 + x^15 + x^12 + x^6 + x^5 + x^3 + 1)*y^4 + (x^18 + x^15 + x^12 + x^10 + x^9 + x^7 + x^4 + x)*y^3 + (x^22 + x^21 + x^20 + x^18 + x^13 + x^12 + x^9 + x^8 + x^7 + x^5 + x^4 + x^3)*y^2 + (x^23 + x^22 + x^20 + x^17 + x^15 + x^14 + x^12 + x^9)*y + x^25 + x^23 + x^19 + x^17 + x^15 + x^13 + x^11 + x^5 sage: x = K._ring.gen() sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x,1)) - sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed + sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed [[ Gauss valuation induced by (x)-adic valuation, v(y + x + 1) = 3/2 ], [ Gauss valuation induced by (x)-adic valuation, v(y) = 1 ], [ Gauss valuation induced by (x)-adic valuation, v(y) = 4/3 ], [ Gauss valuation induced by (x)-adic valuation, v(y^15 + y^13 + y^12 + y^10 + y^9 + y^8 + y^4 + y^3 + y^2 + y + 1) = 1 ]] sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x+1,1)) - sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed + sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed [[ Gauss valuation induced by (x + 1)-adic valuation, v(y + x^2 + 1) = 7/2 ], [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 3/4 ], [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 7/2 ], @@ -487,6 +495,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Cases with trivial residue field extensions:: + sage: # needs sage.rings.padics sage: K. = FunctionField(QQ) sage: S. = K[] sage: F = y^2 - x^2 - x^3 - 3 @@ -499,46 +508,49 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Over a complete base field:: - sage: k=Qp(2,10) - sage: v = k.valuation() + sage: k = Qp(2,10) # needs sage.rings.padics + sage: v = k.valuation() # needs sage.rings.padics - sage: R.=k[] + sage: # needs sage.rings.padics + sage: R. = k[] sage: G = x sage: v.mac_lane_approximants(G) [Gauss valuation induced by 2-adic valuation] - sage: v.mac_lane_approximants(G, required_precision = infinity) + sage: v.mac_lane_approximants(G, required_precision=infinity) [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = +Infinity ]] - sage: G = x^2 + 1 - sage: v.mac_lane_approximants(G) + sage: G = x^2 + 1 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2 ]] - sage: v.mac_lane_approximants(G, required_precision = infinity) - [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2, v((1 + O(2^10))*x^2 + 1 + O(2^10)) = +Infinity ]] + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics + [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2, + v((1 + O(2^10))*x^2 + 1 + O(2^10)) = +Infinity ]] - sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2 - sage: v.mac_lane_approximants(G) + sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4 ]] - sage: v.mac_lane_approximants(G, required_precision=infinity) - [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + 2 + O(2^11)) = +Infinity ]] + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics + [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, + v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + 2 + O(2^11)) = +Infinity ]] The factorization of primes in the Gaussian integers can be read off the Mac Lane approximants:: - sage: v0 = QQ.valuation(2) + sage: v0 = QQ.valuation(2) # needs sage.rings.padics sage: R. = QQ[] sage: G = x^2 + 1 - sage: v0.mac_lane_approximants(G) + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]] - sage: v0 = QQ.valuation(3) - sage: v0.mac_lane_approximants(G) + sage: v0 = QQ.valuation(3) # needs sage.rings.padics + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 3-adic valuation, v(x^2 + 1) = +Infinity ]] - sage: v0 = QQ.valuation(5) - sage: v0.mac_lane_approximants(G) + sage: v0 = QQ.valuation(5) # needs sage.rings.padics + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ], [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]] - sage: v0.mac_lane_approximants(G, required_precision = 10) + sage: v0.mac_lane_approximants(G, required_precision=10) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v(x + 3116/237) = 10 ], [ Gauss valuation induced by 5-adic valuation, v(x - 3116/237) = 10 ]] @@ -546,9 +558,10 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru `\QQ[x]/(x^2+1)`, 5 factors `-(x - 2)(x + 2)`, this behaviour can be read off the Mac Lane approximants:: - sage: k=Qp(5,4) + sage: # needs sage.rings.padics + sage: k = Qp(5,4) sage: v = k.valuation() - sage: R.=k[] + sage: R. = k[] sage: G = x^2 + 1 sage: v1,v2 = v.mac_lane_approximants(G); v1,v2 ([ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + O(5^4)) = 1 ], @@ -559,22 +572,23 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Note how the latter give a better approximation to the factors of `x^2 + 1`:: - sage: v1.phi() * v2.phi() - G + sage: v1.phi() * v2.phi() - G # needs sage.rings.padics O(5^4)*x^2 + (5 + O(5^4))*x + 5 + O(5^4) - sage: w1.phi() * w2.phi() - G + sage: w1.phi() * w2.phi() - G # needs sage.rings.padics O(5^4)*x^2 + (5^2 + O(5^4))*x + 5^3 + O(5^4) In this example, the process stops with a factorization of `x^2 + 1`:: - sage: v.mac_lane_approximants(G, required_precision=infinity) + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) = +Infinity ], [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) = +Infinity ]] This obviously cannot happen over the rationals where we only get an approximate factorization:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(5) - sage: R.=QQ[] + sage: R. = QQ[] sage: G = x^2 + 1 sage: v.mac_lane_approximants(G) [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ], @@ -586,9 +600,10 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Initial versions ran into problems with the trivial residue field extensions in this case:: - sage: K = Qp(3, 20, print_mode='digits') - sage: R. = K[] + sage: K = Qp(3, 20, print_mode='digits') # needs sage.rings.padics + sage: R. = K[] # needs sage.rings.padics + sage: # needs sage.rings.padics sage: alpha = T^3/4 sage: G = 3^3*T^3*(alpha^4 - alpha)^2 - (4*alpha^3 - 1)^3 sage: G = G/G.leading_coefficient() @@ -598,13 +613,14 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru A similar example:: sage: R. = QQ[] - sage: v = QQ.valuation(3) - sage: G = (x^3 + 3)^3 - 81 - sage: v.mac_lane_approximants(G) + sage: v = QQ.valuation(3) # needs sage.rings.padics + sage: G = (x^3 + 3)^3 - 81 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 3-adic valuation, v(x) = 1/3, v(x^3 + 3*x + 3) = 13/9 ]] Another problematic case:: + sage: # needs sage.rings.number_field sage.rings.padics sage: R. = QQ[] sage: Delta = x^12 + 20*x^11 + 154*x^10 + 664*x^9 + 1873*x^8 + 3808*x^7 + 5980*x^6 + 7560*x^5 + 7799*x^4 + 6508*x^3 + 4290*x^2 + 2224*x + 887 sage: K. = NumberField(x^6 + 108) @@ -615,7 +631,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru 1 sage: vK(theta) 1/3 - sage: G=Delta.change_ring(K) + sage: G = Delta.change_ring(K) sage: vK.mac_lane_approximants(G) [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + 3*theta + 1) = 3/2 ], [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + theta + 1) = 3/2 ], @@ -624,8 +640,8 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru An easy case that produced the wrong error at some point:: sage: R. = QQ[] - sage: v = QQ.valuation(2) - sage: v.mac_lane_approximants(x^2 - 1/2) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v.mac_lane_approximants(x^2 - 1/2) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: G must be integral @@ -634,24 +650,29 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru :: + sage: # needs sage.rings.padics sage: R = ZpFM(3, 7, print_mode='terse') sage: S. = R[] sage: v = R.valuation() sage: f = x^4 + 234 - sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet + sage: len(v.mac_lane_approximants(f, # is_squarefree() is not properly implemented yet + ....: assume_squarefree=True)) 2 :: + sage: # needs sage.rings.padics sage: R = ZpFM(2, 50, print_mode='terse') sage: S. = R[] sage: f = (x^32 + 16)*(x^32 + 16 + 2^16*x^2) + 2^34 sage: v = R.valuation() - sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet + sage: len(v.mac_lane_approximants(f, # is_squarefree() is not properly implemented yet + ....: assume_squarefree=True)) 2 A case that triggered an assertion at some point:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(3) sage: R. = QQ[] sage: f = x^36 + 60552000*x^33 + 268157412*x^30 + 173881701*x^27 + 266324841*x^24 + 83125683*x^21 + 111803814*x^18 + 31925826*x^15 + 205726716*x^12 +17990262*x^9 + 351459648*x^6 + 127014399*x^3 + 359254116 @@ -784,10 +805,10 @@ def _pow(self, x, e, error): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: v._pow(2, 2, error=4) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v._pow(2, 2, error=4) # needs sage.rings.padics 4 - sage: v._pow(2, 1000, error=4) + sage: v._pow(2, 1000, error=4) # needs sage.rings.padics 0 """ @@ -817,58 +838,66 @@ def mac_lane_approximant(self, G, valuation, approximants=None): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: R. = QQ[] - sage: G = x^2 + 1 + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: R. = QQ[] # needs sage.rings.padics + sage: G = x^2 + 1 # needs sage.rings.padics We can select an approximant by approximating it:: - sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] As long as this is the only matching approximant, the approximation can be very coarse:: - sage: w = GaussValuation(R, v) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] Or it can be very specific:: - sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2).augmentation(G, infinity) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2).augmentation(G, infinity) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] But it must be an approximation of an approximant:: - sage: w = GaussValuation(R, v).augmentation(x, 1/2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x, 1/2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation [ Gauss valuation induced by 2-adic valuation, v(x) = 1/2 ] is not an approximant for a valuation which extends 2-adic valuation with respect to x^2 + 1 since the valuation of x^2 + 1 does not increase in every step + ValueError: The valuation + [ Gauss valuation induced by 2-adic valuation, v(x) = 1/2 ] is + not an approximant for a valuation which extends 2-adic valuation + with respect to x^2 + 1 since the valuation of x^2 + 1 + does not increase in every step The ``valuation`` must single out one approximant:: - sage: G = x^2 - 1 - sage: w = GaussValuation(R, v) - sage: v.mac_lane_approximant(G, w) + sage: G = x^2 - 1 # needs sage.rings.padics + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 2-adic valuation does not approximate a unique extension of 2-adic valuation with respect to x^2 - 1 + ValueError: The valuation Gauss valuation induced by 2-adic valuation + does not approximate a unique extension of 2-adic valuation + with respect to x^2 - 1 - sage: w = GaussValuation(R, v).augmentation(x + 1, 1) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] does not approximate a unique extension of 2-adic valuation with respect to x^2 - 1 + ValueError: The valuation + [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] does not + approximate a unique extension of 2-adic valuation with respect to x^2 - 1 - sage: w = GaussValuation(R, v).augmentation(x + 1, 2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ] - sage: w = GaussValuation(R, v).augmentation(x + 3, 2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 3, 2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] """ @@ -928,24 +957,26 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No EXAMPLES:: - sage: k=Qp(5,4) + sage: # needs sage.rings.padics + sage: k = Qp(5,4) sage: v = k.valuation() - sage: R.=k[] + sage: R. = k[] sage: G = x^2 + 1 sage: v.montes_factorization(G) - ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) + ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) + * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) The computation might not terminate over incomplete fields (in particular because the factors can not be represented there):: sage: R. = QQ[] - sage: v = QQ.valuation(2) - sage: v.montes_factorization(x^6 - 1) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v.montes_factorization(x^6 - 1) # needs sage.rings.padics (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1) - sage: v.montes_factorization(x^7 - 1) # not tested, does not terminate + sage: v.montes_factorization(x^7 - 1) # not tested # needs sage.rings.padics - sage: v.montes_factorization(x^7 - 1, required_precision=5) + sage: v.montes_factorization(x^7 - 1, required_precision=5) # needs sage.rings.padics (x - 1) * (x^3 - 5*x^2 - 6*x - 1) * (x^3 + 6*x^2 + 5*x - 1) TESTS: @@ -955,6 +986,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No In this example, ``f`` factors as three factors of degree 50 over an unramified extension:: + sage: # needs sage.rings.padics sage: R. = ZqFM(125) sage: S. = R[] sage: f = (x^6+2)^25 + 5 @@ -964,6 +996,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No In this case, ``f`` factors into degrees 1, 2, and 5 over a totally ramified extension:: + sage: # needs sage.rings.padics sage: R = Zp(5) sage: S. = R[] sage: R. = R.extension(w^3 + 5) @@ -1033,8 +1066,8 @@ class MacLaneApproximantNode(): TESTS:: - sage: v = ZZ.valuation(3) - sage: v.extension(GaussianIntegers()) # indirect doctest + sage: v = ZZ.valuation(3) # needs sage.rings.padics + sage: v.extension(GaussianIntegers()) # indirect doctest # needs sage.rings.padics 3-adic valuation """ @@ -1043,8 +1076,8 @@ def __init__(self, valuation, parent, ef, principal_part_bound, coefficients, va TESTS:: sage: from sage.rings.valuation.valuation import MacLaneApproximantNode - sage: node = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) - sage: TestSuite(node).run() + sage: node = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) # needs sage.rings.padics + sage: TestSuite(node).run() # needs sage.rings.padics """ self.valuation = valuation @@ -1061,6 +1094,7 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.rings.padics sage: from sage.rings.valuation.valuation import MacLaneApproximantNode sage: n = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) sage: m = MacLaneApproximantNode(QQ.valuation(3), None, 1, None, None, None) @@ -1070,7 +1104,7 @@ def __eq__(self, other): True """ - if type(self) != type(other): + if type(self) is not type(other): return False return (self.valuation, self.parent, self.ef, self.principal_part_bound, self.coefficients, self.valuations, self.forced_leaf) == (other.valuation, other.parent, other.ef, other.principal_part_bound, other.coefficients, other.valuations, other.forced_leaf) @@ -1080,6 +1114,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.rings.padics sage: from sage.rings.valuation.valuation import MacLaneApproximantNode sage: n = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) sage: m = MacLaneApproximantNode(QQ.valuation(3), None, 1, None, None, None) diff --git a/src/sage/rings/valuation/valuations_catalog.py b/src/sage/rings/valuation/valuations_catalog.py index 69e064a10c1..64effaf13a6 100644 --- a/src/sage/rings/valuation/valuations_catalog.py +++ b/src/sage/rings/valuation/valuations_catalog.py @@ -1,5 +1,9 @@ -from sage.rings.padics.padic_valuation import pAdicValuation -from sage.rings.function_field.valuation import FunctionFieldValuation -from .gauss_valuation import GaussValuation -from .trivial_valuation import TrivialDiscretePseudoValuation, TrivialPseudoValuation, TrivialValuation -from .limit_valuation import LimitValuation +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.rings.padics.padic_valuation', 'pAdicValuation') +lazy_import('sage.rings.function_field.valuation', 'FunctionFieldValuation') +lazy_import('sage.rings.valuation.gauss_valuation', 'GaussValuation') +lazy_import('sage.rings.valuation.trivial_valuation', ['TrivialDiscretePseudoValuation', 'TrivialPseudoValuation', 'TrivialValuation']) +lazy_import('sage.rings.valuation.limit_valuation', 'LimitValuation') + +del lazy_import diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 2d09a660d65..02d2021b2fb 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -326,7 +326,7 @@ from sage.combinat.set_partition import SetPartitions from sage.combinat.vector_partition import IntegerVectorsIterator from sage.functions.log import exp -from sage.functions.other import binomial +from sage.arith.misc import binomial from sage.geometry.polyhedron.constructor import Polyhedron from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index 770295962dd..ca210ca6e2b 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -23,7 +23,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import sage.rings.all as rings +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.rational_field import RationalField import sage.rings.abc from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing @@ -421,7 +423,7 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, x = x.lhs() - x.rhs() if isinstance(parent(x), sage.rings.abc.SymbolicRing): - x = x._polynomial_(rings.QQ['x', 'y']) + x = x._polynomial_(QQ['x', 'y']) if isinstance(x, MPolynomial): if y is None: @@ -448,8 +450,8 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, if R is None: R = Sequence(x).universe() - if R in (rings.ZZ, int): - R = rings.QQ + if R in (ZZ, int): + R = QQ return (R, tuple(R(a) for a in x)), kwds @@ -471,7 +473,7 @@ def create_object(self, version, key, **kwds): """ R, x = key - if R is rings.QQ: + if R is QQ: from .ell_rational_field import EllipticCurve_rational_field return EllipticCurve_rational_field(x, **kwds) elif isinstance(R, NumberField): @@ -597,7 +599,7 @@ def EllipticCurve_from_c4c6(c4, c6): try: K = c4.parent() except AttributeError: - K = rings.RationalField() + K = RationalField() if K not in _Fields: K = K.fraction_field() return EllipticCurve([-K(c4)/K(48), -K(c6)/K(864)]) @@ -692,7 +694,7 @@ def coefficients_from_j(j, minimal_twist=True): try: K = j.parent() except AttributeError: - K = rings.RationalField() + K = RationalField() if K not in _Fields: K = K.fraction_field() @@ -708,7 +710,7 @@ def coefficients_from_j(j, minimal_twist=True): else: return Sequence([0, j, 0, 0, -j**2], universe=K) - if K is rings.RationalField(): + if K is RationalField(): # we construct the minimal twist, i.e. the curve with minimal # conductor with this j_invariant: if j == 0: diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 59c38c633e8..5fc182c8954 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -29,7 +29,8 @@ from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport * from cypari2.paridecl cimport (GEN, cgetg, t_POL, set_gel, gel, stoi, lg, - evalvarn, evalsigne, Z_issquare, hyperellratpoints) + evalvarn, evalsigne, Z_issquare, + hyperellratpoints) from cypari2.stack cimport clear_stack from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t @@ -44,7 +45,7 @@ cdef unsigned long valuation(mpz_t a, mpz_t p): cdef mpz_t aa cdef unsigned long v mpz_init(aa) - v = mpz_remove(aa,a,p) + v = mpz_remove(aa, a, p) mpz_clear(aa) return v @@ -92,22 +93,25 @@ cdef int padic_square(mpz_t a, mpz_t p): cdef mpz_t aa cdef int result - if mpz_sgn(a) == 0: return 1 + if mpz_sgn(a) == 0: + return 1 - v = valuation(a,p) - if v & 1: return 0 + v = valuation(a, p) + if v & 1: + return 0 - mpz_init_set(aa,a) + mpz_init_set(aa, a) while v: v -= 1 mpz_divexact(aa, aa, p) - if mpz_cmp_ui(p, 2)==0: - result = (mpz_fdiv_ui(aa, 8) == 1) + if mpz_cmp_ui(p, 2) == 0: + result = bool(mpz_fdiv_ui(aa, 8) == 1) else: - result = (mpz_legendre(aa, p) == 1) + result = bool(mpz_legendre(aa, p) == 1) mpz_clear(aa) return result + def test_padic_square(a, p): """ Doctest function for cdef int padic_square(mpz_t, unsigned long). @@ -117,13 +121,14 @@ def test_padic_square(a, p): sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps sage: for i in [1..300]: ....: for p in prime_range(100): - ....: if not Qp(p)(i).is_square()==bool(ps(i,p)): + ....: if Qp(p)(i).is_square() != bool(ps(i,p)): ....: print(i, p) """ cdef Integer A = Integer(a) cdef Integer P = Integer(p) return padic_square(A.value, P.value) + cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -147,7 +152,7 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, if padic_square(g_of_x, p): mpz_clear(g_of_x) - return +1 # soluble + return +1 # soluble mpz_init_set(g_prime_of_x, x) mpz_mul(g_prime_of_x, a, x) @@ -159,17 +164,21 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_add(g_prime_of_x, g_prime_of_x, d) lambd = valuation(g_of_x, p) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble - elif lambd >= 2*nu and mu >= nu: result = 0 # undecided + if lambd > 2*mu: + result = 1 # soluble + elif lambd >= 2*nu and mu >= nu: + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -209,28 +218,33 @@ cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, while mpz_even_p(g_of_x_odd_part): mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, 2) g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, 4) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble + if lambd > 2*mu: + result = 1 # soluble elif nu > mu: - if lambd >= mu+nu: result = +1 # soluble + if lambd >= mu+nu: + result = 1 # soluble elif lambd+1 == mu+nu and (lambd & 1) == 0: - result = +1 # soluble + result = 1 # soluble elif lambd+2 == mu+nu and (lambd & 1) == 0 and g_of_x_odd_part_mod_4 == 1: - result = +1 # soluble + result = 1 # soluble else: # nu <= mu - if lambd >= 2*nu: result = 0 # undecided + if lambd >= 2*nu: + result = 0 # undecided elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x_k, mpz_t p, unsigned long k): """ @@ -245,9 +259,9 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t s if mpz_cmp_ui(p, 2) == 0: - code = lemma7(a,b,c,d,e,x_k,p,k) + code = lemma7(a, b, c, d, e, x_k, p, k) else: - code = lemma6(a,b,c,d,e,x_k,p,k) + code = lemma6(a, b, c, d, e, x_k, p, k) if code == 1: return 1 if code == -1: @@ -260,11 +274,12 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_pow_ui(s, p, k) mpz_mul_ui(s, s, t) mpz_add(s, s, x_k) - code = Zp_soluble_BSD(a,b,c,d,e,s,p,k+1) + code = Zp_soluble_BSD(a, b, c, d, e, s, p, k+1) t += 1 mpz_clear(s) return code + cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp, unsigned long pp_ui, nmod_poly_factor_t f_factzn, nmod_poly_t f, @@ -288,24 +303,28 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui)) nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui)) @@ -389,7 +408,7 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -463,8 +482,10 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -515,36 +536,50 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t aa, bb, cc, dd, ee cdef mpz_t aaa, bbb, ccc, ddd, eee cdef mpz_t qq, rr, ss, tt - cdef Integer A,B,C,D,E,P + cdef Integer A, B, C, D, E, P # Step 0: divide out all common p from the quartic v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E - mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E + mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial f_factzn = f.factor() result = 0 for factor, exponent in f_factzn: @@ -627,7 +662,7 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -683,10 +718,20 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, return result else: # Step II in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic f_factzn = f.factor() has_roots = 0 @@ -702,8 +747,10 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_set(roots[j], A.value) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -749,25 +796,27 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, locally soluble at p. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e cdef nmod_poly_t f nmod_poly_init(f, P) - mpz_init_set(a,A) - mpz_init_set(b,B) - mpz_init_set(c,C) - mpz_init_set(d,D) - mpz_init_set(e,E) + mpz_init_set(a, A) + mpz_init_set(b, B) + mpz_init_set(c, C) + mpz_init_set(d, D) + mpz_init_set(e, E) - if Zp_soluble_siksek(a,b,c,d,e,p,P,f_factzn, f, f1, linear): + if Zp_soluble_siksek(a, b, c, d, e, + p, P, f_factzn, f, f1, linear): result = 1 else: - mpz_set(a,A) - mpz_set(b,B) - mpz_set(c,C) - mpz_set(d,D) - mpz_set(e,E) - if Zp_soluble_siksek(e,d,c,b,a,p,P,f_factzn, f, f1, linear): + mpz_set(a, A) + mpz_set(b, B) + mpz_set(c, C) + mpz_set(d, D) + mpz_set(e, E) + if Zp_soluble_siksek(e, d, c, b, a, + p, P,f_factzn, f, f1, linear): result = 1 mpz_clear(a) @@ -778,6 +827,7 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, nmod_poly_clear(f) return result + cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear): """ @@ -786,7 +836,7 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, FLINT. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e mpz_init_set(a,A) mpz_init_set(b,B) @@ -794,7 +844,8 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_init_set(d,D) mpz_init_set(e,E) - if Zp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear): + if Zp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear): result = 1 else: mpz_set(a,A) @@ -820,9 +871,11 @@ cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): cdef mpz_t zero cdef int result = 0 mpz_init_set_ui(zero, 0) - if Zp_soluble_BSD(a,b,c,d,e,zero,p,0): + if Zp_soluble_BSD(a, b, c, d, e, + zero, p, 0): result = 1 - elif Zp_soluble_BSD(e,d,c,b,a,zero,p,1): + elif Zp_soluble_BSD(e, d, c, b, a, + zero, p, 1): result = 1 mpz_clear(zero) return result @@ -843,17 +896,20 @@ cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): if mpz_fits_ulong_p(p): nmod_poly_factor_init(f_factzn) pp = mpz_get_ui(p) - sik_sol = Qp_soluble_siksek(a,b,c,d,e,p,pp,f_factzn,f1,linear) + sik_sol = Qp_soluble_siksek(a, b, c, d, e, + p, pp, f_factzn, f1,linear) nmod_poly_factor_clear(f_factzn) else: - sik_sol = Qp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear) + sik_sol = Qp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear) fmpz_poly_clear(f1) fmpz_poly_clear(linear) else: sik_sol = bsd_sol return sik_sol -def test_qpls(a,b,c,d,e,p): + +def test_qpls(a, b, c, d, e, p): """ Testing function for Qp_soluble. @@ -863,10 +919,15 @@ def test_qpls(a,b,c,d,e,p): sage: tq(1,2,3,4,5,7) 1 """ - cdef Integer A,B,C,D,E,P - cdef int i, result - cdef mpz_t aa,bb,cc,dd,ee,pp - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e); P=Integer(p) + cdef Integer A, B, C, D, E, P + cdef int result + cdef mpz_t aa, bb, cc, dd, ee, pp + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) + P = Integer(p) mpz_init_set(aa, A.value) mpz_init_set(bb, B.value) mpz_init_set(cc, C.value) @@ -882,24 +943,33 @@ def test_qpls(a,b,c,d,e,p): mpz_clear(pp) return result + cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1: """ Returns whether the quartic has local solutions at all primes p. """ - cdef Integer A,B,C,D,E,Delta,p + cdef Integer A, B, C, D, E, Delta,p cdef mpz_t mpz_2 - A=Integer(0); B=Integer(0); C=Integer(0); D=Integer(0); E=Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e) + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E # RR soluble: - if mpz_sgn(a)!=1: + if mpz_sgn(a) != 1: if not real_roots(f): return 0 # Q2 soluble: mpz_init_set_ui(mpz_2, 2) - if not Qp_soluble(a,b,c,d,e,mpz_2): + if not Qp_soluble(a, b, c, d, e, mpz_2): mpz_clear(mpz_2) return 0 mpz_clear(mpz_2) @@ -907,12 +977,15 @@ cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) # Odd finite primes Delta = f.discriminant() for p in prime_divisors(Delta): - if p == 2: continue - if not Qp_soluble(a,b,c,d,e,p.value): return 0 + if p == 2: + continue + if not Qp_soluble(a, b, c, d, e, p.value): + return 0 return 1 -def test_els(a,b,c,d,e): + +def test_els(a, b, c, d, e): """ Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t). @@ -928,10 +1001,15 @@ def test_els(a,b,c,d,e): ....: except ValueError: ....: continue """ - cdef Integer A,B,C,D,E,Delta - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e) + cdef Integer A, B, C, D, E + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value) + cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len, int global_limit_small, int global_limit_large, int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1: @@ -955,7 +1033,6 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len mpz_clear(c_sq_mpz) mpz_clear(d_prime_mpz) - # Set up coefficient array, and static variables cdef mpz_t *coeffs = sig_malloc(5 * sizeof(mpz_t)) for i in range(5): @@ -991,7 +1068,8 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len if mpz_tstbit(j, i): mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i]) if verbosity > 3: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) print('\nSquarefree divisor:', a_Int) mpz_divexact(coeffs[0], d_mpz, coeffs[4]) found_global_points = 0 @@ -1001,10 +1079,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len found_global_points = ratpoints_mpz_exists_only(coeffs, 4, global_limit_small) if found_global_points: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('Found small global point, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('Found small global point, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n1, n1, 1) mpz_add_ui(n2, n2, 1) if verbose: @@ -1018,10 +1099,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len break if els: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('ELS without small global points, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('ELS without small global points, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n2, n2, 1) if not selmer_only: if verbose: @@ -1044,11 +1128,12 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len sig_free(coeffs) return 0 + def two_descent_by_two_isogeny(E, - int global_limit_small=10, - int global_limit_large=10000, - int verbosity=0, - bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, + bint selmer_only=0, bint proof=1): """ Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here @@ -1127,7 +1212,7 @@ def two_descent_by_two_isogeny(E, cdef Integer a1, a2, a3, a4, a6, s2, s4, s6 cdef Integer c, d, x0 cdef list x_list - assert E.torsion_order()%2==0, 'Need rational two-torsion for isogeny descent.' + assert E.torsion_order() % 2 == 0, 'Need rational two-torsion for isogeny descent.' if verbosity > 0: print('\n2-isogeny') if verbosity > 1: @@ -1137,21 +1222,30 @@ def two_descent_by_two_isogeny(E, a3 = Integer(E.a3()) a4 = Integer(E.a4()) a6 = Integer(E.a6()) - if a1==0 and a3==0: - s2=a2; s4=a4; s6=a6 + if a1 == 0 == a3: + s2 = a2 + s4 = a4 + s6 = a6 else: - s2=a1*a1+4*a2; s4=8*(a1*a3+2*a4); s6=16*(a3*a3+4*a6) + s2 = a1*a1+4*a2 + s4 = 8*(a1*a3+2*a4) + s6 = 16*(a3*a3+4*a6) f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s6 - x_list = f.roots() # over ZZ -- use FLINT directly? + x_list = f.roots() # over ZZ -- use FLINT directly? x0 = x_list[0][0] - c = 3*x0+s2; d = (c+s2)*x0+s4 + c = 3*x0+s2 + d = (c+s2)*x0+s4 return two_descent_by_two_isogeny_work(c, d, - global_limit_small, global_limit_large, verbosity, selmer_only, proof) + global_limit_small, + global_limit_large, verbosity, + selmer_only, proof) def two_descent_by_two_isogeny_work(Integer c, Integer d, - int global_limit_small=10, int global_limit_large=10000, - int verbosity=0, bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, bint selmer_only=0, + bint proof=1): """ Do all the work in doing a two-isogeny descent. @@ -1176,7 +1270,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, cdef unsigned long i, j, p, p_list_len cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime cdef object PO - cdef bint found, too_big, d_neg, d_prime_neg + cdef bint found, d_neg, d_prime_neg cdef n_factor_t fact cdef list primes mpz_init_set(c_mpz, c.value) @@ -1212,7 +1306,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, p = fact.p[i] found = 0 for j in range(p_list_len): - if mpz_cmp_ui(p_list_mpz[j], p)==0: + if mpz_cmp_ui(p_list_mpz[j], p) == 0: found = 1 break if not found: @@ -1230,7 +1324,8 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if PO not in primes: primes.append(PO) P = Integer(2) - if P not in primes: primes.append(P) + if P not in primes: + primes.append(P) p_list_len = len(primes) p_list_mpz = sig_malloc(p_list_len * sizeof(mpz_t)) for i in range(p_list_len): @@ -1244,12 +1339,14 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if verbosity > 1: c_prime = -2*c d_prime = c*c-4*d - print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )'%(int(c),int(d))) + print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )' % (int(c), int(d))) print('new isogenous curve is' + - ' y^2 == x( x^2 + (%d)x + (%d) )'%(int(c_prime),int(d_prime))) + ' y^2 == x( x^2 + (%d)x + (%d) )' % (int(c_prime), int(d_prime))) - n1 = Integer(0); n2 = Integer(0) - n1_prime = Integer(0); n2_prime = Integer(0) + n1 = Integer(0) + n2 = Integer(0) + n1_prime = Integer(0) + n2_prime = Integer(0) count(c.value, d.value, p_list_mpz, p_list_len, global_limit_small, global_limit_large, verbosity, selmer_only, n1.value, n2.value) @@ -1303,7 +1400,7 @@ cdef bint ratpoints_mpz_exists_only(mpz_t *coeffs, long degree, long H) except - # PARI checks only for affine points, so we manually check for # points at infinity (of the smooth model) cdef int r - if degree % 2 == 1 or Z_issquare(gel(pol, degree+2)): + if degree % 2 or Z_issquare(gel(pol, degree+2)): r = 1 else: R = hyperellratpoints(pol, stoi(H), 1) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 7ce401587f1..e5e35f2a139 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1250,6 +1250,19 @@ def _call_(self, P): sage: phi = E.isogeny(3^99*P) # optional - sage.rings.finite_rings sage: phi(Q)._order # optional - sage.rings.finite_rings 27 + + Test for :trac:`35983`:: + + sage: E = EllipticCurve([1,0,0,-1,0]) # optional - sage.rings.finite_rings + sage: P = E([1,0]) # optional - sage.rings.finite_rings + sage: P.order() # optional - sage.rings.finite_rings + +Infinity + sage: phi = E.isogenies_prime_degree(2)[0] # optional - sage.rings.finite_rings + sage: Q = phi(P); Q # optional - sage.rings.finite_rings + (0 : 1 : 1) + sage: Q.order() # optional - sage.rings.finite_rings + +Infinity + """ if P.is_zero(): return self._codomain(0) @@ -1281,14 +1294,15 @@ def _call_(self, P): xP = self.__posti_ratl_maps[0](xP) Q = self._codomain(xP, yP) - if hasattr(P, '_order') and P._order.gcd(self._degree).is_one(): + if hasattr(P, '_order'): + if P.has_infinite_order() or P._order.gcd(self._degree).is_one(): + Q._order = P._order # TODO: For non-coprime degree, the order of the point - # gets reduced by a divisor of the degree when passing + # may get reduced by a divisor of the degree when passing # through the isogeny. We could run something along the # lines of order_from_multiple() to determine the new # order, but this probably shouldn't happen by default # as it'll be detrimental to performance in some cases. - Q._order = P._order return Q def __getitem__(self, i): diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 5a5fdf1fcb6..3c359e3de03 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -12,11 +12,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import sage.rings.all as rings import sage.rings.abc from sage.categories.number_fields import NumberFields from sage.categories.finite_fields import FiniteFields - +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.rational_field import QQ from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field @@ -55,7 +57,7 @@ def genus(self): sage: E.genus() 1 """ - return rings.ZZ.one() + return ZZ.one() r""" Twists: rewritten by John Cremona as follows: @@ -149,7 +151,7 @@ def quadratic_twist(self, D=None): if D is None: if K.is_finite(): - x = rings.polygen(K) + x = polygen(K) if char == 2: # We find D such that x^2+x+D is irreducible. If the # degree is odd we can take D=1; otherwise it suffices to @@ -229,9 +231,9 @@ def two_torsion_rank(self): sage: EllipticCurve('15a1').two_torsion_rank() 2 """ - f = self.division_polynomial(rings.Integer(2)) + f = self.division_polynomial(Integer(2)) n = len(f.roots())+1 - return rings.Integer(n).ord(rings.Integer(2)) + return Integer(n).ord(Integer(2)) def quartic_twist(self, D): r""" @@ -425,8 +427,8 @@ def is_quadratic_twist(self, other): return zero if E.is_isomorphic(F): - if K is rings.QQ: - return rings.ZZ(1) + if K is QQ: + return ZZ(1) return K.one() char = K.characteristic() @@ -445,7 +447,7 @@ def is_quadratic_twist(self, other): if j == 0: um = c6E/c6F - x = rings.polygen(K) + x = polygen(K) ulist = (x**3-um).roots(multiplicities=False) if not ulist: D = zero @@ -453,7 +455,7 @@ def is_quadratic_twist(self, other): D = ulist[0] elif j == 1728: um = c4E/c4F - x = rings.polygen(K) + x = polygen(K) ulist = (x**2-um).roots(multiplicities=False) if not ulist: D = zero @@ -467,7 +469,7 @@ def is_quadratic_twist(self, other): if D.is_zero(): return D - if K is rings.QQ: + if K is QQ: D = D.squarefree_part() assert E.quadratic_twist(D).is_isomorphic(F) @@ -708,7 +710,6 @@ def descend_to(self, K, f=None): # j-invariant is in the image, otherwise return an empty list: j = self.j_invariant() - from sage.rings.rational_field import QQ if K == QQ: try: jK = QQ(j) @@ -996,7 +997,7 @@ def division_field(self, l, names='t', map=False, **kwds): - Lorenz Panny (2022): extend to finite fields """ from sage.misc.verbose import verbose - l = rings.Integer(l) + l = Integer(l) if not l.is_prime(): raise ValueError("l must be a prime number") @@ -1052,7 +1053,7 @@ def division_field(self, l, names='t', map=False, **kwds): # Polynomial defining the corresponding Y-coordinate curve = self.defining_polynomial().map_coefficients(F_to_K) - ypol = curve(X, rings.polygen(K), 1) + ypol = curve(X, polygen(K), 1) L = ypol.splitting_field(names, map=map, **kwds) if map: L, K_to_L = L @@ -1571,7 +1572,7 @@ def isogenies_prime_degree(self, l=None, max_l=31): raise NotImplementedError("This code could be implemented for general real fields, but has not been yet.") if isinstance(F, sage.rings.abc.ComplexField): raise NotImplementedError("This code could be implemented for general complex fields, but has not been yet.") - if F is rings.QQbar: + if isinstance(F, sage.rings.abc.AlgebraicField): raise NotImplementedError("This code could be implemented for QQbar, but has not been yet.") if l is None: @@ -1581,9 +1582,9 @@ def isogenies_prime_degree(self, l=None, max_l=31): try: l = list(l) except TypeError: - L = [rings.ZZ(l)] + L = [ZZ(l)] else: - L = [rings.ZZ(d) for d in l] + L = [ZZ(d) for d in l] from .isogeny_small_degree import isogenies_prime_degree return sum([isogenies_prime_degree(self, d) for d in L], []) diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 406450f0831..c7a4bb94e73 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -55,6 +55,7 @@ import math import sage.rings.abc +from sage.rings.finite_rings.integer_mod import mod from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen, polygens from sage.rings.polynomial.polynomial_element import polynomial_is_variable @@ -64,7 +65,13 @@ import sage.groups.generic as generic from sage.arith.functions import lcm -import sage.rings.all as rings +from sage.rings.integer import Integer +from sage.rings.big_oh import O +from sage.rings.infinity import Infinity as oo +from sage.rings.rational import Rational +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.rational_field import RationalField +from sage.rings.real_mpfr import RealField from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById @@ -82,9 +89,6 @@ sqrt = math.sqrt exp = math.exp -oo = rings.infinity # infinity -O = rings.O # big oh - def is_EllipticCurve(x): r""" @@ -575,8 +579,8 @@ def __call__(self, *args, **kwds): # characteristic of the base ring. if so, coerce the point to # infinity. characteristic = self.base_ring().characteristic() - if characteristic != 0 and isinstance(args[0][0], rings.Rational) and isinstance(args[0][1], rings.Rational): - if rings.mod(args[0][0].denominator(),characteristic) == 0 or rings.mod(args[0][1].denominator(),characteristic) == 0: + if characteristic != 0 and isinstance(args[0][0], Rational) and isinstance(args[0][1], Rational): + if mod(args[0][0].denominator(),characteristic) == 0 or mod(args[0][1].denominator(),characteristic) == 0: return self._reduce_point(args[0], characteristic) args = tuple(args[0]) @@ -632,10 +636,10 @@ def _reduce_point(self, R, p): \code{EllipticCurve._reduce_point} """ if R.is_zero(): - return R.curve().change_ring(rings.GF(p))(0) + return R.curve().change_ring(GF(p))(0) x, y = R.xy() d = lcm(x.denominator(), y.denominator()) - return R.curve().change_ring(rings.GF(p))([x*d, y*d, d]) + return R.curve().change_ring(GF(p))([x*d, y*d, d]) def is_x_coord(self, x): r""" @@ -1018,7 +1022,7 @@ def __is_over_RationalField(self): sage: E._EllipticCurve_generic__is_over_RationalField() # optional - sage.rings.finite_rings False """ - return isinstance(self.base_ring(), rings.RationalField) + return isinstance(self.base_ring(), RationalField) def is_on_curve(self, x, y): r""" @@ -1936,7 +1940,7 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu if not (isinstance(x, tuple) and len(x) == 2): raise ValueError("x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1") - m = rings.Integer(m) + m = Integer(m) if x is None: try: @@ -2099,7 +2103,7 @@ def _multiple_x_numerator(self, n, x=None): sage: E._multiple_x_numerator(5) # optional - sage.rings.finite_rings x^25 + 65037*x^23 + 55137*x^22 + ... + 813*x^2 + 10220*x + 42539 """ - n = rings.Integer(n).abs() + n = Integer(n).abs() if not n: raise ValueError("n must be nonzero") @@ -2195,7 +2199,7 @@ def _multiple_x_denominator(self, n, x=None): sage: E._multiple_x_denominator(5) # optional - sage.rings.finite_rings 25*x^24 + 3100*x^22 + 19000*x^21 + ... + 24111*x^2 + 52039*x + 56726 """ - n = rings.Integer(n).abs() + n = Integer(n).abs() if not n: raise ValueError("n must be nonzero") @@ -2321,7 +2325,7 @@ def multiplication_by_m(self, m, x_only=False): sage: assert(E(eval(f,P)) == 2*P) # optional - sage.rings.finite_rings """ # Coerce the input m to be an integer - m = rings.Integer(m) + m = Integer(m) if m == 0: raise ValueError("m must be a non-zero integer") @@ -3168,7 +3172,7 @@ def plot(self, xmin=None, xmax=None, components='both', **args): NotImplementedError: plotting of curves over Complex Field with 53 bits of precision is not implemented yet """ - RR = rings.RealField() + RR = RealField() K = self.base_ring() if not RR.has_coerce_map_from(K): raise NotImplementedError("plotting of curves over %s is not implemented yet" % K) @@ -3372,7 +3376,7 @@ def _p_primary_torsion_basis(self, p, m=None): sage: [t[1] for t in E._p_primary_torsion_basis(2)] # long time (3s on sage.math, 2011) # optional - sage.rings.finite_rings [16, 1] """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise ValueError("p (=%s) should be prime" % p) @@ -3385,7 +3389,7 @@ def _p_primary_torsion_basis(self, p, m=None): # First find the p-torsion: Ep = self(0).division_points(p) - p_rank = rings.Integer(len(Ep)).exact_log(p) + p_rank = Integer(len(Ep)).exact_log(p) assert p_rank in [0, 1, 2] if p_rank == 0: diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 391897f6103..0b6d93a117a 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -122,13 +122,15 @@ from sage.rings.padics.factory import Qp from sage.rings.padics.precision_error import PrecisionError -import sage.rings.all as rings import sage.rings.abc + +from sage.rings.infinity import Infinity as oo from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField +from sage.rings.real_mpfr import RR import sage.groups.generic as generic -from sage.libs.pari.all import pari, PariError -from cypari2.pari_instance import prec_words_to_bits from sage.structure.sequence import Sequence from sage.structure.richcmp import richcmp @@ -141,7 +143,11 @@ from .constructor import EllipticCurve -oo = rings.infinity # infinity +try: + from sage.libs.pari.all import pari, PariError + from cypari2.pari_instance import prec_words_to_bits +except ImportError: + PariError = () class EllipticCurvePoint(SchemeMorphism_point_projective_ring): @@ -1182,16 +1188,24 @@ def _divide_out(self, p): pts = Q.division_points(p) return (Q, k) - def set_order(self, value, *, check=True): + def set_order(self, value=None, *, multiple=None, check=True): r""" - Set the value of ``self._order`` to ``value``. + Set the cached order of this point (i.e., the value of + ``self._order``) to the given ``value``. + + Alternatively, when ``multiple`` is given, this method will + first run :func:`~sage.groups.generic.order_from_multiple` + to determine the exact order from the given multiple of the + point order, then cache the result. - Use this when you know a priori the order of this point to avoid a - potentially expensive order calculation. + Use this when you know a priori the order of this point, or + a multiple of the order, to avoid a potentially expensive + order calculation. INPUT: - ``value`` -- positive integer + - ``multiple`` -- positive integer; mutually exclusive with ``value`` OUTPUT: ``None`` @@ -1206,6 +1220,10 @@ def set_order(self, value, *, check=True): sage: G.set_order(2) # optional - sage.rings.finite_rings sage: 2*G # optional - sage.rings.finite_rings (0 : 1 : 0) + sage: G = E(0, 6) # optional - sage.rings.finite_rings + sage: G.set_order(multiple=12) # optional - sage.rings.finite_rings + sage: G._order # optional - sage.rings.finite_rings + 3 We now give a more interesting case, the NIST-P521 curve. Its order is too big to calculate with Sage, and takes a long time @@ -1227,7 +1245,31 @@ def set_order(self, value, *, check=True): (0 : 1 : 0) sage: proof.arithmetic(prev_proof_state) # restore state - It is an error to pass a `value` equal to `0`:: + Using ``.set_order()`` with a ``multiple=`` argument can + be used to compute a point's order *significantly* faster + than calling :meth:`order` if the point is already known + to be `m`-torsion:: + + sage: F. = GF((10007, 23)) + sage: E = EllipticCurve(F, [9,9]) + sage: n = E.order() + sage: m = 5 * 47 * 139 * 1427 * 2027 * 4831 * 275449 * 29523031 + sage: assert m.divides(n) + sage: P = n/m * E.lift_x(6747+a) + sage: assert m * P == 0 + sage: P.set_order(multiple=m) # compute exact order + sage: factor(m // P.order()) # order is now cached + 47 * 139 + + The algorithm used internally for this functionality is + :meth:`~sage.groups.generic.order_from_multiple`. + Indeed, simply calling :meth:`order` on ``P`` would take + much longer since factoring ``n`` is fairly expensive:: + + sage: n == m * 6670822796985115651 * 441770032618665681677 * 9289973478285634606114927 + True + + It is an error to pass a ``value`` equal to `0`:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12 # optional - sage.rings.finite_rings sage: G = E.random_point() # optional - sage.rings.finite_rings @@ -1251,9 +1293,8 @@ def set_order(self, value, *, check=True): ... ValueError: Value 11 illegal: 11 * (5 : 0 : 1) is not the identity - However, ``set_order`` can be fooled, though it's not likely in "real cases - of interest". For instance, the order can be set to a multiple the - actual order:: + However, ``set_order`` can be fooled. For instance, the order + can be set to a multiple the actual order:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12 # optional - sage.rings.finite_rings sage: G = E(5, 0) # G has order 2 # optional - sage.rings.finite_rings @@ -1261,10 +1302,44 @@ def set_order(self, value, *, check=True): sage: G.order() # optional - sage.rings.finite_rings 8 + TESTS: + + Check that some invalid inputs are caught:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: P = E.lift_x(11) + sage: P.set_order(17, multiple=119) + Traceback (most recent call last): + ... + ValueError: cannot pass both value and multiple + sage: P.set_order(17) + sage: P.set_order(multiple=119+1) + Traceback (most recent call last): + ... + ValueError: previously cached order 17 does not divide given multiple 120 + sage: P.set_order(119) + Traceback (most recent call last): + ... + ValueError: value 119 contradicts previously cached order 17 + AUTHORS: - Mariah Lenox (2011-02-16) + - Lorenz Panny (2022): add ``multiple=`` option """ + if multiple is not None: + if value is not None: + raise ValueError('cannot pass both value and multiple') + + if hasattr(self, '_order'): # already known + if check and not self._order.divides(multiple): + raise ValueError(f'previously cached order {self._order} does not divide given multiple {multiple}') + return + + from sage.groups.generic import order_from_multiple + value = order_from_multiple(self, multiple, check=check) + check = False + value = Integer(value) if check: @@ -1277,6 +1352,9 @@ def set_order(self, value, *, check=True): raise ValueError('Value %s illegal: outside max Hasse bound' % value) if value * self != E(0): raise ValueError('Value %s illegal: %s * %s is not the identity' % (value, value, self)) + if hasattr(self, '_order') and self._order != value: # already known + raise ValueError(f'value {value} contradicts previously cached order {self._order}') + self._order = value # ############################# end ################################ @@ -2293,9 +2371,9 @@ def is_on_identity_component(self, embedding=None): K = E.base_field() if e is None: try: - e = K.embeddings(rings.RealField())[0] + e = K.embeddings(RealField())[0] except IndexError: - e = K.embeddings(rings.ComplexField())[0] + e = K.embeddings(ComplexField())[0] # If there is only one component, the result is True: if not isinstance(e.codomain(), sage.rings.abc.RealField): # complex embedding @@ -2405,7 +2483,7 @@ def has_good_reduction(self, P=None): xyz = list(Q) e = min([c.valuation(P) for c in xyz]) if e != 0: - if K is rings.QQ: + if K is QQ: pi = P else: pi = K.uniformizer(P) @@ -2711,30 +2789,30 @@ def height(self, precision=None, normalised=True, algorithm='pari'): 1.06248137652528 """ if self.has_finite_order(): - return rings.QQ(0) + return QQ(0) E = self.curve() K = E.base_ring() if precision is None: - precision = rings.RealField().precision() + precision = RealField().precision() known_prec = -1 try: height = self.__height known_prec = height.prec() if known_prec > precision: - height = rings.RealField(precision)(height) + height = RealField(precision)(height) except AttributeError: pass if known_prec < precision: - if algorithm == 'pari' and K is rings.QQ: + if algorithm == 'pari' and K is QQ: Emin = E.minimal_model() iso = E.isomorphism_to(Emin) P = iso(self) h = Emin.pari_curve().ellheight(P, precision=precision) - height = rings.RealField(precision)(h) + height = RealField(precision)(h) else: height = (self.non_archimedean_local_height(prec=precision) + self.archimedean_local_height(prec=precision)) @@ -2868,8 +2946,8 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): if prec is None: prec = 53 - if K is rings.QQ: - v = K.embeddings(rings.RR)[0] + if K is QQ: + v = K.embeddings(RR)[0] h = self.archimedean_local_height(v, prec+10) else: r1, r2 = K.signature() @@ -2885,7 +2963,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): prec_v = v.codomain().prec() if prec is None: prec = prec_v - if K is rings.QQ: + if K is QQ: v = K.embeddings(RealField())[0] v_inf = refine_embedding(v, Infinity) v_is_real = v_inf(K.gen()).imag().is_zero() @@ -2943,7 +3021,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): beta = False lam = -t.abs().log() mu = 0 - four_to_n = rings.QQ(1) + four_to_n = QQ(1) for n in range(nterms): if beta: @@ -3079,14 +3157,14 @@ def non_archimedean_local_height(self, v=None, prec=None, -2/3*log(2) """ if prec: - log = lambda x: rings.RealField(prec)(x).log() + log = lambda x: RealField(prec)(x).log() else: from sage.functions.log import log if v is None: D = self.curve().discriminant() K = self.curve().base_ring() - if K is rings.QQ: + if K is QQ: factorD = D.factor() if self[0] == 0: c = 1 @@ -3149,9 +3227,9 @@ def non_archimedean_local_height(self, v=None, prec=None, r = -C/4 r -= offset/6 if not r: - return rings.QQ.zero() + return QQ.zero() else: - if E.base_ring() is rings.QQ: + if E.base_ring() is QQ: Nv = Integer(v) else: Nv = v.norm() diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index d4cd35d8092..765485f0374 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -66,33 +66,38 @@ from sage.modular.modsym.modsym import ModularSymbols from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve -from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve - import sage.modular.modform.constructor import sage.modular.modform.element import sage.databases.cremona import sage.arith.all as arith -import sage.rings.all as rings +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.fast_arith import prime_range +from sage.rings.real_mpfr import RR +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.element import RingElement from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.infinity import Infinity as oo from sage.rings.integer_ring import ZZ, IntegerRing from sage.rings.rational_field import QQ from sage.rings.integer import Integer +from sage.rings.real_mpfi import RealIntervalField from sage.rings.real_mpfr import RealField from sage.rings.complex_mpfr import ComplexField from sage.rings.rational_field import RationalField from sage.structure.coerce import py_scalar_to_element from sage.structure.element import Element -import sage.misc.all as misc +from sage.misc.misc_c import prod as mul +from sage.misc.misc_c import prod +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose as verbose_verbose from sage.functions.log import log -import sage.matrix.all as matrix -from sage.libs.pari.all import pari -from sage.functions.gamma import gamma_inc +from sage.matrix.matrix_space import MatrixSpace +lazy_import('sage.libs.pari.all', 'pari') +lazy_import("sage.functions.gamma", "gamma_inc") from math import sqrt from sage.interfaces.gp import gp from sage.misc.cachefunc import cached_method @@ -102,7 +107,7 @@ C = ComplexField() R = RealField() Z = IntegerRing() -IR = rings.RealIntervalField(20) +IR = RealIntervalField(20) _MAX_HEIGHT = 21 @@ -379,7 +384,7 @@ def is_p_integral(self, p): raise ArithmeticError("p must be prime") if self.is_integral(): return True - return bool(misc.mul([x.valuation(p) >= 0 for x in self.ainvs()])) + return bool(mul([x.valuation(p) >= 0 for x in self.ainvs()])) def is_integral(self): r""" @@ -400,7 +405,7 @@ def is_integral(self): try: return self.__is_integral except AttributeError: - self.__is_integral = bool(misc.mul([x.denominator() == 1 for x in self.ainvs()])) + self.__is_integral = bool(mul([x.denominator() == 1 for x in self.ainvs()])) return self.__is_integral def mwrank(self, options=''): @@ -1525,9 +1530,9 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): if algorithm == 'pari': rank_lead = self.pari_curve().ellanalyticrank() if leading_coefficient: - return (rings.Integer(rank_lead[0]), rank_lead[1].sage()) + return (Integer(rank_lead[0]), rank_lead[1].sage()) else: - return rings.Integer(self.pari_curve().ellanalyticrank()[0]) + return Integer(self.pari_curve().ellanalyticrank()[0]) elif algorithm == 'rubinstein': if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using rubinstein algorithm") @@ -1545,7 +1550,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using magma") from sage.interfaces.magma import magma - return rings.Integer(magma(self).AnalyticRank()) + return Integer(magma(self).AnalyticRank()) elif algorithm == 'zero_sum': if leading_coefficient: s = "Cannot compute leading coefficient using the zero sum method" @@ -1763,6 +1768,8 @@ def analytic_rank_upper_bound(self, ....: bad_primes=bad_primes, ncpus=2) 32 """ + from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve + Z = LFunctionZeroSum_EllipticCurve(self, N) bound = Z.analytic_rank_upper_bound(max_Delta=max_Delta, adaptive=adaptive, @@ -2631,7 +2638,7 @@ def regulator(self, proof=None, precision=53, **kwds): sage: EllipticCurve([0, 0, 1, -79, 342]).regulator(proof=False) # long time (6s on sage.math, 2011) 14.790527570131... """ - R = rings.RealField(precision) + R = RealField(precision) if proof is None: from sage.structure.proof.proof import get_flag @@ -3941,7 +3948,7 @@ def modular_degree(self, algorithm='sympow', M=1): m = sympow.modular_degree(self) elif algorithm == 'magma': from sage.interfaces.magma import magma - m = rings.Integer(magma(self).ModularDegree()) + m = Integer(magma(self).ModularDegree()) else: raise ValueError("unknown algorithm %s" % algorithm) self.__modular_degree = m @@ -4171,16 +4178,16 @@ def reduction(self,p): sage: E.reduction(5) # optional - sage.rings.finite_rings Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise AttributeError("p must be prime.") disc = self.discriminant() if not disc.valuation(p) == 0: local_data = self.local_data(p) if local_data.has_good_reduction(): - return local_data.minimal_model().change_ring(rings.GF(p)) + return local_data.minimal_model().change_ring(GF(p)) raise AttributeError("The curve must have good reduction at p.") - return self.change_ring(rings.GF(p)) + return self.change_ring(GF(p)) def torsion_order(self): r""" @@ -4990,8 +4997,8 @@ def is_isogenous(self, other, proof=True, maxp=200): D1 = E1.discriminant() D2 = E2.discriminant() - if any(E1.change_ring(rings.GF(p)).cardinality() != E2.change_ring(rings.GF(p)).cardinality() - for p in rings.prime_range(2, maxp) + if any(E1.change_ring(GF(p)).cardinality() != E2.change_ring(GF(p)).cardinality() + for p in prime_range(2, maxp) if D1.valuation(p) == 0 and D2.valuation(p) == 0): return False @@ -5334,7 +5341,7 @@ def _shortest_paths(self): """ from sage.graphs.graph import Graph isocls = self.isogeny_class() - M = isocls.matrix(fill=True).change_ring(rings.RR) + M = isocls.matrix(fill=True).change_ring(RR) # see trac #4889 for nebulous M.list() --> M.entries() change... # Take logs here since shortest path minimizes the *sum* of the weights -- not the product. M = M.parent()([a.log() if a else 0 for a in M.list()]) @@ -5553,7 +5560,7 @@ def supersingular_primes(self, B): [] """ v = self.aplist(max(B, 3)) - P = rings.prime_range(max(B,3)+1) + P = prime_range(max(B,3)+1) N = self.conductor() return [P[i] for i in [0,1] if P[i] <= B and v[i] % P[i] == 0 and N % P[i] != 0] + \ [P[i] for i in range(2,len(v)) if v[i] == 0 and N % P[i] != 0] @@ -5585,7 +5592,7 @@ def ordinary_primes(self, B): [] """ v = self.aplist(max(B, 3)) - P = rings.prime_range(max(B, 3) + 1) + P = prime_range(max(B, 3) + 1) result = [P[i] for i in [0, 1] if P[i] <= B and v[i] % P[i]] result += [P[i] for i in range(2, len(v)) if v[i] != 0] return result @@ -6213,7 +6220,7 @@ def point_preprocessing(free,tor): j = self.j_invariant() b2 = self.b2() - Qx = rings.PolynomialRing(RationalField(),'x') + Qx = PolynomialRing(RationalField(),'x') pol = Qx([-self.c6()/216,-self.c4()/12,0,4]) if disc > 0: # two real component -> 3 roots in RR #on curve 897e4, only one root is found with default precision! @@ -6282,7 +6289,7 @@ def point_preprocessing(free,tor): c9_help_list.append((mod_h_list[i]).sqrt()/mw_base_log[i]) c9 = e/c7.sqrt() * min(c9_help_list) n = r+1 - c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * misc.prod(mod_h_list)) + c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * prod(mod_h_list)) top = Z(128) # arbitrary first upper bound bottom = Z(0) @@ -6305,7 +6312,7 @@ def point_preprocessing(free,tor): H_q = R(10)**bound break_cond = 0 #at least one reduction step #reduction via LLL - M = matrix.MatrixSpace(Z,n) + M = MatrixSpace(Z,n) while break_cond < 0.9: #as long as the improvement of the new bound in comparison to the old is greater than 10% c = R((H_q**n)*10) #c has to be greater than H_q^n m = copy(M.identity_matrix()) @@ -6807,9 +6814,9 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): # denom_maxpa is a list of pairs (d,q) where d runs # through possible denominators, and q=p^a is the # maximum prime power divisor of d: - denom_maxpa = [(misc.prod(tmp),max(tmp)) for tmp in cartesian_product_iterator(p_pow_alpha)] + denom_maxpa = [(prod(tmp),max(tmp)) for tmp in cartesian_product_iterator(p_pow_alpha)] # The maximum denominator is this (not used): -# denom = [misc.prod([pp[-1] for pp in p_pow_alpha],1)] +# denom = [prod([pp[-1] for pp in p_pow_alpha],1)] for de,maxpa in denom_maxpa: n_max = (abs_bound*de).ceil() n_min = maxpa*de @@ -6865,7 +6872,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): w1, w2 = E.period_lattice().basis() - Qx = rings.PolynomialRing(RationalField(),'x') + Qx = PolynomialRing(RationalField(),'x') pol = Qx([-54*c6,-27*c4,0,1]) if disc > 0: # two real component -> 3 roots in RR # it is possible that only one root is found with default precision! (see integral_points()) @@ -6974,7 +6981,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): sys.stdout.flush() break_cond = 0 - M = matrix.MatrixSpace(Z,n) + M = MatrixSpace(Z,n) #Reduction of initial bound if verbose: print('initial bound', H_q) @@ -7122,7 +7129,7 @@ def cremona_curves(conductors): ('39a3', 0), ('39a4', 0)] """ - if isinstance(conductors, (rings.RingElement, int)): + if isinstance(conductors, (RingElement, int)): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter(conductors) @@ -7148,7 +7155,7 @@ def cremona_optimal_curves(conductors): ['990a1', '990b1', '990c1', '990d1', '990e1', '990f1', '990g1', '990h3', '990i1', '990j1', '990k1', '990l1'] """ - if isinstance(conductors, (rings.RingElement, int)): + if isinstance(conductors, (RingElement, int)): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter_optimal(conductors) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 0b7cd52a146..7b616671e24 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -50,7 +50,7 @@ from sage.functions.log import log from sage.misc.functional import denominator from sage.misc.misc_c import prod -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix @richcmp_method @@ -113,7 +113,7 @@ def __richcmp__(self, other, op): sage: eq7 == eq5 False """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self._E, self._p), (other._E, other._p), op) @@ -659,7 +659,7 @@ def padic_regulator(self, prec=20): "for non-split multiplicative reduction.") basis = self._E.gens() - M = matrix.matrix(K, rank, rank, 0) + M = matrix(K, rank, rank, 0) height = self.padic_height(prec=prec) point_height = [height(P) for P in basis] diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py index 9bd2b1e8f96..f56c3ee0e6f 100644 --- a/src/sage/schemes/elliptic_curves/ell_torsion.py +++ b/src/sage/schemes/elliptic_curves/ell_torsion.py @@ -237,7 +237,7 @@ def __richcmp__(self, other, op): sage: tor == tor True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.__E, other.__E, op) diff --git a/src/sage/schemes/elliptic_curves/formal_group.py b/src/sage/schemes/elliptic_curves/formal_group.py index 7949eb94bcf..63ce58c74c6 100644 --- a/src/sage/schemes/elliptic_curves/formal_group.py +++ b/src/sage/schemes/elliptic_curves/formal_group.py @@ -15,7 +15,8 @@ from sage.structure.sage_object import SageObject import sage.misc.misc as misc -import sage.rings.all as rings +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.rings.big_oh import O @@ -159,7 +160,7 @@ def w(self, prec=20): R = w.parent() except AttributeError: # No cached version available - R = rings.PowerSeriesRing(k, "t") + R = PowerSeriesRing(k, "t") w = R([k(0), k(0), k(0), k(1)], 4) cached_prec = 4 self.__w = w @@ -526,7 +527,7 @@ def group_law(self, prec=10): if prec <= 0: raise ValueError("The precision must be positive.") - R = rings.PowerSeriesRing(self.curve().base_ring(), 2, 't1,t2') + R = PowerSeriesRing(self.curve().base_ring(), 2, 't1,t2') t1, t2 = R.gens() if prec == 1: @@ -666,7 +667,7 @@ def mult_by_n(self, n, prec=10): # Now the general case, not necessarily over a field. - R = rings.PowerSeriesRing(self.curve().base_ring(), "t") + R = PowerSeriesRing(self.curve().base_ring(), "t") t = R.gen() if n == 1: @@ -744,7 +745,7 @@ def sigma(self, prec=10): fl = self.log(prec) F = fl.reverse() - S = rings.LaurentSeriesRing(k,'z') + S = LaurentSeriesRing(k,'z') z = S.gen() F = F(z + O(z**prec)) wp = self.x()(F) + (a1**2 + 4*a2)/12 @@ -752,7 +753,7 @@ def sigma(self, prec=10): h = g.integral().integral() sigma_of_z = z.power_series() * h.exp() - T = rings.PowerSeriesRing(k,'t') + T = PowerSeriesRing(k,'t') fl = fl(T.gen()+O(T.gen()**prec)) sigma_of_t = sigma_of_z(fl) return sigma_of_t diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py index 1b8d2ad64fd..c28b4f76d2c 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps.py +++ b/src/sage/schemes/elliptic_curves/gal_reps.py @@ -115,17 +115,19 @@ # http://www.gnu.org/licenses/ ###################################################################### +from math import sqrt + from sage.structure.sage_object import SageObject import sage.arith.all as arith from sage.rings.fast_arith import prime_range -import sage.misc.all as misc +from sage.misc.lazy_import import lazy_import +from sage.misc.misc_c import prod as mul from sage.misc.verbose import verbose -import sage.rings.all as rings +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.real_mpfr import RealField from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from math import sqrt -from sage.libs.pari.all import pari +lazy_import('sage.libs.pari.all', 'pari') def _ex_set(p): @@ -467,7 +469,7 @@ def _is_surjective(self, p, A): self.__image_type[p] = "The image is meta-cyclic inside a Borel subgroup as there is a %s-torsion point on the curve." % p return False - R = rings.PolynomialRing(self._E.base_ring(), 'x') + R = PolynomialRing(self._E.base_ring(), 'x') x = R.gen() if p == 2: @@ -676,12 +678,12 @@ def non_surjective(self, A=1000): C2 = (sqrt(p0)+1)**8 C = max(C1,C2) verbose("j is not integral -- Serre's bound is %s" % C) - C3 = 1 + 4*sqrt(6)*int(N)/3 * sqrt(misc.mul([1+1.0/int(p) for p,_ in arith.factor(N)])) + C3 = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) C = min(C,C3) verbose("conductor = %s, and bound is %s" % (N,C)) else: # Cojocaru's bound (depends on the conductor) - C = 1 + 4*sqrt(6)*int(N)/3 * sqrt(misc.mul([1+1.0/int(p) for p,_ in arith.factor(N)])) + C = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) verbose("conductor = %s, and bound is %s" % (N,C)) B = [] p = 2 diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 71f4b86d29b..75a356289f2 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -99,12 +99,18 @@ import sage.rings.abc import sage.rings.number_field.number_field_element import sage.rings.number_field.number_field as number_field -import sage.rings.all as rings +from sage.rings.number_field.number_field import NumberField +from sage.rings.number_field.number_field import QuadraticField +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfi import RealIntervalField +from sage.rings.infinity import Infinity as infinity +from sage.rings.fast_arith import prime_range from sage.arith.functions import lcm from sage.arith.misc import (binomial, factorial, prime_divisors, GCD as gcd, XGCD as xgcd) -from sage.matrix.constructor import Matrix as matrix +from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod @@ -3566,14 +3572,14 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): return v[0] g, d = make_monic(f) - K = rings.NumberField(g, var) + K = NumberField(g, var) x = K.gen() / d if optimize: KO, from_KO, to_KO = K.optimized_representation() K = KO x = to_KO(x) if K.degree() < 2 * self.ring_class_field().degree_over_K(): - M = rings.QuadraticField(self.discriminant(),'b') + M = QuadraticField(self.discriminant(),'b') KD = K.composite_fields(M, names='a')[0] phi = K.embeddings(KD)[0] x = phi(x) @@ -3808,7 +3814,7 @@ def _trace_numerical_conductor_1(self, prec=53): R, U = self._good_tau_representatives() E = self.__E phi = E.modular_parametrization() - C = rings.ComplexField(prec) + C = ComplexField(prec) F = E.change_ring(C) s = 0 for u, weight in U: @@ -4324,7 +4330,7 @@ def trace_to_real_numerical(self, prec=53): R = 2*P else: R = P + E.point([x.conjugate() for x in P],check=False) - F = self.curve().change_ring(rings.RealField(prec)) + F = self.curve().change_ring(RealField(prec)) return F.point([x.real() for x in R], check=False) @cached_method @@ -6591,12 +6597,12 @@ def heegner_point_height(self, D, prec=2, check_rank=True): eps = self.root_number() L1_vanishes = self.lseries().L1_vanishes() - IR = rings.RealIntervalField(20) # TODO: why 20 bits here? + IR = RealIntervalField(20) # TODO: why 20 bits here? if eps == 1 and L1_vanishes: return IR(0) # rank even hence >= 2, so Heegner point is torsion. - RR = rings.RealField() + RR = RealField() from math import sqrt alpha = RR(sqrt(abs(D)))/(2*self.period_lattice().complex_area()) @@ -6740,13 +6746,13 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, raise ArithmeticError("Discriminant (=%s) must be a fundamental discriminant that satisfies the Heegner hypothesis." % D) if check_rank and self.rank() >= 2: - return rings.infinity + return infinity # First compute upper bound on height of Heegner point. tm = verbose("computing heegner point height...") h0 = self.heegner_point_height(D, prec=prec, check_rank=check_rank) if h0 == 0: - return rings.infinity + return infinity # We divide by 2 to get the height **over Q** of the # Heegner point on the twist. @@ -6768,7 +6774,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, from .ell_rational_field import _MAX_HEIGHT - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? a = 1 if c > _MAX_HEIGHT or F is self: @@ -6795,7 +6801,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose("doing point search") P = F.point_search(c) verbose("done with point search") - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] a = 1 if len(P) == 0: return IR(1) @@ -6833,7 +6839,7 @@ def _adjust_heegner_index(self, a): 1.?e-8 """ if a.lower() < 0: - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? a = IR((0, a.upper())) return a.sqrt() @@ -6940,7 +6946,7 @@ def _bound(P): S, I, reg = F.saturation(P) - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? h = IR(reg-eps,reg+eps) ind2 = ht/(h/2) verbose("index squared = %s" % ind2) @@ -6956,17 +6962,17 @@ def _bound(P): # First try a quick search, in case we get lucky and find # a generator. P = F.point_search(13, rank_bound=1) - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] if len(P) > 0: return _bound(P) # Do search to eliminate possibility that Heegner point is # divisible by primes up to p, without finding Heegner point. P = F.point_search(c, rank_bound=1) - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] if len(P) == 0: # We've eliminated the possibility of a divisor up to p. - return rings.prime_range(3, p), D, False + return prime_range(3, p), D, False else: return _bound(P) @@ -7036,7 +7042,7 @@ def _heegner_index_in_EK(self, D): E = self # nice shortcut F = E.quadratic_twist(D).minimal_model() - K = rings.QuadraticField(D, 'a') + K = QuadraticField(D, 'a') # Define a map phi that we'll use to put the points of E^D(QQ) # into E(K): @@ -7051,11 +7057,11 @@ def _heegner_index_in_EK(self, D): ((z.order() % 2 == 0 and len(z.order().factor()) == 1))] r = len(basis) # rank - V = rings.QQ**r + V = QQ**r B = [] # Iterate through reps for A/(2*A) creating vectors in (1/2)*ZZ^r - for v in rings.GF(2)**r: + for v in GF(2)**r: if not v: continue P = sum([basis[i] for i in range(r) if v[i]]) @@ -7063,9 +7069,9 @@ def _heegner_index_in_EK(self, D): if (P+t).is_divisible_by(2): B.append(V(v)/2) - A = rings.ZZ**r + A = ZZ**r # Take span of our vectors in (1/2)*ZZ^r, along with ZZ^r. This is E(K)/tor. - W = V.span(B, rings.ZZ) + A + W = V.span(B, ZZ) + A # Compute the index in E(K)/tor of A = E(Q)/tor + E^D(Q)/tor, cache, and return. index = A.index_in(W) @@ -7165,7 +7171,7 @@ def heegner_sha_an(self, D, prec=53): # see page 311 of [GZ1986]_ for the formula. E = self # notational convenience F = E.quadratic_twist(D).minimal_model() - K = rings.QuadraticField(D, 'a') + K = QuadraticField(D, 'a') # Compute each of the quantities in BSD # - The torsion subgroup over K. diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index 6a88b4147e9..65742f28d72 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -273,7 +273,8 @@ cdef llong llxgcd(llong a, llong b, llong *ss, llong *tt) except -1: tt[0] = q * qsign return a -def _test_llfunctions(a,b): + +def _test_llfunctions(a, b): r""" Doctest function for the above three functions. Given a, b this returns the absolute value of a, @@ -300,6 +301,7 @@ def _test_llfunctions(a,b): assert a*a4 + b*a5 == a3 return (a1,a2,a3,a4,a5) + # ================================ # this is a llong version of a function in @@ -391,7 +393,8 @@ cdef int proj_normalise(llong N, llong u, llong v, #verbose(" leaving proj_normalise with s=%s, t=%s"%(u,v), level=5) return 0 -def _test_proj_normalise(N,u,v): + +def _test_proj_normalise(N, u, v): r""" The doctest function for proj_normalise. @@ -411,9 +414,10 @@ def _test_proj_normalise(N,u,v): (1, 7) """ cdef llong uu, vv - ans = proj_normalise(N,u,v,&uu,&vv) + _ = proj_normalise(N,u,v,&uu,&vv) return (Integer(uu), Integer(vv)) + cdef int best_proj_point(llong u, llong v, llong N, llong* uu, llong* vv) except -1: r""" @@ -518,7 +522,8 @@ cdef int best_proj_point(llong u, llong v, llong N, vv[0] = t1 return 0 -def _test_best_proj_point(u,v,N): + +def _test_best_proj_point(u, v, N): r""" Doctest function of best_proj_point. @@ -546,6 +551,7 @@ def _test_best_proj_point(u,v,N): assert a == 0 return (Integer(uu), Integer(vv)) + #====================================================================== cdef class _CuspsForModularSymbolNumerical: @@ -614,7 +620,7 @@ cdef class _CuspsForModularSymbolNumerical: four [a,b,c,d] corresponds to [[a,b],[c,d]]. """ - cdef llong Q, B, c, g, x, y + cdef llong Q, B, c, x, y #verbose(" enter atkin_lehner for cusp r=%s"%self._r, level=5) Q = self._width @@ -623,7 +629,7 @@ cdef class _CuspsForModularSymbolNumerical: if llgcd(Q, B) != 1: raise ValueError("This cusp is not in the Atkin-Lehner " "orbit of oo.") - g = llxgcd( self._a * Q, self._m, &x, &y) + _ = llxgcd( self._a * Q, self._m, &x, &y) res[0] = Q * x res[1] = y res[2] = -c * self._N_level @@ -633,7 +639,8 @@ cdef class _CuspsForModularSymbolNumerical: # level=5) return 0 -def _test_cusps(r,N): + +def _test_cusps(r, N): r""" Doctest function for the above class. @@ -658,12 +665,12 @@ def _test_cusps(r,N): sage: _test_cusps(5/27,27) (1, 1, [[11, -2], [-27, 5]]) """ - cdef llong *wQ = [0L,0L,0L,0L] - rc = _CuspsForModularSymbolNumerical(r,N) + cdef llong *wQ = [0L, 0L, 0L, 0L] + rc = _CuspsForModularSymbolNumerical(r, N) a1 = rc._width a2 = rc.is_unitary() if a2: - a3 = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) a = Integer(wQ[0]) b = Integer(wQ[1]) c = Integer(wQ[2]) @@ -802,7 +809,7 @@ cdef class ModularSymbolNumerical: sig_free(self._ans_num) sig_free(self._ans) -# == basics ================ + # == basics ================ def __repr__(self): """ @@ -815,7 +822,7 @@ cdef class ModularSymbolNumerical: sage: M Numerical modular symbol attached to Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field """ - return "Numerical modular symbol attached to %s"%(self._E) + return "Numerical modular symbol attached to %s" % (self._E) def elliptic_curve(self): r""" @@ -867,9 +874,8 @@ cdef class ModularSymbolNumerical: 0 sage: M(112379/43568779) 5 - """ - cdef llong Q - cdef Rational ra, ans + """ + cdef Rational ra if sign == 0: sign = self._global_sign @@ -882,7 +888,7 @@ cdef class ModularSymbolNumerical: ra = Rational( (0,1) ) elif isinstance(r, sage.rings.infinity.PlusInfinity): return Rational(0) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a " "rational number only.") if use_twist: @@ -892,7 +898,6 @@ cdef class ModularSymbolNumerical: return self._twisted_symbol(ra, sign=sign) return self._evaluate(ra, sign=sign) - def approximative_value(self, r, int sign=0, int prec=20, use_twist=True): r""" The numerical modular symbol evaluated at rational. @@ -936,14 +941,12 @@ cdef class ModularSymbolNumerical: sage: M.approximative_value(1/7,prec=10) # abs tol 1e-11 0.999999972802649 """ - cdef llong Q cdef Rational ra cdef ComplexNumber ans cdef double eps cdef object L cdef int cinf - if sign == 0: sign = self._global_sign @@ -953,7 +956,7 @@ cdef class ModularSymbolNumerical: ra = r elif isinstance(r, Integer): ra = Rational( (0,1) ) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a" "rational number only.") if use_twist: @@ -981,8 +984,7 @@ cdef class ModularSymbolNumerical: else: return ans.imag()/ self._om2 - -# == initialisation ======== + # == initialisation ======== def _set_epsQs(self): r""" @@ -997,10 +999,9 @@ cdef class ModularSymbolNumerical: sage: E = EllipticCurve("20a2") sage: M = E.modular_symbol(implementation="num") #indirect doctest """ - self._epsQs = dict( - [d,prod(self._E.root_number(p) - for p in d.prime_divisors() )] - for d in Integer( self._N_E ).divisors()) + self._epsQs = {d: prod(self._E.root_number(p) + for p in d.prime_divisors()) + for d in Integer(self._N_E).divisors()} def _set_den_bounds(self): r""" @@ -1152,11 +1153,11 @@ cdef class ModularSymbolNumerical: EXAMPLES:: sage: E = EllipticCurve("63a2") - sage: M =E.modular_symbol(implementation="num") + sage: M = E.modular_symbol(implementation="num") sage: M(3/4, use_twist=True) # indirect doctest -1 """ - cdef Integer D, ell, de, ve, Dmax, DD, Nmin + cdef Integer D, ell cdef RealNumber qq, Db #verbose(" enter _set_up_twist", level=5) @@ -1200,7 +1201,6 @@ cdef class ModularSymbolNumerical: qq = self._om1 * Db/self._Mt._om2 * 2 assert self._twist_q == Rational( ( qq.round(),2)) - def _round(self, RealNumber val, int sign, int unitary): r""" Round the numerical approximation to the rational. @@ -1343,7 +1343,6 @@ cdef class ModularSymbolNumerical: # last n such that ans[n] is allowed self._lans = T - def clear_cache(self): r""" Clear the cached values in all methods of this class @@ -1362,8 +1361,7 @@ cdef class ModularSymbolNumerical: for me in cadi: cadi[me].clear_cache() - -#================== Low level summation ========= + #================== Low level summation ========= def _integration_to_tau(self, ComplexNumber tau, int number_of_terms, int prec): @@ -1648,8 +1646,7 @@ cdef class ModularSymbolNumerical: # " %s, %s, ... %s"%(res[0], res[1], res[m-1]), level=5) return res - -#================ + #================ def _get_truncation_and_prec(self, double y, double eps): r""" @@ -1867,7 +1864,7 @@ cdef class ModularSymbolNumerical: ra = sig_malloc( m * sizeof(double)) if ra is NULL: raise MemoryError - oi = self._partial_real_sums_double(y, m, T, ra) + _ = self._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) #verbose(" leaving _kappa with" @@ -1925,8 +1922,8 @@ cdef class ModularSymbolNumerical: # " and eps=%s"%(r,eps), level=5) cdef: llong m, Q, epsQ, a, u - double yy, taui, zz, epsi - int T, prec, j, oi, preci + double yy, taui + int T, prec, j double complex tauc, tauphc, int1c, int2c, twopii, ze1, ze2, su ComplexNumber tau, tauph, int1, int2 llong * wQ = [0L, 0L, 0L, 0L] @@ -1934,7 +1931,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, self._N_E) Q = rc._width - oi = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) m = rc._m epsQ = self._epsQs[Q] r = rc._r @@ -1970,7 +1967,6 @@ cdef class ModularSymbolNumerical: verbose(" yields %s"%int2, level=2) return int2 + int1 - elif not use_partials: # prec = 53 taui = (Q) taui = sqrt(taui) @@ -2051,7 +2047,7 @@ cdef class ModularSymbolNumerical: RealNumber x1, x2, s complex tau0c, tau1c, int1c, int2c, ze1, ze2, su, twopii llong g, u, v, uu, vv, D, a, aa, m, mm, Q, QQ, z, xi, xixi - int oi, j, preci + int oi, j double x1d, x2d, sd #verbose(" enter _from_r_to_rr_approx_direct with r=%s," @@ -2225,7 +2221,6 @@ cdef class ModularSymbolNumerical: llong * wQ = [0L, 0L, 0L, 0L] llong * wQQ = [0L, 0L, 0L, 0L] Integer epsQ, epsQQ - Rational csq, x double s, yy ComplexNumber ans, ans2 int T=0, prec=0, T1=0, T2=0, oi @@ -2698,7 +2693,7 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_non_unitary with r=%s," # " sign=%s"%(r,sign), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2, res @@ -2707,9 +2702,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -2722,14 +2715,14 @@ cdef class ModularSymbolNumerical: aell = Integer(self._ans[ell]) N_ell = ell + 1 - aell # {ell * r , r} - verbose(" Compute symbol {ell*r -> r} = {%s -> %s}"%(ell*r,r), + verbose(" Compute symbol {ell*r -> r} = {%s -> %s}" % (ell*r, r), level=4) res = self.transportable_symbol(ell * r, r, sign=sign) # {(r + u)/ ell, r} u = Integer(0) while u < ell: r2 = (r+u) / ell - verbose(" Compute symbol {r2-> r} = {%s -> %s}"%(r2,r), + verbose(" Compute symbol {r2-> r} = {%s -> %s}" % (r2, r), level=4) res += self.transportable_symbol(r2, r, sign=sign) u += 1 @@ -2781,7 +2774,6 @@ cdef class ModularSymbolNumerical: cdef: llong c, d, x, y, N = self._N_E, Mu, Mv, Qu, Qv, du=1, dv=1 Rational r, rr, res - int oi #verbose(" enter _manin_symbol_with_cache with u=%s, v=%s," # " sign =%s"%(u,v,sign), level=5) @@ -2802,9 +2794,9 @@ cdef class ModularSymbolNumerical: Mv = llgcd(v,N) Qv = N/Mv isunitary = ( llgcd(Qu,Mu) == 1 and llgcd(Qv,Mv) == 1 ) - if isunitary: # unitary case - oi = best_proj_point(u, v, self._N_E, &c, &d) - else: # at least one of the two cusps is not unitary + if isunitary: # unitary case + _ = best_proj_point(u, v, self._N_E, &c, &d) + else: # at least one of the two cusps is not unitary du = llgcd(Qu,Mu) dv = llgcd(Qv,Mv) NMM = N/Mv/Mu @@ -2986,10 +2978,9 @@ cdef class ModularSymbolNumerical: return res + # =============================== -# =============================== - - @cached_method # not sure this is not a waist + @cached_method # not sure this is not a waist def _evaluate(self, Rational r, int sign=0): r""" Given a rational number `r` this computes the modular symbol @@ -3417,16 +3408,14 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_nonunitary_approx with r=%s," # " eps=%s"%(r,eps), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2 ComplexNumber res rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -3619,7 +3608,8 @@ def _test_init(E): e2 = M._eps_minus e3 = M._eps_unitary_plus e4 = M._eps_unitary_minus - return e, [a1,a2,a3,a4,a5], [t1,t2,t3,t4], [e1,e2,e3,e4] + return e, [a1, a2, a3, a4, a5], [t1, t2, t3, t4], [e1, e2, e3, e4] + def _test_integration(E, a, b, T): r""" @@ -3661,6 +3651,7 @@ def _test_integration(E, a, b, T): ans = M._integration_to_tau_double(c,tt) return ans + def _test_integration_via_partials(E, y, m, T): r""" Doctest for the numerical integration in @@ -3692,15 +3683,13 @@ def _test_integration_via_partials(E, y, m, T): sage: _test_integration_via_partials(E,0.03,3,7000) # abs tol 1e-11 [0.49198993741342784, 0.6601504274130793, 0.3177042713926389] """ - cdef int oi, mm = (m) + cdef int mm = (m) cdef double * ra ra = sig_malloc( mm * sizeof(double)) if ra is NULL: raise MemoryError M = ModularSymbolNumerical(E) - yy = (y) - tt = T - oi = M._partial_real_sums_double(y, m, T, ra) + _ = M._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) return res diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 7f32eb10a21..a6ac5c30af5 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -61,7 +61,7 @@ # https://www.gnu.org/licenses/ ###################################################################### -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix import sage.schemes.hyperelliptic_curves.monsky_washnitzer from sage.arith.functions import lcm as LCM @@ -224,7 +224,7 @@ def __richcmp__(self, other, op): sage: lp1 == lp3 False """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self._E, self._p), (other._E, other._p), op) @@ -1449,7 +1449,7 @@ def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): H = QpT(Hli, prec) # now compute phi - phi = matrix.matrix([[0, -1 / p], [1, E.ap(p) / p]]) + phi = matrix([[0, -1 / p], [1, E.ap(p) / p]]) lpv = vector([G + (E.ap(p)) * H, - R(p) * H]) # this is L_p eps = (1 - phi)**(-2) resu = lpv * eps.transpose() @@ -1498,7 +1498,7 @@ def frobenius(self, prec=20, algorithm="mw"): Q = x**3 + modprecring(Ew.a4()) * x + modprecring(Ew.a6()) trace = Ew.ap(p) fr = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius(Q, p, adjusted_prec, trace) - fr = matrix.matrix(output_ring,2,2,fr) + fr = matrix(output_ring,2,2,fr) # return a vector for PARI's ellchangecurve to pass from e1 to e2 def isom(e1, e2): @@ -1516,7 +1516,7 @@ def isom(e1, e2): r = v[1] # change basis - A = matrix.matrix([[u, -r/u], [0, 1/u]]) + A = matrix([[u, -r/u], [0, 1/u]]) frn = A * fr * A**(-1) return 1 / p*frn @@ -1610,7 +1610,7 @@ def __phi_bpr(self, prec=0): c = -gamma d = E.ap(p) - a b = (-1/p+a*d)/c - phi = matrix.matrix([[a,b],[c,d]]) + phi = matrix([[a,b],[c,d]]) return phi def bernardi_sigma_function(self, prec=20): @@ -1748,7 +1748,7 @@ def hv(vec, P): basis = E.gens() def regv(vec): - M = matrix.matrix(K, rk, rk, 0) + M = matrix(K, rk, rk, 0) point_height = [hv(vec, P) for P in basis] for i in range(rk): for j in range(i+1, rk): diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index f59e4b823fc..51f7cc3db90 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -23,10 +23,13 @@ import math -import sage.arith.all as arith -import sage.matrix.all as matrix -import sage.misc.misc as misc -import sage.rings.all as rings +from sage.arith.functions import lcm as LCM +from sage.arith.misc import valuation +from sage.matrix.constructor import matrix +from sage.misc.misc import newton_method_sizes +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.padics.factory import Qp as pAdicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import sage.schemes.hyperelliptic_curves.hypellfrob import sage.schemes.hyperelliptic_curves.monsky_washnitzer @@ -61,7 +64,7 @@ def __check_padic_hypotheses(self, p): ArithmeticError: p must be a good ordinary prime """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise ValueError("p = (%s) must be prime" % p) if p == 2: @@ -399,7 +402,7 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= K = Qp(p, prec=prec) rank = self.rank() - M = matrix.matrix(K, rank, rank, 0) + M = matrix(K, rank, rank, 0) if rank == 0: return M @@ -630,7 +633,7 @@ def _multiple_to_make_good_reduction(E): "Please change the model first.") raise NotImplementedError(st) if E.is_minimal(): - n2 = arith.LCM(E.tamagawa_numbers()) + n2 = LCM(E.tamagawa_numbers()) else: # generalising to number fields one can get the u from local_data Emin = E.global_minimal_model() @@ -651,7 +654,7 @@ def _multiple_to_make_good_reduction(E): otherbad = Integer(Emin.discriminant()).prime_divisors() otherbad = [p for p in otherbad if u%p != 0 ] li += [E.tamagawa_number(p) for p in otherbad] - n2 = arith.LCM(li) + n2 = LCM(li) return n2 def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): @@ -805,13 +808,13 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): # For notation and definitions, see [Har2009]_. - n1 = self.change_ring(rings.GF(p)).cardinality() + n1 = self.change_ring(GF(p)).cardinality() n2 = _multiple_to_make_good_reduction(self) - n = arith.LCM(n1, n2) + n = LCM(n1, n2) m = int(n / n2) - adjusted_prec = prec + 2 * arith.valuation(n, p) # this is M' - R = rings.Integers(p ** adjusted_prec) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p ** adjusted_prec) if sigma is None: sigma = self.padic_sigma(p, adjusted_prec, check_hypotheses=False) @@ -948,15 +951,15 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): # For notation and definitions, [Har2009]_ - n1 = self.change_ring(rings.GF(p)).cardinality() + n1 = self.change_ring(GF(p)).cardinality() n2 = _multiple_to_make_good_reduction(self) - n = arith.LCM(n1, n2) + n = LCM(n1, n2) m = int(n / n2) lamb = int(math.floor(math.sqrt(prec))) - adjusted_prec = prec + 2 * arith.valuation(n, p) # this is M' - R = rings.Integers(p ** (adjusted_prec + 2*lamb)) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p ** (adjusted_prec + 2*lamb)) sigma = self.padic_sigma_truncated(p, N=adjusted_prec, E2=E2, lamb=lamb) @@ -1150,7 +1153,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): QQt = LaurentSeriesRing(RationalField(), "x") - R = rings.Integers(p**(N-2)) + R = Integers(p**(N-2)) X = self.change_ring(R) c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 @@ -1171,7 +1174,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = rings.Integers(p**(N-1)) + R = Integers(p**(N-1)) A = [R(u) for u in A] A[0] = self.change_ring(R).a1()/2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) @@ -1184,7 +1187,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): # [Note: there are actually more digits available, but it's a bit # tricky to figure out exactly how many, and we only need p^(N-k+1) # for p-adic height purposes anyway] - K = rings.pAdicField(p, N + 1) + K = pAdicField(p, N + 1) sigma = sigma.padded_list(N+1) @@ -1193,13 +1196,13 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): for n in range(2, N+1): sigma[n] = K(sigma[n].lift(), N - n + 1) - S = rings.PowerSeriesRing(K, "t", N+1) + S = PowerSeriesRing(K, "t", N+1) sigma = S(sigma, N+1) # if requested, check that sigma satisfies the appropriate # differential equation if check: - R = rings.Integers(p**N) + R = Integers(p**N) X = self.change_ring(R) x = X.formal_group().x(N+5) # few extra terms for safety f = X.formal_group().differential(N+5) @@ -1337,7 +1340,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) QQt = LaurentSeriesRing(RationalField(), "x") - R = rings.Integers(p**(N-2)) + R = Integers(p**(N-2)) X = self.change_ring(R) c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 @@ -1358,7 +1361,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = rings.Integers(p**(N-1+lamb)) + R = Integers(p**(N-1+lamb)) A = [R(u) for u in A] A[0] = self.change_ring(R).a1()/2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) @@ -1368,7 +1371,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) # Convert the answer to power series over p-adics; drop the precision # of the t^j coefficient to p^{N - 2 + (3 - j)(lamb + 1)}). - K = rings.pAdicField(p, N - 2 + 3*(lamb+1)) + K = pAdicField(p, N - 2 + 3*(lamb+1)) sigma = sigma.padded_list(trunc+1) @@ -1377,7 +1380,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) for j in range(2, trunc+1): sigma[j] = K(sigma[j].lift(), N - 2 + (3 - j)*(lamb+1)) - S = rings.PowerSeriesRing(K, "t", trunc + 1) + S = PowerSeriesRing(K, "t", trunc + 1) sigma = S(sigma, trunc+1) return sigma @@ -1551,7 +1554,7 @@ def padic_E2(self, p, prec=20, check=False, check_hypotheses=True, algorithm="au frob_p_n = frob_p**prec # todo: think about the sign of this. Is it correct? - output_ring = rings.pAdicField(p, prec) + output_ring = pAdicField(p, prec) E2_of_X = output_ring( (-12 * frob_p_n[0,1] / frob_p_n[1,1]).lift() ) \ + O(p**prec) @@ -1686,16 +1689,16 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al else: trace = self.ap(p) - base_ring = rings.Integers(p**adjusted_prec) + base_ring = Integers(p**adjusted_prec) - R, x = rings.PolynomialRing(base_ring, 'x').objgen() + R, x = PolynomialRing(base_ring, 'x').objgen() Q = x**3 + base_ring(X.a4()) * x + base_ring(X.a6()) frob_p = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius( Q, p, adjusted_prec, trace) else: # algorithm == "sqrtp" p_to_prec = p**prec - R = rings.PolynomialRing(Integers(), "x") + R = PolynomialRing(Integers(), "x") Q = R([X.a6() % p_to_prec, X.a4() % p_to_prec, 0, 1]) frob_p = sage.schemes.hyperelliptic_curves.hypellfrob.hypellfrob(p, prec, Q) @@ -1776,7 +1779,7 @@ def _brent(F, p, N): G = Rx.one() # loop over an appropriate increasing sequence of lengths s - for s in misc.newton_method_sizes(N): + for s in newton_method_sizes(N): # zero-extend to s terms # todo: there has to be a better way in Sage to do this... G = Rx(G.list(), s) diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index e4344334d81..309b62e05c1 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -40,7 +40,7 @@ from sage.structure.sage_object import SageObject -from sage.matrix.constructor import Matrix as matrix +from sage.matrix.constructor import matrix from sage.matrix.special import identity_matrix from sage.geometry.fan import Fan from sage.geometry.lattice_polytope import LatticePolytope diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 784a09daf4c..cc65dcb7cc1 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -188,7 +188,7 @@ cdef class CategoryObject(SageObject): if self._category is None: self._init_category_(category) return - if not (type(category) == tuple or type(category) == list): + if not isinstance(category, (tuple, list)): category = [category] self._category = self._category.join([self._category]+list(category)) diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index f5894af43ac..fa5157b3a65 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -9,7 +9,7 @@ sage: R. = PowerSeriesRing(QQ) sage: R.default_prec() 20 - sage: cos(x) # optional - sage.symbolic + sage: cos(x) # needs sage.symbolic 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 - 1/3628800*x^10 + 1/479001600*x^12 - 1/87178291200*x^14 + 1/20922789888000*x^16 - 1/6402373705728000*x^18 + O(x^20) @@ -19,7 +19,7 @@ sage: R. = PowerSeriesRing(QQ, default_prec=10) sage: R.default_prec() 10 - sage: cos(x) + sage: cos(x) # needs sage.symbolic 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 + O(x^10) .. NOTE:: diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 7a1fdb66d80..ce8f8d3b850 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -238,7 +238,7 @@ Check that :trac:`9880` is fixed:: 11/27*b_0/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ 11/27*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ 11/27*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 \ + 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 sage: f.nops() 38 diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index f3aad785d3f..2db60e8f915 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -604,7 +604,7 @@ def __eq__(self, other): sage: F == F True """ - return type(self) == type(other) and self.vars == other.vars + return type(self) is type(other) and self.vars == other.vars def __ne__(self, other): r""" @@ -767,7 +767,7 @@ def merge(self, other): """ if self == other: return self - elif type(self) == type(other): + elif type(self) is type(other): return type(self)(self.vars | other.vars) elif isinstance(other, SymbolicSubringRejectingVarsFunctor): if not (self.vars & other.vars): @@ -968,7 +968,7 @@ def merge(self, other): """ if self == other: return self - elif type(self) == type(other): + elif type(self) is type(other): return type(self)(self.vars & other.vars) elif isinstance(other, SymbolicSubringAcceptingVarsFunctor): if not (self.vars & other.vars): diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index b4f5bfe47d1..c056e43aa55 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -21,10 +21,10 @@ sage: factor(31415926535898) 2 * 3 * 53 * 73 * 2531 * 534697 sage: n = 7403756347956171282804679609742957314259318888\ -...9231289084936232638972765034028266276891996419625117\ -...8439958943305021275853701189680982867331732731089309\ -...0055250511687706329907239638078671008609696253793465\ -...0563796359 +....: 9231289084936232638972765034028266276891996419625117\ +....: 8439958943305021275853701189680982867331732731089309\ +....: 0055250511687706329907239638078671008609696253793465\ +....: 0563796359 sage: len(n.str(2)) 704 sage: len(n.str(10)) diff --git a/src/sage/topology/all.py b/src/sage/topology/all.py index 354039b6c94..87b6e7775da 100644 --- a/src/sage/topology/all.py +++ b/src/sage/topology/all.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs from .simplicial_complex import SimplicialComplex, Simplex from .simplicial_complex_morphism import SimplicialComplexMorphism diff --git a/src/sage/topology/cell_complex.py b/src/sage/topology/cell_complex.py index f2981862c74..906936a44c1 100644 --- a/src/sage/topology/cell_complex.py +++ b/src/sage/topology/cell_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Generic cell complexes @@ -503,25 +503,26 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: + sage: # needs sage.modules sage: P = delta_complexes.RealProjectivePlane() sage: P.homology() {0: 0, 1: C2, 2: 0} sage: P.homology(reduced=False) {0: Z, 1: C2, 2: 0} - sage: P.homology(base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: P.homology(base_ring=GF(2)) {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: S7 = delta_complexes.Sphere(7) - sage: S7.homology(7) # optional - sage.modules + sage: S7.homology(7) Z - sage: cubical_complexes.KleinBottle().homology(1, base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: cubical_complexes.KleinBottle().homology(1, base_ring=GF(2)) Vector space of dimension 2 over Finite Field of size 2 Sage can compute generators of homology groups:: sage: S2 = simplicial_complexes.Sphere(2) - sage: S2.homology(dim=2, generators=True, base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: S2.homology(dim=2, generators=True, base_ring=GF(2)) # needs sage.modules [(Vector space of dimension 1 over Finite Field of size 2, (0, 1, 2) + (0, 1, 3) + (0, 2, 3) + (1, 2, 3))] @@ -532,7 +533,7 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, complexes, each generator is a linear combination of cubes:: sage: S2_cub = cubical_complexes.Sphere(2) - sage: S2_cub.homology(dim=2, generators=True) # optional - sage.modules + sage: S2_cub.homology(dim=2, generators=True) # needs sage.modules [(Z, [0,0] x [0,1] x [0,1] - [0,1] x [0,0] x [0,1] + [0,1] x [0,1] x [0,0] - [0,1] x [0,1] x [1,1] + [0,1] x [1,1] x [0,1] - [1,1] x [0,1] x [0,1])] @@ -540,7 +541,7 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, Similarly for simpicial sets:: sage: S = simplicial_sets.Sphere(2) - sage: S.homology(generators=True) # optional - sage.modules + sage: S.homology(generators=True) # needs sage.modules {0: [], 1: 0, 2: [(Z, sigma_2)]} """ from sage.homology.homology_group import HomologyGroup @@ -617,36 +618,37 @@ def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: circle.cohomology(0) + sage: circle.cohomology(0) # needs sage.modules 0 - sage: circle.cohomology(1) + sage: circle.cohomology(1) # needs sage.modules Z Projective plane:: + sage: # needs sage.modules sage: P2 = SimplicialComplex([[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], ....: [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]]) - sage: P2.cohomology(2) # optional - sage.modules + sage: P2.cohomology(2) C2 - sage: P2.cohomology(2, base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: P2.cohomology(2, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 - sage: P2.cohomology(2, base_ring=GF(3)) # optional - sage.modules sage.rings.finite_rings + sage: P2.cohomology(2, base_ring=GF(3)) Vector space of dimension 0 over Finite Field of size 3 - sage: cubical_complexes.KleinBottle().cohomology(2) # optional - sage.modules + sage: cubical_complexes.KleinBottle().cohomology(2) # needs sage.modules C2 Relative cohomology:: sage: T = SimplicialComplex([[0,1]]) sage: U = SimplicialComplex([[0], [1]]) - sage: T.cohomology(1, subcomplex=U) # optional - sage.modules + sage: T.cohomology(1, subcomplex=U) # needs sage.modules Z A `\Delta`-complex example:: sage: s5 = delta_complexes.Sphere(5) - sage: s5.cohomology(base_ring=GF(7))[5] # optional - sage.modules sage.rings.finite_rings + sage: s5.cohomology(base_ring=GF(7))[5] # needs sage.modules Vector space of dimension 1 over Finite Field of size 7 """ return self.homology(dim=dim, cohomology=True, base_ring=base_ring, @@ -679,23 +681,23 @@ def betti(self, dim=None, subcomplex=None): two-point space with itself:: sage: S = SimplicialComplex([[0], [1]]) - sage: (S*S*S).betti() + sage: (S*S*S).betti() # needs sage.modules {0: 1, 1: 0, 2: 1} - sage: (S*S*S).betti([1,2]) + sage: (S*S*S).betti([1,2]) # needs sage.modules {1: 0, 2: 1} - sage: (S*S*S).betti(2) + sage: (S*S*S).betti(2) # needs sage.modules 1 Or build the two-sphere as a `\Delta`-complex:: sage: S2 = delta_complexes.Sphere(2) - sage: S2.betti([1,2]) + sage: S2.betti([1,2]) # needs sage.modules {1: 0, 2: 1} Or as a cubical complex:: sage: S2c = cubical_complexes.Sphere(2) - sage: S2c.betti(2) + sage: S2c.betti(2) # needs sage.modules 1 """ dict = {} @@ -722,9 +724,9 @@ def is_acyclic(self, base_ring=ZZ): EXAMPLES:: sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: RP2.is_acyclic() + sage: RP2.is_acyclic() # needs sage.modules False - sage: RP2.is_acyclic(QQ) + sage: RP2.is_acyclic(QQ) # needs sage.modules True This first computes the Euler characteristic: if it is not 1, @@ -734,8 +736,7 @@ def is_acyclic(self, base_ring=ZZ): sage: K = cubical_complexes.KleinBottle() sage: C = cubical_complexes.Cube(2) - sage: P = K.product(C) - sage: P + sage: P = K.product(C); P Cubical complex with 168 vertices and 1512 cubes sage: P.euler_characteristic() 0 @@ -770,11 +771,12 @@ def n_chains(self, n, base_ring=ZZ, cochains=False): EXAMPLES:: sage: S2 = simplicial_complexes.Sphere(2) - sage: S2.n_chains(1, QQ) - Free module generated by {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} over Rational Field - sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=False).basis()) + sage: S2.n_chains(1, QQ) # needs sage.modules + Free module generated by {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} + over Rational Field + sage: list(S2.n_chains(1, QQ, cochains=False).basis()) # needs sage.modules [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=True).basis()) + sage: list(S2.n_chains(1, QQ, cochains=True).basis()) # needs sage.modules [\chi_(0, 1), \chi_(0, 2), \chi_(0, 3), \chi_(1, 2), \chi_(1, 3), \chi_(2, 3)] """ from sage.homology.chains import Chains, Cochains @@ -839,27 +841,28 @@ def homology_with_basis(self, base_ring=QQ, cohomology=False): EXAMPLES:: + sage: # needs sage.modules sage: K = simplicial_complexes.KleinBottle() - sage: H = K.homology_with_basis(QQ); H # optional - sage.modules + sage: H = K.homology_with_basis(QQ); H Homology module of Minimal triangulation of the Klein bottle over Rational Field - sage: sorted(H.basis(), key=str) # optional - sage.modules + sage: sorted(H.basis(), key=str) [h_{0,0}, h_{1,0}] - sage: H = K.homology_with_basis(GF(2)); H # optional - sage.modules sage.rings.finite_rings + sage: H = K.homology_with_basis(GF(2)); H Homology module of Minimal triangulation of the Klein bottle over Finite Field of size 2 - sage: sorted(H.basis(), key=str) # optional - sage.modules sage.rings.finite_rings + sage: sorted(H.basis(), key=str) [h_{0,0}, h_{1,0}, h_{1,1}, h_{2,0}] The homology is constructed as a graded object, so for example, you can ask for the basis in a single degree:: - sage: H.basis(1) # optional - sage.modules sage.rings.finite_rings + sage: H.basis(1) # needs sage.modules Finite family {(1, 0): h_{1,0}, (1, 1): h_{1,1}} sage: S3 = delta_complexes.Sphere(3) - sage: H = S3.homology_with_basis(QQ, cohomology=True) # optional - sage.modules - sage: list(H.basis(3)) # optional - sage.modules + sage: H = S3.homology_with_basis(QQ, cohomology=True) # needs sage.modules + sage: list(H.basis(3)) # needs sage.modules [h^{3,0}] """ from sage.homology.homology_vector_space_with_basis import HomologyVectorSpaceWithBasis @@ -898,35 +901,37 @@ def cohomology_ring(self, base_ring=QQ): EXAMPLES:: + sage: # needs sage.modules sage: K = simplicial_complexes.KleinBottle() sage: H = K.cohomology_ring(QQ); H Cohomology ring of Minimal triangulation of the Klein bottle over Rational Field sage: sorted(H.basis(), key=str) [h^{0,0}, h^{1,0}] - sage: H = K.cohomology_ring(GF(2)); H # optional - sage.rings.finite_rings + sage: H = K.cohomology_ring(GF(2)); H Cohomology ring of Minimal triangulation of the Klein bottle over Finite Field of size 2 - sage: sorted(H.basis(), key=str) # optional - sage.rings.finite_rings + sage: sorted(H.basis(), key=str) [h^{0,0}, h^{1,0}, h^{1,1}, h^{2,0}] sage: X = delta_complexes.SurfaceOfGenus(2) - sage: H = X.cohomology_ring(QQ); H + sage: H = X.cohomology_ring(QQ); H # needs sage.modules Cohomology ring of Delta complex with 3 vertices and 29 simplices over Rational Field - sage: sorted(H.basis(1), key=str) + sage: sorted(H.basis(1), key=str) # needs sage.modules [h^{1,0}, h^{1,1}, h^{1,2}, h^{1,3}] - sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H + sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H # needs sage.modules Cohomology ring of Minimal triangulation of the torus over Rational Field - sage: x = H.basis()[1,0]; x + sage: x = H.basis()[1,0]; x # needs sage.modules h^{1,0} - sage: y = H.basis()[1,1]; y + sage: y = H.basis()[1,1]; y # needs sage.modules h^{1,1} You can compute cup products of cohomology classes:: + sage: # needs sage.modules sage: x.cup_product(y) -h^{2,0} sage: x * y # alternate notation @@ -938,12 +943,13 @@ def cohomology_ring(self, base_ring=QQ): Cohomology operations:: - sage: RP2 = simplicial_complexes.RealProjectivePlane() # optional - sage.groups - sage: K = RP2.suspension() # optional - sage.graphs sage.groups - sage: K.set_immutable() # optional - sage.graphs sage.groups - sage: y = K.cohomology_ring(GF(2)).basis()[2,0]; y # optional - sage.graphs sage.groups sage.rings.finite_rings + sage: # needs sage.groups + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: K = RP2.suspension() + sage: K.set_immutable() + sage: y = K.cohomology_ring(GF(2)).basis()[2,0]; y # needs sage.modules h^{2,0} - sage: y.Sq(1) # optional - sage.graphs sage.groups sage.rings.finite_rings + sage: y.Sq(1) # needs sage.modules h^{3,0} To compute the cohomology ring, the complex must be @@ -957,14 +963,14 @@ def cohomology_ring(self, base_ring=QQ): sage: T = S1.product(S1) sage: T.is_immutable() False - sage: T.cohomology_ring() + sage: T.cohomology_ring() # needs sage.modules Traceback (most recent call last): ... ValueError: this simplicial complex must be immutable; call set_immutable() sage: T.set_immutable() - sage: T.cohomology_ring() + sage: T.cohomology_ring() # needs sage.modules Cohomology ring of Simplicial complex with 9 vertices and - 18 facets over Rational Field + 18 facets over Rational Field """ from sage.homology.homology_vector_space_with_basis import CohomologyRing return CohomologyRing(base_ring, self) @@ -1036,13 +1042,13 @@ def face_poset(self): EXAMPLES:: - sage: P = SimplicialComplex([[0, 1], [1,2], [2,3]]).face_poset(); P # optional - sage.combinat sage.graphs + sage: P = SimplicialComplex([[0, 1], [1,2], [2,3]]).face_poset(); P Finite poset containing 7 elements - sage: sorted(P.list()) # optional - sage.combinat sage.graphs + sage: sorted(P.list()) [(0,), (0, 1), (1,), (1, 2), (2,), (2, 3), (3,)] sage: S2 = cubical_complexes.Sphere(2) - sage: S2.face_poset() # optional - sage.combinat sage.graphs + sage: S2.face_poset() Finite poset containing 26 elements """ from sage.combinat.posets.posets import Poset @@ -1086,24 +1092,24 @@ def is_connected(self): sage: V = SimplicialComplex([[0,1,2],[3]]); V Simplicial complex with vertex set (0, 1, 2, 3) and facets {(3,), (0, 1, 2)} - sage: V.is_connected() # optional - sage.graphs + sage: V.is_connected() False sage: X = SimplicialComplex([[0,1,2]]) - sage: X.is_connected() # optional - sage.graphs + sage: X.is_connected() True sage: U = simplicial_complexes.ChessboardComplex(3,3) - sage: U.is_connected() # optional - sage.graphs + sage: U.is_connected() True sage: W = simplicial_complexes.Sphere(3) - sage: W.is_connected() # optional - sage.graphs + sage: W.is_connected() True sage: S = SimplicialComplex([[0,1],[2,3]]) - sage: S.is_connected() # optional - sage.graphs + sage: S.is_connected() False - sage: cubical_complexes.Sphere(0).is_connected() # optional - sage.graphs + sage: cubical_complexes.Sphere(0).is_connected() False - sage: cubical_complexes.Sphere(2).is_connected() # optional - sage.graphs + sage: cubical_complexes.Sphere(2).is_connected() True """ return self.graph().is_connected() diff --git a/src/sage/topology/cubical_complex.py b/src/sage/topology/cubical_complex.py index 3ada7a7c8a2..c26ff4e08bb 100644 --- a/src/sage/topology/cubical_complex.py +++ b/src/sage/topology/cubical_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite cubical complexes @@ -46,11 +46,11 @@ segment in the plane from `(0,2)` to `(0,3)`. We could form a topologically equivalent space by inserting some degenerate simplices:: - sage: S1.homology() + sage: S1.homology() # needs sage.modules {0: 0, 1: Z} sage: X = CubicalComplex([([0,0], [2,3], [2]), ([0,1], [3,3], [2]), ....: ([0,1], [2,2], [2]), ([1,1], [2,3], [2])]) - sage: X.homology() + sage: X.homology() # needs sage.modules {0: 0, 1: Z} Topologically, the cubical complex ``X`` consists of four edges of a @@ -75,11 +75,13 @@ from sage.sets.set import Set from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.superseded import deprecation from functools import total_ordering +lazy_import('sage.matrix.constructor', 'matrix') + @total_ordering class Cube(SageObject): @@ -776,7 +778,7 @@ class :class:`Cube`, or lists or tuples suitable for conversion to sage: S1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), ....: ([0,1], [2,2]), ([1,1], [2,3])]); S1 Cubical complex with 4 vertices and 8 cubes - sage: S1.homology() + sage: S1.homology() # needs sage.modules {0: 0, 1: Z} A set of five points and its product with ``S1``:: @@ -784,18 +786,18 @@ class :class:`Cube`, or lists or tuples suitable for conversion to sage: pts = CubicalComplex([([0],), ([3],), ([6],), ([-12],), ([5],)]) sage: pts Cubical complex with 5 vertices and 5 cubes - sage: pts.homology() + sage: pts.homology() # needs sage.modules {0: Z x Z x Z x Z} sage: X = S1.product(pts); X Cubical complex with 20 vertices and 40 cubes - sage: X.homology() + sage: X.homology() # needs sage.modules {0: Z x Z x Z x Z, 1: Z^5} Converting a simplicial complex to a cubical complex:: sage: S2 = simplicial_complexes.Sphere(2) sage: C2 = CubicalComplex(S2) - sage: all(C2.homology(n) == S2.homology(n) for n in range(3)) + sage: all(C2.homology(n) == S2.homology(n) for n in range(3)) # needs sage.modules True You can get the set of maximal cells or a dictionary of all cells:: @@ -832,14 +834,14 @@ class :class:`Cube`, or lists or tuples suitable for conversion to sage: T = S1.product(S1); T Cubical complex with 16 vertices and 64 cubes - sage: T.chain_complex() + sage: T.chain_complex() # needs sage.modules Chain complex with at most 3 nonzero terms over Integer Ring - sage: T.homology(base_ring=QQ) # optional - sage.modules + sage: T.homology(base_ring=QQ) # needs sage.modules {0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: RP2.cohomology(dim=[1, 2], base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: RP2.cohomology(dim=[1, 2], base_ring=GF(2)) # needs sage.modules {1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} @@ -1168,6 +1170,7 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: S2 = cubical_complexes.Sphere(2) sage: S2.chain_complex() Chain complex with at most 3 nonzero terms over Integer Ring @@ -1186,6 +1189,7 @@ def chain_complex(self, subcomplex=None, augmented=False, Check that :trac:`32203` has been fixed:: + sage: # needs sage.modules sage: Square = CubicalComplex([([0,1],[0,1])]) sage: EdgesLTR = CubicalComplex([([0,0],[0,1]),([0,1],[1,1]),([1,1],[0,1])]) sage: EdgesLBR = CubicalComplex([([0,0],[0,1]),([0,1],[0,0]),([1,1],[0,1])]) @@ -1332,7 +1336,7 @@ def graph(self): EXAMPLES:: - sage: cubical_complexes.Sphere(2).graph() # optional - sage.graphs + sage: cubical_complexes.Sphere(2).graph() Graph on 8 vertices """ from sage.graphs.graph import Graph @@ -1480,7 +1484,7 @@ def disjoint_union(self, other): sage: S1 = cubical_complexes.Sphere(1) sage: S2 = cubical_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ embedded_left = len(tuple(self.maximal_cells()[0])) @@ -1515,7 +1519,7 @@ def wedge(self, other): sage: S1 = cubical_complexes.Sphere(1) sage: S2 = cubical_complexes.Sphere(2) - sage: S1.wedge(S2).homology() + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ embedded_left = len(tuple(self.maximal_cells()[0])) @@ -1551,12 +1555,12 @@ def connected_sum(self, other): sage: T = cubical_complexes.Torus() sage: S2 = cubical_complexes.Sphere(2) - sage: T.connected_sum(S2).cohomology() == T.cohomology() # optional - sage.modules + sage: T.connected_sum(S2).cohomology() == T.cohomology() # needs sage.modules True sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: T.connected_sum(RP2).homology(1) # optional - sage.modules + sage: T.connected_sum(RP2).homology(1) # needs sage.modules Z x Z x C2 - sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) # optional - sage.modules + sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) # needs sage.modules Z x Z x C2 """ # connected_sum: first check whether the complexes are pure @@ -1671,15 +1675,16 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: + sage: # needs sage.modules sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: phi, M = RP2.algebraic_topological_model(GF(2)) # optional - sage.rings.finite_rings - sage: M.homology() # optional - sage.modules sage.rings.finite_rings + sage: phi, M = RP2.algebraic_topological_model(GF(2)) + sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: T = cubical_complexes.Torus() sage: phi, M = T.algebraic_topological_model(QQ) - sage: M.homology() # optional - sage.modules + sage: M.homology() {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -1755,7 +1760,7 @@ def _simplicial_(self): sage: Ts = T._simplicial_(); Ts Simplicial complex with 16 vertices and 32 facets - sage: T.homology() == Ts.homology() + sage: T.homology() == Ts.homology() # needs sage.modules True Each `n`-dimensional cube produces `n!` `n`-simplices:: diff --git a/src/sage/topology/delta_complex.py b/src/sage/topology/delta_complex.py index 24bd57c6caf..18888465713 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite Delta-complexes @@ -54,10 +54,12 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.integer import Integer -from sage.matrix.constructor import matrix from .simplicial_complex import Simplex, lattice_paths, SimplicialComplex from sage.arith.misc import binomial from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.matrix.constructor', 'matrix') class DeltaComplex(GenericCellComplex): @@ -105,7 +107,7 @@ class DeltaComplex(GenericCellComplex): Let's compute its homology, and also compare it to the simplicial version:: - sage: S5.homology() + sage: S5.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} sage: S5.f_vector() # number of simplices in each dimension [1, 6, 15, 20, 15, 6, 2] @@ -126,7 +128,7 @@ class DeltaComplex(GenericCellComplex): ....: Simplex(0): ()} sage: T = DeltaComplex(torus_dict); T Delta complex with 1 vertex and 7 simplices - sage: T.cohomology(base_ring=QQ) + sage: T.cohomology(base_ring=QQ) # needs sage.modules {0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -177,9 +179,9 @@ class DeltaComplex(GenericCellComplex): :: - sage: P.homology(1) + sage: P.homology(1) # needs sage.modules C2 - sage: P.cohomology(2) + sage: P.cohomology(2) # needs sage.modules C2 Closely related to this form for ``data`` is ``X.cells()`` @@ -244,7 +246,7 @@ def __init__(self, data=None, check_validity=True): sage: X = DeltaComplex({Simplex(3):True, Simplex(range(1,5)): Simplex(3), Simplex(range(2,6)): Simplex(3)}); X # indirect doctest Delta complex with 4 vertices and 18 simplices - sage: X.homology() + sage: X.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z x Z} sage: X == loads(dumps(X)) True @@ -403,7 +405,7 @@ def subcomplex(self, data): sage: X = delta_complexes.Torus() sage: A = X.subcomplex({2: [0]}) # one of the triangles of X - sage: X.homology(subcomplex=A) + sage: X.homology(subcomplex=A) # needs sage.modules {0: 0, 1: 0, 2: Z} In the following, ``line`` is a line segment and ``ends`` is @@ -416,7 +418,7 @@ def subcomplex(self, data): sage: ends = line.subcomplex({0: (0, 1)}) sage: ends.cells() {-1: ((),), 0: ((), ())} - sage: line.homology(subcomplex=ends) + sage: line.homology(subcomplex=ends) # needs sage.modules {0: 0, 1: Z} """ if isinstance(data, (list, tuple)): @@ -605,6 +607,7 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: circle = delta_complexes.Sphere(1) sage: circle.chain_complex() Chain complex with at most 2 nonzero terms over Integer Ring @@ -749,7 +752,7 @@ def n_skeleton(self, n): Delta complex with 4 vertices and 11 simplices sage: S3.n_skeleton(1).dimension() 1 - sage: S3.n_skeleton(1).homology() + sage: S3.n_skeleton(1).homology() # needs sage.modules {0: 0, 1: Z x Z x Z} """ if n >= self.dimension(): @@ -811,14 +814,14 @@ def join(self, other): sage: K = delta_complexes.KleinBottle() sage: T_simp = simplicial_complexes.Torus() sage: K_simp = simplicial_complexes.KleinBottle() - sage: T.join(K).homology()[3] == T_simp.join(K_simp).homology()[3] # long time (3 seconds) + sage: T.join(K).homology()[3] == T_simp.join(K_simp).homology()[3] # long time (3 seconds), needs sage.modules True The notation '*' may be used, as well:: sage: S1 = delta_complexes.Sphere(1) sage: X = S1 * S1 # X is a 3-sphere - sage: X.homology() + sage: X.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ data = [] @@ -893,7 +896,7 @@ def cone(self): sage: K = delta_complexes.KleinBottle() sage: K.cone() Delta complex with 2 vertices and 14 simplices - sage: K.cone().homology() + sage: K.cone().homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} """ return self.join(delta_complexes.Simplex(0)) @@ -916,7 +919,7 @@ def suspension(self, n=1): sage: S = delta_complexes.Sphere(0) sage: S3 = S.suspension(3) # the 3-sphere - sage: S3.homology() + sage: S3.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ if n < 0: @@ -944,22 +947,25 @@ def product(self, other): sage: K = delta_complexes.KleinBottle() sage: X = K.product(K) - sage: X.homology(1) # optional - sage.modules + + sage: # needs sage.modules + sage: X.homology(1) Z x Z x C2 x C2 - sage: X.homology(2) # optional - sage.modules + sage: X.homology(2) Z x C2 x C2 x C2 - sage: X.homology(3) # optional - sage.modules + sage: X.homology(3) C2 - sage: X.homology(4) # optional - sage.modules + sage: X.homology(4) 0 - sage: X.homology(base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: X.homology(base_ring=GF(2)) {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 4 over Finite Field of size 2, 2: Vector space of dimension 6 over Finite Field of size 2, 3: Vector space of dimension 4 over Finite Field of size 2, 4: Vector space of dimension 1 over Finite Field of size 2} + sage: S1 = delta_complexes.Sphere(1) - sage: K.product(S1).homology() == S1.product(K).homology() # optional - sage.modules + sage: K.product(S1).homology() == S1.product(K).homology() # needs sage.modules True sage: S1.product(S1) == delta_complexes.Torus() True @@ -1063,7 +1069,7 @@ def disjoint_union(self, right): sage: S1 = delta_complexes.Sphere(1) sage: S2 = delta_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() # optional - sage.modules + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ dim = max(self.dimension(), right.dimension()) @@ -1095,7 +1101,7 @@ def wedge(self, right): sage: S1 = delta_complexes.Sphere(1) sage: S2 = delta_complexes.Sphere(2) - sage: S1.wedge(S2).homology() # optional - sage.modules + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ data = self.disjoint_union(right).cells() @@ -1144,16 +1150,17 @@ def connected_sum(self, other): EXAMPLES:: + sage: # needs sage.modules sage: T = delta_complexes.Torus() sage: S2 = delta_complexes.Sphere(2) - sage: T.connected_sum(S2).cohomology() == T.cohomology() # optional - sage.modules + sage: T.connected_sum(S2).cohomology() == T.cohomology() True sage: RP2 = delta_complexes.RealProjectivePlane() - sage: T.connected_sum(RP2).homology(1) # optional - sage.modules + sage: T.connected_sum(RP2).homology(1) Z x Z x C2 - sage: T.connected_sum(RP2).homology(2) # optional - sage.modules + sage: T.connected_sum(RP2).homology(2) 0 - sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) # optional - sage.modules + sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) Z x Z x C2 """ if not self.dimension() == other.dimension(): @@ -1272,7 +1279,7 @@ def elementary_subdivision(self, idx=-1): Delta complex with 2 vertices and 13 simplices sage: X.elementary_subdivision() Delta complex with 3 vertices and 19 simplices - sage: X.homology() == T.homology() # optional - sage.modules + sage: X.homology() == T.homology() # needs sage.modules True """ pi = self._epi_from_standard_simplex(idx=idx) @@ -1453,7 +1460,7 @@ def face_poset(self): EXAMPLES:: sage: T = delta_complexes.Torus() - sage: T.face_poset() # optional - sage.combinat sage.graphs + sage: T.face_poset() Finite poset containing 6 elements """ from sage.combinat.posets.posets import Poset @@ -1517,11 +1524,12 @@ def n_chains(self, n, base_ring=None, cochains=False): EXAMPLES:: sage: T = delta_complexes.Torus() - sage: T.n_chains(1, QQ) - Free module generated by {(0, (0, 0)), (1, (0, 0)), (2, (0, 0))} over Rational Field - sage: list(T.n_chains(1, QQ, cochains=False).basis()) + sage: T.n_chains(1, QQ) # needs sage.modules + Free module generated by {(0, (0, 0)), (1, (0, 0)), (2, (0, 0))} + over Rational Field + sage: list(T.n_chains(1, QQ, cochains=False).basis()) # needs sage.modules [(0, (0, 0)), (1, (0, 0)), (2, (0, 0))] - sage: list(T.n_chains(1, QQ, cochains=True).basis()) + sage: list(T.n_chains(1, QQ, cochains=True).basis()) # needs sage.modules [\chi_(0, (0, 0)), \chi_(1, (0, 0)), \chi_(2, (0, 0))] """ from sage.homology.chains import Chains, Cochains @@ -1580,15 +1588,16 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: + sage: # needs sage.modules sage: RP2 = delta_complexes.RealProjectivePlane() - sage: phi, M = RP2.algebraic_topological_model(GF(2)) # optional - sage.rings.finite_rings - sage: M.homology() # optional - sage.modules sage.rings.finite_rings + sage: phi, M = RP2.algebraic_topological_model(GF(2)) + sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: T = delta_complexes.Torus() sage: phi, M = T.algebraic_topological_model(QQ) - sage: M.homology() # optional - sage.modules + sage: M.homology() {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -1632,7 +1641,7 @@ class DeltaComplexExamples(): sage: S = delta_complexes.Sphere(6) # the 6-sphere sage: S.dimension() 6 - sage: S.cohomology(6) + sage: S.cohomology(6) # needs sage.modules Z sage: delta_complexes.Torus() == delta_complexes.Sphere(3) False @@ -1649,7 +1658,7 @@ def Sphere(self, n): EXAMPLES:: - sage: delta_complexes.Sphere(4).cohomology(4, base_ring=GF(3)) # optional - sage.modules sage.rings.finite_rings + sage: delta_complexes.Sphere(4).cohomology(4, base_ring=GF(3)) # needs sage.modules Vector space of dimension 1 over Finite Field of size 3 """ if n == 1: @@ -1665,7 +1674,7 @@ def Torus(self): EXAMPLES:: - sage: delta_complexes.Torus().homology(1) + sage: delta_complexes.Torus().homology(1) # needs sage.modules sage.rings.finite_rings Z x Z """ return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), @@ -1680,14 +1689,15 @@ def RealProjectivePlane(self): EXAMPLES:: + sage: # needs sage.modules sage: P = delta_complexes.RealProjectivePlane() - sage: P.cohomology(1) # optional - sage.modules + sage: P.cohomology(1) 0 - sage: P.cohomology(2) # optional - sage.modules + sage: P.cohomology(2) C2 - sage: P.cohomology(dim=1, base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: P.cohomology(dim=1, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 - sage: P.cohomology(dim=2, base_ring=GF(2)) # optional - sage.modules sage.rings.finite_rings + sage: P.cohomology(dim=2, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 """ return DeltaComplex((((), ()), ((1, 0), (1, 0), (0, 0)), @@ -1743,9 +1753,9 @@ def SurfaceOfGenus(self, g, orientable=True): sage: delta_complexes.SurfaceOfGenus(1, orientable=False) Delta complex with 2 vertices and 8 simplices - sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(1) # optional - sage.modules + sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(1) # needs sage.modules Z x Z x C2 - sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(2) # optional - sage.modules + sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(2) # needs sage.modules 0 Compare to simplicial complexes:: @@ -1756,7 +1766,7 @@ def SurfaceOfGenus(self, g, orientable=True): sage: simpl_g4 = simplicial_complexes.SurfaceOfGenus(4) sage: simpl_g4.f_vector() [1, 19, 75, 50] - sage: delta_g4.homology() == simpl_g4.homology() # optional - sage.modules + sage: delta_g4.homology() == simpl_g4.homology() # needs sage.modules True """ try: diff --git a/src/sage/topology/filtered_simplicial_complex.py b/src/sage/topology/filtered_simplicial_complex.py index c7bf66a66cb..95191dd1cd4 100644 --- a/src/sage/topology/filtered_simplicial_complex.py +++ b/src/sage/topology/filtered_simplicial_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite filtered complexes @@ -22,20 +22,20 @@ Sage can compute persistent homology of simplicial complexes:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)]) - sage: X.persistence_intervals(0) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(0) # needs sage.modules [(0, 1), (0, +Infinity)] FilteredSimplicialComplex objects are mutable. Filtration values can be set with the ``filtration`` method as follows:: sage: X = FilteredSimplicialComplex() # returns an empty complex - sage: X.persistence_intervals(1) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(1) # needs sage.modules [] sage: X.filtration(Simplex([0, 2]), 0) # recursively adds faces sage: X.filtration(Simplex([0, 1]), 0) sage: X.filtration(Simplex([1, 2]), 0) sage: X.filtration(Simplex([0, 1, 2]), 1) # closes the circle - sage: X.persistence_intervals(1) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(1) # needs sage.modules [(0, 1)] The filtration value of a simplex can be accessed as well with the @@ -83,13 +83,15 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sage_object import SageObject -from sage.topology.simplicial_complex import Simplex, SimplicialComplex -from sage.modules.free_module import FreeModule -from sage.rings.finite_rings.finite_field_constructor import GF +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.misc.cachefunc import cached_method +from sage.structure.sage_object import SageObject +from sage.topology.simplicial_complex import Simplex, SimplicialComplex + +lazy_import('sage.modules.free_module', 'FreeModule') +lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') class FilteredSimplicialComplex(SageObject): @@ -396,7 +398,7 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X._persistent_homology()[0] # optional - sage.modules sage.rings.finite_rings + sage: X._persistent_homology()[0] # needs sage.modules [(0, 2), (0, +Infinity)] Some homology elements may have a lifespan or persistence of 0. @@ -404,7 +406,7 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): sage: X = FilteredSimplicialComplex() sage: X.insert([0,1],1) # opens a hole and closes it instantly - sage: X._persistent_homology(strict=False)[0] # optional - sage.modules sage.rings.finite_rings + sage: X._persistent_homology(strict=False)[0] # needs sage.modules [(1, 1), (1, +Infinity)] REFERENCES: @@ -419,11 +421,11 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): ....: ([1, 2], 1), ([0, 3], 2), ([2, 3], 2), ([0, 2], 3), ....: ([0, 1, 2], 4), ([0, 2, 3], 5)] sage: X = FilteredSimplicialComplex(l) - sage: X.persistence_intervals(0) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(0) # needs sage.modules [(0, 1), (1, 2), (0, +Infinity)] - sage: X.persistence_intervals(1) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(1) # needs sage.modules [(3, 4), (2, 5)] - sage: X.persistence_intervals(0, strict=False) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(0, strict=False) # needs sage.modules [(0, 1), (1, 1), (1, 2), (0, +Infinity)] """ # first, order the simplices in lexico order @@ -508,19 +510,20 @@ def _add_interval(self, s, t, intervals): TESTS:: + sage: # needs sage.modules sage: X = FilteredSimplicialComplex([([0], 0), ([1, 2], 10)]) - sage: int_list = X._persistent_homology() # optional - sage.modules sage.rings.finite_rings - sage: int_list[0] # optional - sage.modules sage.rings.finite_rings + sage: int_list = X._persistent_homology() + sage: int_list[0] [(0, +Infinity), (10, +Infinity)] - sage: X._add_interval(Simplex([0]), Simplex([1, 2]), int_list) # optional - sage.modules sage.rings.finite_rings - sage: int_list[0] # optional - sage.modules sage.rings.finite_rings + sage: X._add_interval(Simplex([0]), Simplex([1, 2]), int_list) + sage: int_list[0] [(0, +Infinity), (10, +Infinity), (0, 10)] Infinite interval:: sage: int_list2 = [[],[]] - sage: X._add_interval(Simplex([1, 2]), None, int_list2) # optional - sage.modules sage.rings.finite_rings - sage: int_list2[1] # optional - sage.modules sage.rings.finite_rings + sage: X._add_interval(Simplex([1, 2]), None, int_list2) # needs sage.modules + sage: int_list2[1] [(10, +Infinity)] """ # figure out dimension of homology element @@ -554,12 +557,12 @@ def _remove_pivot_rows(self, s, simplices): sage: l = [([0], 0), ([1], 0), ([2], 1), ([3], 1), ([0, 1], 1), ([1, 2], 1), ....: ([0, 3], 2), ([2, 3], 2), ([0, 2], 3), ([0, 1, 2], 4)] sage: X = FilteredSimplicialComplex(l) - sage: X._persistent_homology() # optional - sage.modules sage.rings.finite_rings + sage: X._persistent_homology() # needs sage.modules [[(0, 1), (1, 2), (0, +Infinity)], [(3, 4), (2, +Infinity)], []] - sage: X._remove_pivot_rows(Simplex([0,1,2]), list(X._filtration_dict)) # optional - sage.modules sage.rings.finite_rings + sage: X._remove_pivot_rows(Simplex([0,1,2]), list(X._filtration_dict)) # needs sage.modules 0 sage: X.insert([0,2,3],5) - sage: X._remove_pivot_rows(Simplex([0,2,3]), list(X._filtration_dict)) # optional - sage.modules sage.rings.finite_rings + sage: X._remove_pivot_rows(Simplex([0,2,3]), list(X._filtration_dict)) # needs sage.modules B[(2, 3)] """ d = self._chaingroup() @@ -604,13 +607,14 @@ def _max_index(self, d): TESTS:: + sage: # needs sage.modules sage: X = FilteredSimplicialComplex([([0], 0), ([1], 5), ([0, 1], 18), ([0, 2, 3], 32)]) - sage: X._persistent_homology() # optional - sage.modules sage.rings.finite_rings + sage: X._persistent_homology() [[(5, 18), (0, +Infinity)], [], []] - sage: a = X._chaingroup(Simplex([0, 1])) # optional - sage.modules sage.rings.finite_rings - sage: b = X._chaingroup(Simplex([0, 3])) # optional - sage.modules sage.rings.finite_rings - sage: d = a + b # optional - sage.modules sage.rings.finite_rings - sage: X._max_index(d) # optional - sage.modules sage.rings.finite_rings + sage: a = X._chaingroup(Simplex([0, 1])) + sage: b = X._chaingroup(Simplex([0, 3])) + sage: d = a + b + sage: X._max_index(d) 6 """ currmax = -1 @@ -639,7 +643,7 @@ def persistence_intervals(self, dimension, field=2, strict=True, verbose=None): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 1), ([0,1], 2)]) - sage: X.persistence_intervals(0) # optional - sage.modules sage.rings.finite_rings + sage: X.persistence_intervals(0) # needs sage.modules [(1, 2), (0, +Infinity)] """ if verbose is None: @@ -674,16 +678,16 @@ def betti_number(self, k, a, b, field=2, strict=True, verbose=None): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X.betti_number(0, 0.5, 1) # optional - sage.modules sage.rings.finite_rings + sage: X.betti_number(0, 0.5, 1) # needs sage.modules 2 - sage: X.betti_number(0, 1.5, 1) # optional - sage.modules sage.rings.finite_rings + sage: X.betti_number(0, 1.5, 1) # needs sage.modules 1 If an element vanishes at time ``a + b`` exactly, it does not count towards the Betti number:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X.betti_number(0, 1.5, 0.5) # optional - sage.modules sage.rings.finite_rings + sage: X.betti_number(0, 1.5, 0.5) # needs sage.modules 1 """ if verbose is None: diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 91f7deb1486..d3959b55b92 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite simplicial complexes @@ -92,7 +92,7 @@ sage: T = S.product(S) # torus sage: T Simplicial complex with 9 vertices and 18 facets - sage: T.homology() # this computes reduced homology # optional - sage.modules + sage: T.homology() # this computes reduced homology # needs sage.modules {0: 0, 1: Z x Z, 2: Z} sage: T.euler_characteristic() 0 @@ -105,8 +105,8 @@ [1, 4, 4] sage: X.face_poset() Finite poset containing 8 elements - sage: x0, x1, x2, x3 = X.stanley_reisner_ring().gens() - sage: x0*x2 == x1*x3 == 0 + sage: x0, x1, x2, x3 = X.stanley_reisner_ring().gens() # needs sage.libs.singular + sage: x0*x2 == x1*x3 == 0 # needs sage.libs.singular True sage: X.is_pure() True @@ -173,10 +173,11 @@ from sage.structure.category_object import normalize_names from sage.misc.latex import latex from sage.misc.superseded import deprecation -from sage.matrix.constructor import matrix from functools import total_ordering from itertools import combinations, chain + lazy_import('sage.categories.simplicial_complexes', 'SimplicialComplexes') +lazy_import('sage.matrix.constructor', 'matrix') def lattice_paths(t1, t2, length=None): @@ -894,7 +895,7 @@ class SimplicialComplex(Parent, GenericCellComplex): Cubical complex with 16 vertices and 64 cubes sage: Ts = SimplicialComplex(Tc); Ts Simplicial complex with 16 vertices and 32 facets - sage: Ts.homology() # optional - sage.modules + sage: Ts.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} In the situation where the first argument is a simplicial complex @@ -914,9 +915,9 @@ class SimplicialComplex(Parent, GenericCellComplex): or e.g. the simplicial complex of all 168 hyperovals of the projective plane of order 4:: - sage: l = designs.ProjectiveGeometryDesign(2,1,GF(4,name='a')) + sage: l = designs.ProjectiveGeometryDesign(2, 1, GF(4,name='a')) # needs sage.rings.finite_rings sage: f = lambda S: not any(len(set(S).intersection(x))>2 for x in l) - sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) + sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) # needs sage.rings.finite_rings Simplicial complex with 21 vertices and 168 facets TESTS: @@ -1483,12 +1484,13 @@ def g_vector(self): EXAMPLES:: - sage: S3 = simplicial_complexes.Sphere(3).barycentric_subdivision() # optional - sage.combinat sage.graphs - sage: S3.f_vector() # optional - sage.combinat sage.graphs + sage: # needs sage.combinat + sage: S3 = simplicial_complexes.Sphere(3).barycentric_subdivision() + sage: S3.f_vector() [1, 30, 150, 240, 120] - sage: S3.h_vector() # optional - sage.combinat sage.graphs + sage: S3.h_vector() [1, 26, 66, 26, 1] - sage: S3.g_vector() # optional - sage.combinat sage.graphs + sage: S3.g_vector() [1, 25, 40] """ d = self.dimension() @@ -1610,14 +1612,14 @@ def F_triangle(self, S): EXAMPLES:: sage: cs = simplicial_complexes.Torus() - sage: cs.F_triangle(cs.facets()[0]) # optional - sage.combinat + sage: cs.F_triangle(cs.facets()[0]) # needs sage.combinat F: x^3 + 9*x^2*y + 3*x*y^2 + y^3 + 6*x^2 + 12*x*y + 3*y^2 + 4*x + 3*y + 1 TESTS:: sage: S = SimplicialComplex([]) - sage: S.F_triangle(S.facets()[0]) # optional - sage.combinat + sage: S.F_triangle(S.facets()[0]) # needs sage.combinat F: 1 """ x, y = polygens(ZZ, 'x, y') @@ -1647,29 +1649,29 @@ def flip_graph(self): EXAMPLES:: sage: S0 = simplicial_complexes.Sphere(0) - sage: G = S0.flip_graph() # optional - sage.graphs - sage: G.vertices(sort=True); G.edges(sort=True, labels=False) # optional - sage.graphs + sage: G = S0.flip_graph() + sage: G.vertices(sort=True); G.edges(sort=True, labels=False) [(0,), (1,)] [((0,), (1,))] - sage: G = (S0.wedge(S0)).flip_graph() # optional - sage.graphs - sage: G.vertices(sort=True); G.edges(sort=True, labels=False) # optional - sage.graphs + sage: G = (S0.wedge(S0)).flip_graph() + sage: G.vertices(sort=True); G.edges(sort=True, labels=False) [(0,), ('L1',), ('R1',)] [((0,), ('L1',)), ((0,), ('R1',)), (('L1',), ('R1',))] sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: G = (S1.wedge(S1)).flip_graph() # optional - sage.graphs - sage: len(G.vertices(sort=False)) # optional - sage.graphs + sage: G = (S1.wedge(S1)).flip_graph() + sage: len(G.vertices(sort=False)) 6 - sage: len(G.edges(sort=False)) # optional - sage.graphs + sage: len(G.edges(sort=False)) 10 - sage: (S1.wedge(S2)).flip_graph() is None # optional - sage.graphs + sage: (S1.wedge(S2)).flip_graph() is None True - sage: G = S2.flip_graph() # optional - sage.graphs - sage: G.vertices(sort=True); G.edges(sort=True, labels=False) # optional - sage.graphs + sage: G = S2.flip_graph() + sage: G.vertices(sort=True); G.edges(sort=True, labels=False) [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)] [((0, 1, 2), (0, 1, 3)), ((0, 1, 2), (0, 2, 3)), @@ -1678,9 +1680,9 @@ def flip_graph(self): ((0, 1, 3), (1, 2, 3)), ((0, 2, 3), (1, 2, 3))] - sage: T = simplicial_complexes.Torus() # optional - sage.graphs - sage: G = T.suspension(4).flip_graph() # optional - sage.graphs - sage: len(G.vertices(sort=False)); len(G.edges(sort=False, labels=False)) # optional - sage.graphs + sage: T = simplicial_complexes.Torus() + sage: G = T.suspension(4).flip_graph() + sage: len(G.vertices(sort=False)); len(G.edges(sort=False, labels=False)) 46 161 """ @@ -1731,20 +1733,20 @@ def is_pseudomanifold(self): EXAMPLES:: sage: S0 = simplicial_complexes.Sphere(0) - sage: S0.is_pseudomanifold() # optional - sage.graphs + sage: S0.is_pseudomanifold() True - sage: (S0.wedge(S0)).is_pseudomanifold() # optional - sage.graphs + sage: (S0.wedge(S0)).is_pseudomanifold() False sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: (S1.wedge(S1)).is_pseudomanifold() # optional - sage.graphs + sage: (S1.wedge(S1)).is_pseudomanifold() False - sage: (S1.wedge(S2)).is_pseudomanifold() # optional - sage.graphs + sage: (S1.wedge(S2)).is_pseudomanifold() False - sage: S2.is_pseudomanifold() # optional - sage.graphs + sage: S2.is_pseudomanifold() True sage: T = simplicial_complexes.Torus() - sage: T.suspension(4).is_pseudomanifold() # optional - sage.graphs + sage: T.suspension(4).is_pseudomanifold() True """ if not self.is_pure(): @@ -1806,7 +1808,7 @@ def product(self, right, rename_vertices=True, is_mutable=True): sage: T = S.product(S) # torus sage: T Simplicial complex with 9 vertices and 18 facets - sage: T.homology() # optional - sage.modules + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} These can get large pretty quickly:: @@ -1950,8 +1952,8 @@ def suspension(self, n=1, is_mutable=True): sage: S0 = SimplicialComplex([[0], [1]]) sage: S0.suspension() == simplicial_complexes.Sphere(1) True - sage: S3 = S0.suspension(3) # the 3-sphere # optional - sage.graphs - sage: S3.homology() # optional - sage.graphs sage.modules + sage: S3 = S0.suspension(3) # the 3-sphere + sage: S3.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} For pseudomanifolds, the complex constructed here will be @@ -2012,7 +2014,7 @@ def disjoint_union(self, right, rename_vertices=True, is_mutable=True): sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() # optional - sage.modules + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ facets = [] @@ -2052,7 +2054,7 @@ def wedge(self, right, rename_vertices=True, is_mutable=True): sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: S1.wedge(S2).homology() # optional - sage.modules + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ left_vertices = list(self.vertices()) @@ -2120,11 +2122,11 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: circle.chain_complex() # optional - sage.modules + sage: circle.chain_complex() # needs sage.modules Chain complex with at most 2 nonzero terms over Integer Ring - sage: circle.chain_complex()._latex_() # optional - sage.modules + sage: circle.chain_complex()._latex_() # needs sage.modules '\\Bold{Z}^{3} \\xrightarrow{d_{1}} \\Bold{Z}^{3}' - sage: circle.chain_complex(base_ring=QQ, augmented=True) # optional - sage.modules + sage: circle.chain_complex(base_ring=QQ, augmented=True) # needs sage.modules Chain complex with at most 3 nonzero terms over Rational Field """ # initialize subcomplex @@ -2315,6 +2317,7 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: + sage: # needs sage.modules sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: circle._homology_() {0: 0, 1: Z} @@ -2323,43 +2326,44 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, sage: sphere Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)} - sage: sphere._homology_() # optional - sage.modules + sage: sphere._homology_() {0: 0, 1: 0, 2: Z} - sage: sphere._homology_(reduced=False) # optional - sage.modules + sage: sphere._homology_(reduced=False) {0: Z, 1: 0, 2: Z} - sage: sphere._homology_(base_ring=GF(2), reduced=False) # optional - sage.modules sage.rings.finite_rings + sage: sphere._homology_(base_ring=GF(2), reduced=False) {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} We need an immutable complex to compute homology generators:: + sage: # needs sage.modules sage: sphere.set_immutable() - sage: sphere._homology_(generators=True) # optional - sage.modules + sage: sphere._homology_(generators=True) {0: [], 1: [], 2: [(Z, (0, 1, 2) - (0, 1, 3) + (0, 2, 3) - (1, 2, 3))]} Another way to get a two-sphere: take a two-point space and take its three-fold join with itself:: sage: S = SimplicialComplex([[0], [1]]) - sage: (S*S*S)._homology_(dim=2, cohomology=True) # optional - sage.modules + sage: (S*S*S)._homology_(dim=2, cohomology=True) # needs sage.modules Z The same computation, done without finding a contractible subcomplex:: - sage: (S*S*S)._homology_(dim=2, cohomology=True, enlarge=False) # optional - sage.modules + sage: (S*S*S)._homology_(dim=2, cohomology=True, enlarge=False) # needs sage.modules Z Relative homology:: sage: T = SimplicialComplex([[0,1,2]]) sage: U = SimplicialComplex([[0,1], [1,2], [0,2]]) - sage: T._homology_(subcomplex=U) # optional - sage.modules + sage: T._homology_(subcomplex=U) # needs sage.modules {0: 0, 1: 0, 2: Z} Generators:: - sage: simplicial_complexes.Torus().homology(generators=True) # optional - sage.modules + sage: simplicial_complexes.Torus().homology(generators=True) # needs sage.modules {0: [], 1: [(Z, (2, 4) - (2, 6) + (4, 6)), (Z, (1, 4) - (1, 6) + (4, 6))], 2: [(Z, (0, 1, 2) - (0, 1, 5) + (0, 2, 6) - (0, 3, 4) + (0, 3, 5) @@ -2495,15 +2499,16 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: - sage: RP2 = simplicial_complexes.RealProjectivePlane() # optional - sage.rings.finite_rings - sage: phi, M = RP2.algebraic_topological_model(GF(2)) # optional - sage.rings.finite_rings - sage: M.homology() # optional - sage.modules sage.rings.finite_rings + sage: # needs sage.modules + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: phi, M = RP2.algebraic_topological_model(GF(2)) + sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: T = simplicial_complexes.Torus() sage: phi, M = T.algebraic_topological_model(QQ) - sage: M.homology() # optional - sage.modules + sage: M.homology() {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -2576,10 +2581,10 @@ def add_face(self, face): Check that the bug reported at :trac:`14354` has been fixed:: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: T.homology() + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z x Z} sage: T.add_face([1,2,3]) - sage: T.homology() # optional - sage.modules + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: 0} Check that the ``_faces`` cache is treated correctly @@ -2587,19 +2592,19 @@ def add_face(self, face): sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) sage: _ = T.faces() # populate the _faces attribute - sage: _ = T.homology() # add more to _faces # optional - sage.modules - sage: T.add_face((1,2,3)) # optional - sage.modules - sage: all(Simplex((1,2,3)) in T._faces[L][2] for L in T._faces) # optional - sage.modules + sage: _ = T.homology() # add more to _faces # needs sage.modules + sage: T.add_face((1,2,3)) + sage: all(Simplex((1,2,3)) in T._faces[L][2] for L in T._faces) True Check that the ``__enlarged`` cache is treated correctly (:trac:`20758`):: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: T.homology() # to populate the __enlarged attribute # optional - sage.modules + sage: T.homology() # to populate the __enlarged attribute # needs sage.modules {0: 0, 1: Z x Z x Z} - sage: T.add_face([1,2,3]) # optional - sage.modules - sage: len(T._SimplicialComplex__enlarged) > 0 # optional - sage.modules + sage: T.add_face([1,2,3]) + sage: len(T._SimplicialComplex__enlarged) > 0 # needs sage.modules True Check we've fixed the bug reported at :trac:`14578`:: @@ -2608,7 +2613,7 @@ def add_face(self, face): sage: t0.add_face(('a', 'b')) sage: t0.add_face(('c', 'd', 'e')) sage: t0.add_face(('e', 'f', 'c')) - sage: t0.homology() # optional - sage.modules + sage: t0.homology() # needs sage.modules {0: Z, 1: 0, 2: 0} Check that we've fixed the bug reported at :trac:`22880`:: @@ -2723,13 +2728,13 @@ def remove_face(self, face, check=False): sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) sage: _ = T.faces() # populate the _faces attribute - sage: _ = T.homology() # add more to _faces # optional - sage.modules - sage: T.add_face((1,2,3)) # optional - sage.modules - sage: T.remove_face((1,2,3)) # optional - sage.modules - sage: len(T._faces) # optional - sage.modules + sage: _ = T.homology() # add more to _faces # needs sage.modules + sage: T.add_face((1,2,3)) + sage: T.remove_face((1,2,3)) + sage: len(T._faces) # needs sage.modules 2 - sage: T.remove_face((1,2)) # optional - sage.modules - sage: len(T._faces) # optional - sage.modules + sage: T.remove_face((1,2)) + sage: len(T._faces) 1 Check that the face to be removed can be given with a @@ -2912,7 +2917,7 @@ def connected_sum(self, other, is_mutable=True): EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) - sage: S1.connected_sum(S1.connected_sum(S1)).homology() + sage: S1.connected_sum(S1.connected_sum(S1)).homology() # needs sage.modules {0: 0, 1: Z} sage: P = simplicial_complexes.RealProjectivePlane(); P Minimal triangulation of the real projective plane @@ -2923,7 +2928,7 @@ def connected_sum(self, other, is_mutable=True): sage: P + P # the Klein bottle Simplicial complex with 9 vertices and 18 facets - sage: (P + P).homology()[1] # optional - sage.modules + sage: (P + P).homology()[1] # needs sage.modules Z x C2 """ if not (self.is_pure() and other.is_pure() and @@ -3033,23 +3038,23 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0): Spheres are Cohen-Macaulay:: sage: S = SimplicialComplex([[1,2],[2,3],[3,1]]) - sage: S.is_cohen_macaulay(ncpus=3) # optional - sage.modules + sage: S.is_cohen_macaulay(ncpus=3) # needs sage.modules True The following example is taken from Bruns, Herzog - Cohen-Macaulay rings, Figure 5.3:: sage: S = SimplicialComplex([[1,2,3],[1,4,5]]) - sage: S.is_cohen_macaulay(ncpus=3) # optional - sage.modules + sage: S.is_cohen_macaulay(ncpus=3) # needs sage.modules False The choice of base ring can matter. The real projective plane `\RR P^2` has `H_1(\RR P^2) = \ZZ/2`, hence is CM over `\QQ` but not over `\ZZ`. :: sage: X = simplicial_complexes.RealProjectivePlane() - sage: X.is_cohen_macaulay() # optional - sage.modules + sage: X.is_cohen_macaulay() # needs sage.modules True - sage: X.is_cohen_macaulay(ZZ) # optional - sage.modules + sage: X.is_cohen_macaulay(ZZ) # needs sage.modules False """ from sage.parallel.decorate import parallel @@ -3608,9 +3613,9 @@ def barycentric_subdivision(self): EXAMPLES:: sage: triangle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: hexagon = triangle.barycentric_subdivision(); hexagon # optional - sage.combinat sage.graphs + sage: hexagon = triangle.barycentric_subdivision(); hexagon Simplicial complex with 6 vertices and 6 facets - sage: hexagon.homology(1) == triangle.homology(1) # optional - sage.combinat sage.graphs sage.modules + sage: hexagon.homology(1) == triangle.homology(1) # needs sage.modules True Barycentric subdivisions can get quite large, since each @@ -3726,9 +3731,9 @@ def graph(self): EXAMPLES:: sage: S = SimplicialComplex([[0,1,2,3]]) - sage: G = S.graph(); G # optional - sage.graphs + sage: G = S.graph(); G Graph on 4 vertices - sage: G.edges(sort=True) # optional - sage.graphs + sage: G.edges(sort=True) [(0, 1, None), (0, 2, None), (0, 3, None), (1, 2, None), (1, 3, None), (2, 3, None)] """ if self._graph is None: @@ -3774,7 +3779,7 @@ def delta_complex(self, sort_simplices=False): sage: Td = T.delta_complex() sage: Td Delta complex with 7 vertices and 43 simplices - sage: T.homology() == Td.homology() # optional - sage.modules + sage: T.homology() == Td.homology() # needs sage.modules True """ from .delta_complex import DeltaComplex @@ -3803,11 +3808,11 @@ def is_flag_complex(self): EXAMPLES:: - sage: h = Graph({0: [1,2,3,4], 1: [2,3,4], 2: [3]}) # optional - sage.graphs - sage: x = h.clique_complex(); x # optional - sage.graphs + sage: h = Graph({0: [1,2,3,4], 1: [2,3,4], 2: [3]}) + sage: x = h.clique_complex(); x Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 1, 2, 3)} - sage: x.is_flag_complex() # optional - sage.graphs + sage: x.is_flag_complex() True sage: X = simplicial_complexes.ChessboardComplex(3,3) @@ -3882,7 +3887,7 @@ def _contractible_subcomplex(self, verbose=False): sage: L = sphere._contractible_subcomplex(); L Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3)} - sage: L.homology() # optional - sage.modules + sage: L.homology() # needs sage.modules {0: 0, 1: 0, 2: 0} """ facets = [sorted(self._facets, key=str)[0]] @@ -3918,14 +3923,14 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): Inside the torus, define a subcomplex consisting of a loop:: sage: S = SimplicialComplex([[0,1], [1,2], [0,2]], is_mutable=False) - sage: S.homology() # optional - sage.modules + sage: S.homology() # needs sage.modules {0: 0, 1: Z} sage: L = T._enlarge_subcomplex(S) sage: L Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 8 facets sage: sorted(L.facets()) [(0, 1), (0, 1, 5), (0, 2), (0, 2, 6), (0, 3, 4), (0, 3, 5), (0, 4, 6), (1, 2)] - sage: L.homology()[1] # optional - sage.modules + sage: L.homology()[1] # needs sage.modules Z """ # Make the subcomplex immutable if not @@ -4007,12 +4012,12 @@ def _cubical_(self): EXAMPLES:: sage: T = simplicial_complexes.Torus() - sage: T.homology() # optional - sage.modules + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} sage: Tc = T._cubical_() sage: Tc Cubical complex with 42 vertices and 168 cubes - sage: Tc.homology() # optional - sage.modules + sage: Tc.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} """ from .cubical_complex import CubicalComplex @@ -4049,22 +4054,22 @@ def connected_component(self, simplex=None): EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) - sage: S1 == S1.connected_component() # optional - sage.graphs + sage: S1 == S1.connected_component() True sage: X = S1.disjoint_union(S1) - sage: X == X.connected_component() # optional - sage.graphs + sage: X == X.connected_component() False - sage: CL0 = X.connected_component(Simplex(['L0'])) # optional - sage.graphs - sage: CR0 = X.connected_component(Simplex(['R0'])) # optional - sage.graphs - sage: CL0 == CR0 # optional - sage.graphs + sage: CL0 = X.connected_component(Simplex(['L0'])) + sage: CR0 = X.connected_component(Simplex(['R0'])) + sage: CL0 == CR0 False sage: S0 = simplicial_complexes.Sphere(0) sage: S0.vertices() (0, 1) - sage: S0.connected_component() # optional - sage.graphs + sage: S0.connected_component() Simplicial complex with vertex set (0,) and facets {(0,)} - sage: S0.connected_component(Simplex((1,))) # optional - sage.graphs + sage: S0.connected_component(Simplex((1,))) Simplicial complex with vertex set (1,) and facets {(1,)} sage: SimplicialComplex([[]]).connected_component() @@ -4111,7 +4116,7 @@ def fundamental_group(self, base_point=None, simplify=True): EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) - sage: S1.fundamental_group() # optional - sage.graphs sage.groups + sage: S1.fundamental_group() # needs sage.groups Finitely presented group < e | > If we pass the argument ``simplify=False``, we get generators and @@ -4119,43 +4124,45 @@ def fundamental_group(self, base_point=None, simplify=True): cyclic group of order 2, for instance:: sage: RP2 = simplicial_complexes.RealProjectiveSpace(2) - sage: C2 = RP2.fundamental_group(simplify=False); C2 # optional - sage.graphs sage.groups + sage: C2 = RP2.fundamental_group(simplify=False); C2 # needs sage.groups Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 | e0, e3, e4, e7, e9, e5*e2^-1*e0, e7*e2^-1*e1, e8*e3^-1*e1, e8*e6^-1*e4, e9*e6^-1*e5 > - sage: C2.simplified() # optional - sage.graphs sage.groups + sage: C2.simplified() # needs sage.groups Finitely presented group < e1 | e1^2 > This is the same answer given if the argument ``simplify`` is True (the default):: - sage: RP2.fundamental_group() # optional - sage.graphs sage.groups + sage: RP2.fundamental_group() # needs sage.groups Finitely presented group < e1 | e1^2 > You must specify a base point to compute the fundamental group of a non-connected complex:: - sage: K = S1.disjoint_union(RP2) # optional - sage.graphs sage.groups - sage: K.fundamental_group() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: K = S1.disjoint_union(RP2) + sage: K.fundamental_group() Traceback (most recent call last): ... ValueError: this complex is not connected, so you must specify a base point - sage: K.fundamental_group(base_point='L0') # optional - sage.graphs sage.groups + sage: K.fundamental_group(base_point='L0') Finitely presented group < e | > - sage: K.fundamental_group(base_point='R0').order() # optional - sage.graphs sage.groups + sage: K.fundamental_group(base_point='R0').order() 2 Some other examples:: - sage: S1.wedge(S1).fundamental_group() # optional - sage.graphs sage.groups + sage: S1.wedge(S1).fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > - sage: simplicial_complexes.Torus().fundamental_group() # optional - sage.graphs sage.groups + sage: simplicial_complexes.Torus().fundamental_group() # needs sage.groups Finitely presented group < e1, e4 | e4^-1*e1^-1*e4*e1 > - sage: G = simplicial_complexes.MooreSpace(5).fundamental_group() # optional - sage.graphs sage.groups - sage: G.ngens() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: G = simplicial_complexes.MooreSpace(5).fundamental_group() + sage: G.ngens() 1 - sage: x = G.gen(0) # optional - sage.graphs sage.groups - sage: [(x**n).is_one() for n in range(1,6)] # optional - sage.graphs sage.groups + sage: x = G.gen(0) + sage: [(x**n).is_one() for n in range(1,6)] [False, False, False, False, True] """ if not self.is_connected(): @@ -4224,18 +4231,18 @@ def is_isomorphic(self, other, certificate=False): sage: Z1 = SimplicialComplex([[0,1],[1,2],[2,3,4],[4,5]]) sage: Z2 = SimplicialComplex([['a','b'],['b','c'],['c','d','e'],['e','f']]) sage: Z3 = SimplicialComplex([[1,2,3]]) - sage: Z1.is_isomorphic(Z2) # optional - sage.graphs + sage: Z1.is_isomorphic(Z2) True - sage: Z1.is_isomorphic(Z2, certificate=True) # optional - sage.graphs + sage: Z1.is_isomorphic(Z2, certificate=True) (True, {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f'}) - sage: Z3.is_isomorphic(Z2) # optional - sage.graphs + sage: Z3.is_isomorphic(Z2) False We check that :trac:`20751` is fixed:: sage: C1 = SimplicialComplex([[1,2,3], [2,4], [3,5], [5,6]]) sage: C2 = SimplicialComplex([['a','b','c'], ['b','d'], ['c','e'], ['e','f']]) - sage: C1.is_isomorphic(C2, certificate=True) # optional - sage.graphs + sage: C1.is_isomorphic(C2, certificate=True) (True, {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f'}) """ # Check easy invariants agree @@ -4291,24 +4298,24 @@ def automorphism_group(self): EXAMPLES:: sage: S = simplicial_complexes.Simplex(3) - sage: S.automorphism_group().is_isomorphic(SymmetricGroup(4)) # optional - sage.graphs sage.groups + sage: S.automorphism_group().is_isomorphic(SymmetricGroup(4)) # needs sage.groups True sage: P = simplicial_complexes.RealProjectivePlane() - sage: P.automorphism_group().is_isomorphic(AlternatingGroup(5)) # optional - sage.graphs sage.groups + sage: P.automorphism_group().is_isomorphic(AlternatingGroup(5)) # needs sage.groups True sage: Z = SimplicialComplex([['1','2'],['2','3','a']]) - sage: Z.automorphism_group().is_isomorphic(CyclicPermutationGroup(2)) # optional - sage.graphs sage.groups + sage: Z.automorphism_group().is_isomorphic(CyclicPermutationGroup(2)) # needs sage.groups True - sage: group = Z.automorphism_group() # optional - sage.graphs sage.groups - sage: sorted(group.domain()) # optional - sage.graphs sage.groups + sage: group = Z.automorphism_group() # needs sage.groups + sage: sorted(group.domain()) # needs sage.groups ['1', '2', '3', 'a'] Check that :trac:`17032` is fixed:: sage: s = SimplicialComplex([[(0,1),(2,3)]]) - sage: s.automorphism_group().cardinality() # optional - sage.graphs sage.groups + sage: s.automorphism_group().cardinality() # needs sage.groups 2 """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -4349,25 +4356,25 @@ def fixed_complex(self, G): sage: S4 = simplicial_complexes.Sphere(4) sage: S3 = simplicial_complexes.Sphere(3) - sage: fix = S4.fixed_complex([S4.automorphism_group()([(0,1)])]); fix # optional - sage.graphs sage.groups + sage: fix = S4.fixed_complex([S4.automorphism_group()([(0,1)])]); fix # needs sage.groups Simplicial complex with vertex set (0, 2, 3, 4, 5) and 5 facets - sage: fix.is_isomorphic(S3) # optional - sage.graphs sage.groups + sage: fix.is_isomorphic(S3) # needs sage.groups True Another simple example:: sage: T = SimplicialComplex([[1,2,3],[2,3,4]]) - sage: G = T.automorphism_group() # optional - sage.graphs sage.groups - sage: T.fixed_complex([G([(1,4)])]) # optional - sage.graphs sage.groups + sage: G = T.automorphism_group() # needs sage.groups + sage: T.fixed_complex([G([(1,4)])]) # needs sage.groups Simplicial complex with vertex set (2, 3) and facets {(2, 3)} A more sophisticated example:: sage: RP2 = simplicial_complexes.ProjectivePlane() sage: CP2 = simplicial_complexes.ComplexProjectivePlane() - sage: G = CP2.automorphism_group() # optional - sage.graphs sage.groups - sage: H = G.subgroup([G([(2,3),(5,6),(8,9)])]) # optional - sage.graphs sage.groups - sage: CP2.fixed_complex(H).is_isomorphic(RP2) # optional - sage.graphs sage.groups + sage: G = CP2.automorphism_group() # needs sage.groups + sage: H = G.subgroup([G([(2,3),(5,6),(8,9)])]) # needs sage.groups + sage: CP2.fixed_complex(H).is_isomorphic(RP2) # needs sage.groups True """ from sage.categories.groups import Groups @@ -4694,28 +4701,28 @@ def is_balanced(self, check_purity=False, certificate=False): A 1-dim simplicial complex is balanced iff it is bipartite:: sage: X = SimplicialComplex([[1,2], [1,4], [3,4], [2,5]]) - sage: X.is_balanced() # optional - sage.graphs + sage: X.is_balanced() True - sage: sorted(X.is_balanced(certificate=True)) # optional - sage.graphs + sage: sorted(X.is_balanced(certificate=True)) [[1, 3, 5], [2, 4]] sage: X = SimplicialComplex([[1,2], [1,4], [3,4], [2,4]]) - sage: X.is_balanced() # optional - sage.graphs + sage: X.is_balanced() False Any barycentric division is balanced:: sage: X = SimplicialComplex([[1,2,3], [1,2,4], [2,3,4]]) - sage: X.is_balanced() # optional - sage.graphs + sage: X.is_balanced() False - sage: X.barycentric_subdivision().is_balanced() # optional - sage.graphs + sage: X.barycentric_subdivision().is_balanced() True A non-pure balanced complex:: sage: X = SimplicialComplex([[1,2,3], [3,4]]) - sage: X.is_balanced(check_purity=True) # optional - sage.graphs + sage: X.is_balanced(check_purity=True) False - sage: sorted(X.is_balanced(certificate=True)) # optional - sage.graphs + sage: sorted(X.is_balanced(certificate=True)) [[1, 4], [2], [3]] """ d = 1 + self.dimension() @@ -4771,13 +4778,14 @@ def is_partitionable(self, certificate=False, Simplices are trivially partitionable:: sage: X = SimplicialComplex([[1,2,3,4]]) - sage: X.is_partitionable() + sage: X.is_partitionable() # needs sage.numerical.mip True - sage: X.is_partitionable(certificate=True) + sage: X.is_partitionable(certificate=True) # needs sage.numerical.mip [((), (1, 2, 3, 4), 4)] Shellable complexes are partitionable:: + sage: # needs sage.numerical.mip sage: X = SimplicialComplex([[1,3,5], [1,3,6], [1,4,5], [1,4,6], ....: [2,3,5], [2,3,6], [2,4,5]]) sage: X.is_partitionable() @@ -4793,13 +4801,13 @@ def is_partitionable(self, certificate=False, A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Björner:: sage: X = SimplicialComplex([[1,2,3], [1,2,4], [1,3,4], [2,3,4], [1,5,6]]) - sage: X.is_partitionable() + sage: X.is_partitionable() # needs sage.numerical.mip True The bowtie complex is not partitionable:: sage: X = SimplicialComplex([[1,2,3], [1,4,5]]) - sage: X.is_partitionable() + sage: X.is_partitionable() # needs sage.numerical.mip False """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -4859,9 +4867,9 @@ def bigraded_betti_numbers(self, base_ring=ZZ): sage: X = SimplicialComplex([[0,1],[1,2],[1,3],[2,3]]) sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) - sage: sorted(X.bigraded_betti_numbers().items(), reverse=True) + sage: sorted(X.bigraded_betti_numbers().items(), reverse=True) # needs sage.modules [((0, 0), 1), ((-1, 6), 1), ((-1, 4), 2), ((-2, 8), 1), ((-2, 6), 1)] - sage: sorted(Y.bigraded_betti_numbers(base_ring=QQ).items(), reverse=True) + sage: sorted(Y.bigraded_betti_numbers(base_ring=QQ).items(), reverse=True) # needs sage.modules [((0, 0), 1), ((-1, 4), 3), ((-2, 8), 2), ((-2, 6), 1), ((-3, 10), 1)] """ if base_ring in self._bbn_all_computed: @@ -4900,6 +4908,7 @@ def bigraded_betti_number(self, a, b, base_ring=ZZ): EXAMPLES:: + sage: # needs sage.modules sage: X = SimplicialComplex([[0,1],[1,2],[2,0],[1,3]]) sage: X.bigraded_betti_number(-1, 4, base_ring=QQ) 2 @@ -4959,6 +4968,7 @@ def is_golod(self) -> bool: EXAMPLES:: + sage: # needs sage.modules sage: X = SimplicialComplex([[0,1],[1,2],[2,3],[3,0]]) sage: Y = SimplicialComplex([[0,1,2],[0,2],[0,4]]) sage: X.is_golod() @@ -4986,6 +4996,7 @@ def is_minimally_non_golod(self) -> bool: EXAMPLES:: + sage: # needs sage.modules sage: X = SimplicialComplex([[0,1],[1,2],[2,3],[3,0]]) sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) sage: X.is_golod() diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 3789a087970..dff18de22a0 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs """ Catalog of simplicial complexes @@ -54,14 +54,14 @@ EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) # the 2-sphere - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: simplicial_complexes.SurfaceOfGenus(3) Triangulation of an orientable surface of genus 3 sage: M4 = simplicial_complexes.MooreSpace(4) - sage: M4.homology() + sage: M4.homology() # needs sage.modules {0: 0, 1: C4, 2: 0} - sage: simplicial_complexes.MatchingComplex(6).homology() + sage: simplicial_complexes.MatchingComplex(6).homology() # needs sage.modules {0: 0, 1: Z^16, 2: 0} """ diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index 7e6f0eeca75..304ea7ec8aa 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs """ Examples of simplicial complexes @@ -54,22 +54,23 @@ EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) # the 2-sphere - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: simplicial_complexes.SurfaceOfGenus(3) Triangulation of an orientable surface of genus 3 sage: M4 = simplicial_complexes.MooreSpace(4) - sage: M4.homology() + sage: M4.homology() # needs sage.modules {0: 0, 1: C4, 2: 0} - sage: simplicial_complexes.MatchingComplex(6).homology() + sage: simplicial_complexes.MatchingComplex(6).homology() # needs sage.modules {0: 0, 1: Z^16, 2: 0} TESTS:: sage: from sage.topology.simplicial_complex_examples import PseudoQuaternionicProjectivePlane - sage: H = PseudoQuaternionicProjectivePlane() + sage: H = PseudoQuaternionicProjectivePlane() # needs sage.groups doctest:warning...: - DeprecationWarning: PseudoQuaternionicProjectivePlane is deprecated. Please use sage.topology.simplicial_complex_examples.QuaternionicProjectivePlane instead. + DeprecationWarning: PseudoQuaternionicProjectivePlane is deprecated. + Please use sage.topology.simplicial_complex_examples.QuaternionicProjectivePlane instead. See https://github.com/sagemath/sage/issues/34568 for details. """ @@ -306,7 +307,7 @@ def Sphere(n): sage: simplicial_complexes.Sphere(2) Minimal triangulation of the 2-sphere - sage: simplicial_complexes.Sphere(5).homology() + sage: simplicial_complexes.Sphere(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} sage: [simplicial_complexes.Sphere(n).euler_characteristic() for n in range(6)] [2, 0, 2, 0, 2, 0] @@ -359,7 +360,8 @@ def Torus(): EXAMPLES:: - sage: T = simplicial_complexes.Torus(); T.homology(1) + sage: T = simplicial_complexes.Torus() + sage: T.homology(1) # needs sage.modules Z x Z sage: T.f_vector() [1, 7, 21, 14] @@ -390,6 +392,8 @@ def RealProjectivePlane(): sage: Q = simplicial_complexes.ProjectivePlane() sage: P == Q True + + sage: # needs sage.modules sage: P.cohomology(1) 0 sage: P.cohomology(2) @@ -500,9 +504,9 @@ def MooreSpace(q): sage: simplicial_complexes.MooreSpace(2) Minimal triangulation of the real projective plane - sage: simplicial_complexes.MooreSpace(3).homology()[1] + sage: simplicial_complexes.MooreSpace(3).homology()[1] # needs sage.modules C3 - sage: simplicial_complexes.MooreSpace(4).suspension().homology()[2] + sage: simplicial_complexes.MooreSpace(4).suspension().homology()[2] # needs sage.modules C4 sage: simplicial_complexes.MooreSpace(8) Triangulation of the mod 8 Moore space @@ -541,9 +545,9 @@ def ComplexProjectivePlane(): sage: C = simplicial_complexes.ComplexProjectivePlane() sage: C.f_vector() [1, 9, 36, 84, 90, 36] - sage: C.homology(2) + sage: C.homology(2) # needs sage.modules Z - sage: C.homology(4) + sage: C.homology(4) # needs sage.modules Z """ return UniqueSimplicialComplex( @@ -581,14 +585,14 @@ def QuaternionicProjectivePlane(): EXAMPLES:: - sage: HP2 = simplicial_complexes.QuaternionicProjectivePlane(); HP2 # optional - sage.groups + sage: HP2 = simplicial_complexes.QuaternionicProjectivePlane(); HP2 # needs sage.groups Simplicial complex with 15 vertices and 490 facets - sage: HP2.f_vector() # optional - sage.groups + sage: HP2.f_vector() # needs sage.groups [1, 15, 105, 455, 1365, 3003, 4515, 4230, 2205, 490] Checking its automorphism group:: - sage: HP2.automorphism_group().is_isomorphic(AlternatingGroup(5)) # optional - sage.groups + sage: HP2.automorphism_group().is_isomorphic(AlternatingGroup(5)) # needs sage.groups True """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -632,9 +636,9 @@ def PoincareHomologyThreeSphere(): sage: S3 = simplicial_complexes.Sphere(3) sage: Sigma3 = simplicial_complexes.PoincareHomologyThreeSphere() - sage: S3.homology() == Sigma3.homology() + sage: S3.homology() == Sigma3.homology() # needs sage.modules True - sage: Sigma3.fundamental_group().cardinality() # long time + sage: Sigma3.fundamental_group().cardinality() # long time # needs sage.groups 120 """ return UniqueSimplicialComplex( @@ -734,7 +738,7 @@ def RealProjectiveSpace(n): sage: P3 = simplicial_complexes.RealProjectiveSpace(3) sage: P3.f_vector() [1, 11, 51, 80, 40] - sage: P3.homology() + sage: P3.homology() # needs sage.modules {0: 0, 1: C2, 2: 0, 3: Z} sage: P4 = simplicial_complexes.RealProjectiveSpace(4) sage: P4.f_vector() @@ -1002,7 +1006,7 @@ def BarnetteSphere(): ....: [3, 4, 5, 8], [4, 5, 6, 8], [1, 2, 6, 8], ....: [1, 5, 6, 8], [1, 3, 5, 8], [2, 4, 6, 8], ....: [1, 3, 5, 7]]) - sage: BS.is_isomorphic(BS2) # optional - sage.graphs + sage: BS.is_isomorphic(BS2) True """ return UniqueSimplicialComplex([(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), @@ -1075,9 +1079,10 @@ def NotIConnectedGraphs(n, i): EXAMPLES:: - sage: simplicial_complexes.NotIConnectedGraphs(5, 2).f_vector() + sage: NICG52 = simplicial_complexes.NotIConnectedGraphs(5, 2) + sage: NICG52.f_vector() [1, 10, 45, 120, 210, 240, 140, 20] - sage: simplicial_complexes.NotIConnectedGraphs(5, 2).homology(5).ngens() + sage: NICG52.homology(5).ngens() # needs sage.modules 6 """ G_list = range(1, n+1) @@ -1130,11 +1135,12 @@ def MatchingComplex(n): EXAMPLES:: sage: M = simplicial_complexes.MatchingComplex(7) - sage: H = M.homology(); H + sage: H = M.homology(); H # needs sage.modules {0: 0, 1: C3, 2: Z^20} - sage: H[2].ngens() + sage: H[2].ngens() # needs sage.modules 20 - sage: simplicial_complexes.MatchingComplex(8).homology(2) # long time (6s on sage.math, 2012) + sage: M8 = simplicial_complexes.MatchingComplex(8) + sage: M8.homology(2) # long time (6s on sage.math, 2012), needs sage.modules Z^132 """ G_vertices = Set(range(1, n+1)) @@ -1206,7 +1212,7 @@ def ChessboardComplex(n, i): sage: C = simplicial_complexes.ChessboardComplex(5, 5) sage: C.f_vector() [1, 25, 200, 600, 600, 120] - sage: simplicial_complexes.ChessboardComplex(3, 3).homology() + sage: simplicial_complexes.ChessboardComplex(3, 3).homology() # needs sage.modules {0: 0, 1: Z x Z x Z x Z, 2: 0} """ A = range(n) @@ -1310,58 +1316,58 @@ def SumComplex(n, A): sage: S = simplicial_complexes.SumComplex(10, [0, 1, 2, 3, 6]); S Sum complex on vertices Z/10Z associated to {0, 1, 2, 3, 6} - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: C2728, 4: 0} sage: factor(2728) 2^3 * 11 * 31 sage: S = simplicial_complexes.SumComplex(11, [0, 1, 3]); S Sum complex on vertices Z/11Z associated to {0, 1, 3} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C23 sage: S = simplicial_complexes.SumComplex(11, [0, 1, 2, 3, 4, 7]); S Sum complex on vertices Z/11Z associated to {0, 1, 2, 3, 4, 7} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: C645679, 5: 0} sage: factor(645679) 23 * 67 * 419 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 3]); S Sum complex on vertices Z/13Z associated to {0, 1, 3} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C159 sage: factor(159) 3 * 53 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 2, 5]); S Sum complex on vertices Z/13Z associated to {0, 1, 2, 5} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: C146989209, 3: 0} sage: factor(1648910295) 3^2 * 5 * 53 * 521 * 1327 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 2, 3, 5]); S Sum complex on vertices Z/13Z associated to {0, 1, 2, 3, 5} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: 0, 3: C3 x C237 x C706565607945, 4: 0} - sage: factor(706565607945) + sage: factor(706565607945) # needs sage.libs.pari 3 * 5 * 53 * 79 * 131 * 157 * 547 sage: S = simplicial_complexes.SumComplex(17, [0, 1, 4]); S Sum complex on vertices Z/17Z associated to {0, 1, 4} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C140183 sage: factor(140183) 103 * 1361 sage: S = simplicial_complexes.SumComplex(19, [0, 1, 4]); S Sum complex on vertices Z/19Z associated to {0, 1, 4} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C5670599 sage: factor(5670599) 11 * 191 * 2699 sage: S = simplicial_complexes.SumComplex(31, [0, 1, 4]); S Sum complex on vertices Z/31Z associated to {0, 1, 4} - sage: S.homology(1) # long time + sage: S.homology(1) # long time # needs sage.modules C5 x C5 x C5 x C5 x C26951480558170926865 - sage: factor(26951480558170926865) + sage: factor(26951480558170926865) # needs sage.libs.pari 5 * 311 * 683 * 1117 * 11657 * 1948909 """ from sage.rings.finite_rings.integer_mod_ring import Integers @@ -1417,15 +1423,16 @@ def RandomTwoSphere(n): EXAMPLES:: - sage: G = simplicial_complexes.RandomTwoSphere(6); G # optional - sage.graphs + sage: + sage: G = simplicial_complexes.RandomTwoSphere(6); G Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and 8 facets - sage: G.homology() # optional - sage.graphs + sage: G.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} - sage: G.is_pure() # optional - sage.graphs + sage: G.is_pure() True - sage: fg = G.flip_graph(); fg # optional - sage.graphs + sage: fg = G.flip_graph(); fg Graph on 8 vertices - sage: fg.is_planar() and fg.is_regular(3) # optional - sage.graphs + sage: fg.is_planar() and fg.is_regular(3) True """ from sage.graphs.generators.random import RandomTriangulation @@ -1465,14 +1472,15 @@ def ShiftedComplex(generators): EXAMPLES:: - sage: X = simplicial_complexes.ShiftedComplex([Simplex([1, 6]), (2, 4), [8]]) # optional - sage.combinat - sage: sorted(X.facets()) # optional - sage.combinat + sage: # needs sage.combinat + sage: X = simplicial_complexes.ShiftedComplex([Simplex([1, 6]), (2, 4), [8]]) + sage: sorted(X.facets()) [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (7,), (8,)] - sage: X = simplicial_complexes.ShiftedComplex([[2, 3, 5]]) # optional - sage.combinat - sage: sorted(X.facets()) # optional - sage.combinat + sage: X = simplicial_complexes.ShiftedComplex([[2, 3, 5]]) + sage: sorted(X.facets()) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (2, 3, 4), (2, 3, 5)] - sage: X = simplicial_complexes.ShiftedComplex([[1, 3, 5], [2, 6]]) # optional - sage.combinat - sage: sorted(X.facets()) # optional - sage.combinat + sage: X = simplicial_complexes.ShiftedComplex([[1, 3, 5], [2, 6]]) + sage: sorted(X.facets()) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 6), (2, 6)] """ from sage.combinat.partition import Partitions @@ -1500,9 +1508,9 @@ def RudinBall(): Rudin ball sage: R.f_vector() [1, 14, 66, 94, 41] - sage: R.homology() + sage: R.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} - sage: R.is_cohen_macaulay() + sage: R.is_cohen_macaulay() # needs sage.modules True """ return UniqueSimplicialComplex( @@ -1533,9 +1541,9 @@ def ZieglerBall(): Ziegler ball sage: Z.f_vector() [1, 10, 38, 50, 21] - sage: Z.homology() + sage: Z.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} - sage: Z.is_cohen_macaulay() + sage: Z.is_cohen_macaulay() # needs sage.modules True """ @@ -1561,9 +1569,9 @@ def DunceHat(): Minimal triangulation of the dunce hat sage: D.f_vector() [1, 8, 24, 17] - sage: D.homology() + sage: D.homology() # needs sage.modules {0: 0, 1: 0, 2: 0} - sage: D.is_cohen_macaulay() + sage: D.is_cohen_macaulay() # needs sage.modules True """ return UniqueSimplicialComplex( @@ -1595,14 +1603,14 @@ def FareyMap(p): EXAMPLES:: - sage: S5 = simplicial_complexes.FareyMap(5); S5 # optional - sage.groups + sage: S5 = simplicial_complexes.FareyMap(5); S5 # needs sage.groups Simplicial complex with 12 vertices and 20 facets - sage: S5.automorphism_group().cardinality() # optional - sage.groups + sage: S5.automorphism_group().cardinality() # needs sage.groups 120 - sage: S7 = simplicial_complexes.FareyMap(7); S7 # optional - sage.groups + sage: S7 = simplicial_complexes.FareyMap(7); S7 # needs sage.groups Simplicial complex with 24 vertices and 56 facets - sage: S7.f_vector() # optional - sage.groups + sage: S7.f_vector() # needs sage.groups [1, 24, 84, 56] REFERENCES: @@ -1660,9 +1668,9 @@ def GenusSix(): EXAMPLES:: sage: S = simplicial_complexes.GenusSix() - sage: S.automorphism_group().cardinality() # optional - sage.groups + sage: S.automorphism_group().cardinality() # needs sage.groups 12 - sage: S.betti() + sage: S.betti() # needs sage.modules {0: 1, 1: 12, 2: 1} sage: S.f_vector() [1, 12, 66, 44] diff --git a/src/sage/topology/simplicial_complex_homset.py b/src/sage/topology/simplicial_complex_homset.py index 4ee6c6abea9..255e905a990 100644 --- a/src/sage/topology/simplicial_complex_homset.py +++ b/src/sage/topology/simplicial_complex_homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Homsets between simplicial complexes diff --git a/src/sage/topology/simplicial_complex_morphism.py b/src/sage/topology/simplicial_complex_morphism.py index 15f10f05521..3d4fc063198 100644 --- a/src/sage/topology/simplicial_complex_morphism.py +++ b/src/sage/topology/simplicial_complex_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Morphisms of simplicial complexes @@ -105,11 +106,13 @@ from sage.categories.homset import Hom from sage.categories.morphism import Morphism from sage.categories.simplicial_complexes import SimplicialComplexes -from sage.matrix.constructor import matrix, zero_matrix +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ from .simplicial_complex import Simplex, SimplicialComplex +lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix']) + def is_SimplicialComplexMorphism(x): """ @@ -239,7 +242,7 @@ def __call__(self, x, orientation=False): sage: g = Hom(X,X)({0:1, 1:0}) sage: g(Simplex([0,1])) (0, 1) - sage: g(Simplex([0,1]), orientation=True) + sage: g(Simplex([0,1]), orientation=True) # needs sage.modules ((0, 1), -1) """ dim = self.domain().dimension() @@ -311,33 +314,34 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, EXAMPLES:: + sage: # needs sage.modules sage: S = simplicial_complexes.Sphere(1) sage: T = simplicial_complexes.Sphere(2) - sage: H = Hom(S,T) - sage: f = {0:0,1:1,2:2} - sage: x = H(f) - sage: x + sage: H = Hom(S, T) + sage: f = {0:0, 1:1, 2:2} + sage: x = H(f); x Simplicial complex morphism: From: Minimal triangulation of the 1-sphere To: Minimal triangulation of the 2-sphere Defn: 0 |--> 0 1 |--> 1 2 |--> 2 - sage: a = x.associated_chain_complex_morphism() - sage: a + sage: a = x.associated_chain_complex_morphism(); a Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: a._matrix_dictionary {0: [1 0 0] - [0 1 0] - [0 0 1] - [0 0 0], 1: [1 0 0] - [0 1 0] - [0 0 0] - [0 0 1] - [0 0 0] - [0 0 0], 2: []} + [0 1 0] + [0 0 1] + [0 0 0], + 1: [1 0 0] + [0 1 0] + [0 0 0] + [0 0 1] + [0 0 0] + [0 0 0], + 2: []} sage: x.associated_chain_complex_morphism(augmented=True) Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring @@ -346,7 +350,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring - sage: x.associated_chain_complex_morphism(augmented=True,cochain=True) + sage: x.associated_chain_complex_morphism(augmented=True, cochain=True) Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring @@ -357,21 +361,25 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, Some simplicial maps which reverse the orientation of a few simplices:: + sage: # needs sage.modules sage: g = {0:1, 1:2, 2:0} sage: H(g).associated_chain_complex_morphism()._matrix_dictionary {0: [0 0 1] - [1 0 0] - [0 1 0] - [0 0 0], 1: [ 0 -1 0] - [ 0 0 -1] - [ 0 0 0] - [ 1 0 0] - [ 0 0 0] - [ 0 0 0], 2: []} + [1 0 0] + [0 1 0] + [0 0 0], + 1: [ 0 -1 0] + [ 0 0 -1] + [ 0 0 0] + [ 1 0 0] + [ 0 0 0] + [ 0 0 0], + 2: []} sage: X = SimplicialComplex([[0, 1]], is_mutable=False) sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary {0: [0 1] - [1 0], 1: [-1]} + [1 0], + 1: [-1]} """ from sage.homology.chain_complex_morphism import ChainComplexMorphism @@ -627,13 +635,13 @@ def mapping_torus(self): sage: C = simplicial_complexes.Sphere(1) # Circle sage: T = Hom(C,C).identity().mapping_torus() ; T # Torus Simplicial complex with 9 vertices and 18 facets - sage: T.homology() == simplicial_complexes.Torus().homology() + sage: T.homology() == simplicial_complexes.Torus().homology() # needs sage.modules True - sage: f = Hom(C,C)({0:0,1:2,2:1}) - sage: K = f.mapping_torus() ; K # Klein Bottle + sage: f = Hom(C,C)({0:0, 1:2, 2:1}) + sage: K = f.mapping_torus(); K # Klein Bottle Simplicial complex with 9 vertices and 18 facets - sage: K.homology() == simplicial_complexes.KleinBottle().homology() + sage: K.homology() == simplicial_complexes.KleinBottle().homology() # needs sage.modules True TESTS:: @@ -674,11 +682,12 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: T = S.product(S, is_mutable=False) sage: H = Hom(S,T) sage: diag = H.diagonal_morphism() - sage: h = diag.induced_homology_morphism(QQ) - sage: h + sage: h = diag.induced_homology_morphism(QQ); h # needs sage.modules Graded vector space morphism: - From: Homology module of Minimal triangulation of the 1-sphere over Rational Field - To: Homology module of Simplicial complex with 9 vertices and 18 facets over Rational Field + From: Homology module of + Minimal triangulation of the 1-sphere over Rational Field + To: Homology module of + Simplicial complex with 9 vertices and 18 facets over Rational Field Defn: induced by: Simplicial complex morphism: From: Minimal triangulation of the 1-sphere @@ -689,12 +698,12 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): We can view the matrix form for the homomorphism:: - sage: h.to_matrix(0) # in degree 0 + sage: h.to_matrix(0) # in degree 0 # needs sage.modules [1] - sage: h.to_matrix(1) # in degree 1 + sage: h.to_matrix(1) # in degree 1 # needs sage.modules [1] [1] - sage: h.to_matrix() # the entire homomorphism + sage: h.to_matrix() # the entire homomorphism # needs sage.modules [1|0] [-+-] [0|1] @@ -704,18 +713,18 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): The map on cohomology should be dual to the map on homology:: - sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) - sage: coh.to_matrix(1) + sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) # needs sage.modules + sage: coh.to_matrix(1) # needs sage.modules [1 1] - sage: h.to_matrix() == coh.to_matrix().transpose() + sage: h.to_matrix() == coh.to_matrix().transpose() # needs sage.modules True We can evaluate the map on (co)homology classes:: - sage: x,y = list(T.cohomology_ring(QQ).basis(1)) - sage: coh(x) + sage: x,y = list(T.cohomology_ring(QQ).basis(1)) # needs sage.modules + sage: coh(x) # needs sage.modules h^{1,0} - sage: coh(2*x+3*y) + sage: coh(2*x + 3*y) # needs sage.modules 5*h^{1,0} Note that the complexes must be immutable for this to @@ -729,13 +738,13 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: S2 = S.suspension() sage: S2.is_immutable() False - sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules Traceback (most recent call last): ... ValueError: the domain and codomain complexes must be immutable sage: S2.set_immutable(); S2.is_immutable() True - sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules """ from sage.homology.homology_morphism import InducedHomologyMorphism return InducedHomologyMorphism(self, base_ring, cohomology) diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 813e2d4defa..42cc3f77780 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Simplicial sets @@ -41,7 +41,7 @@ sage: simplicial_sets.Torus() Torus - sage: simplicial_sets.RealProjectiveSpace(7) # optional - sage.groups + sage: simplicial_sets.RealProjectiveSpace(7) # needs sage.groups RP^7 sage: S5 = simplicial_sets.Sphere(5); S5 S^5 @@ -51,14 +51,14 @@ One class of infinite simplicial sets is available: classifying spaces of groups, or more generally, nerves of finite monoids:: - sage: Sigma4 = groups.permutation.Symmetric(4) - sage: Sigma4.nerve() + sage: Sigma4 = groups.permutation.Symmetric(4) # needs sage.groups + sage: Sigma4.nerve() # needs sage.groups Nerve of Symmetric group of order 4! as a permutation group The same simplicial set (albeit with a different name) can also be constructed as :: - sage: simplicial_sets.ClassifyingSpace(Sigma4) + sage: simplicial_sets.ClassifyingSpace(Sigma4) # needs sage.groups Classifying space of Symmetric group of order 4! as a permutation group Type ``simplicial_sets.`` and hit the :kbd:`Tab` key to get a full list @@ -166,9 +166,10 @@ sage: S1 = simplicial_sets.Sphere(1) sage: eight = S1.wedge(S1) - sage: eight.fundamental_group() + sage: eight.fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > + sage: # needs sage.groups sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = Sigma3.nerve() sage: pi = BSigma3.fundamental_group(); pi @@ -178,8 +179,8 @@ sage: pi.is_abelian() False - sage: RP6 = simplicial_sets.RealProjectiveSpace(6) - sage: RP6.homology(reduced=False, base_ring=GF(2)) + sage: RP6 = simplicial_sets.RealProjectiveSpace(6) # needs sage.groups + sage: RP6.homology(reduced=False, base_ring=GF(2)) # needs sage.groups sage.modules {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2, @@ -187,7 +188,7 @@ 4: Vector space of dimension 1 over Finite Field of size 2, 5: Vector space of dimension 1 over Finite Field of size 2, 6: Vector space of dimension 1 over Finite Field of size 2} - sage: RP6.homology(reduced=False, base_ring=QQ) + sage: RP6.homology(reduced=False, base_ring=QQ) # needs sage.groups sage.modules {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 0 over Rational Field, 2: Vector space of dimension 0 over Rational Field, @@ -200,20 +201,24 @@ by taking an `n`-skeleton for an appropriate `n`, either implicitly or explicitly:: - sage: B3 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([3])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([3]) + sage: B3 = simplicial_sets.ClassifyingSpace(G) sage: B3.disjoint_union(B3).n_skeleton(3) - Disjoint union: (Simplicial set with 15 non-degenerate simplices u Simplicial set with 15 non-degenerate simplices) + Disjoint union: (Simplicial set with 15 non-degenerate simplices + u Simplicial set with 15 non-degenerate simplices) sage: S1 = simplicial_sets.Sphere(1) - sage: B3.product(S1).homology(range(4)) + sage: B3.product(S1).homology(range(4)) # needs sage.modules {0: 0, 1: Z x C3, 2: C3, 3: C3} Without the ``range`` argument, this would raise an error, since ``B3`` is infinite:: - sage: B3.product(S1).homology() + sage: B3.product(S1).homology() # needs sage.groups sage.modules Traceback (most recent call last): ... - NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology + NotImplementedError: this simplicial set may be infinite, + so specify dimensions when computing homology It should be easy to construct many simplicial sets from the predefined ones using pushouts, pullbacks, etc., but they can also be @@ -231,7 +236,7 @@ ending at `w`. Therefore the first homology group of `X` should be a copy of the integers:: - sage: X.homology(1) + sage: X.homology(1) # needs sage.modules Z """ # **************************************************************************** @@ -253,9 +258,9 @@ import copy -from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -266,8 +271,8 @@ from .delta_complex import DeltaComplex from .simplicial_complex import SimplicialComplex -from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') +lazy_import('sage.matrix.constructor', 'matrix') ######################################################################## @@ -816,15 +821,16 @@ def __deepcopy__(self, memo): The purpose for this method is to be able to make distinct copies of simplicial sets:: + sage: # needs sage.groups sage: from sage.topology.simplicial_set import SimplicialSet - sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # optional - sage.groups - sage: dict(copy.copy(RP3._data)) == dict(RP3._data) # optional - sage.groups + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) + sage: dict(copy.copy(RP3._data)) == dict(RP3._data) True - sage: dict(copy.deepcopy(RP3._data)) == dict(RP3._data) # optional - sage.groups + sage: dict(copy.deepcopy(RP3._data)) == dict(RP3._data) False - sage: SimplicialSet(RP3) == RP3 # optional - sage.groups + sage: SimplicialSet(RP3) == RP3 False - sage: copy.copy(RP3) == RP3 # optional - sage.groups + sage: copy.copy(RP3) == RP3 False """ underlying = self.nondegenerate() @@ -1151,11 +1157,12 @@ def faces(self, simplex): sage: S2.faces(sigma.apply_degeneracies(0)) [sigma_2, sigma_2, s_1 s_0 v_0, s_1 s_0 v_0] - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: f2 = BC3.n_cells(1)[1]; f2 # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) + sage: f2 = BC3.n_cells(1)[1]; f2 f^2 - sage: BC3.faces(f2) # optional - sage.groups + sage: BC3.faces(f2) (1, 1) TESTS:: @@ -1356,11 +1363,12 @@ def nondegenerate_simplices(self, max_dim=None): Test an infinite example:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.nondegenerate_simplices(2) # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) + sage: BC3.nondegenerate_simplices(2) [1, f, f^2, f * f, f * f^2, f^2 * f, f^2 * f^2] - sage: BC3.nondegenerate_simplices() # optional - sage.groups + sage: BC3.nondegenerate_simplices() Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify max_dim @@ -1411,20 +1419,21 @@ def cells(self, subcomplex=None, max_dim=None): sage: S1.cells() {0: [v], 1: [e]} - sage: S0.cells(S0.subsimplicial_set([v, w])) # optional - sage.graphs + sage: S0.cells(S0.subsimplicial_set([v, w])) {0: [*]} sage: X = SimplicialSet({e: (v,w)}) - sage: X.cells(X.subsimplicial_set([v, w])) # optional - sage.graphs + sage: X.cells(X.subsimplicial_set([v, w])) {0: [*], 1: [e]} Test an infinite example:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.cells(max_dim=2) # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) + sage: BC3.cells(max_dim=2) {0: [1], 1: [f, f^2], 2: [f * f, f * f^2, f^2 * f, f^2 * f^2]} - sage: BC3.cells() # optional - sage.groups + sage: BC3.cells() Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify max_dim @@ -1470,9 +1479,9 @@ def n_cells(self, n, subcomplex=None): [sigma_3] sage: simplicial_sets.Sphere(3).n_cells(2) [] - sage: C2 = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: BC2 = C2.nerve() # optional - sage.groups - sage: BC2.n_cells(3) # optional - sage.groups + sage: C2 = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: BC2 = C2.nerve() # needs sage.groups + sage: BC2.n_cells(3) # needs sage.groups [f * f * f] """ cells = self.cells(subcomplex=subcomplex, max_dim=n) @@ -1530,9 +1539,9 @@ def all_n_simplices(self, n): An example involving an infinite simplicial set:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.all_n_simplices(2) # optional - sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.all_n_simplices(2) # needs sage.groups [f * f, f * f^2, f^2 * f, @@ -1576,10 +1585,11 @@ def identity(self): Simplicial set endomorphism of S^3 Defn: Identity map - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: one = BC3.identity() # optional - sage.groups - sage: [(sigma, one(sigma)) for sigma in BC3.n_cells(2)] # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) + sage: one = BC3.identity() + sage: [(sigma, one(sigma)) for sigma in BC3.n_cells(2)] [(f * f, f * f), (f * f^2, f * f^2), (f^2 * f, f^2 * f), @@ -1617,8 +1627,8 @@ def constant_map(self, codomain=None, point=None): To: S^0 Defn: Constant map at v_0 - sage: Sigma3 = groups.permutation.Symmetric(3) # optional - sage.groups - sage: Sigma3.nerve().constant_map() # optional - sage.groups + sage: Sigma3 = groups.permutation.Symmetric(3) # needs sage.groups + sage: Sigma3.nerve().constant_map() # needs sage.groups Simplicial set morphism: From: Nerve of Symmetric group of order 3! as a permutation group To: Point @@ -1657,8 +1667,8 @@ def graph(self): EXAMPLES:: sage: Delta3 = simplicial_sets.Simplex(3) - sage: G = Delta3.graph() # optional - sage.graphs - sage: G.edges(sort=True) # optional - sage.graphs + sage: G = Delta3.graph() + sage: G.edges(sort=True) [((0,), (1,), (0, 1)), ((0,), (2,), (0, 2)), ((0,), (3,), (0, 3)), @@ -1667,20 +1677,21 @@ def graph(self): ((2,), (3,), (2, 3))] sage: T = simplicial_sets.Torus() - sage: T.graph() # optional - sage.graphs + sage: T.graph() Looped multi-graph on 1 vertex - sage: len(T.graph().edges(sort=False)) # optional - sage.graphs + sage: len(T.graph().edges(sort=False)) 3 + sage: # needs pyparsing sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3) - sage: G = CP3.graph() # optional - sage.graphs - sage: len(G.vertices(sort=False)) # optional - sage.graphs + sage: G = CP3.graph() + sage: len(G.vertices(sort=False)) 1 - sage: len(G.edges(sort=False)) # optional - sage.graphs + sage: len(G.edges(sort=False)) 0 - sage: Sigma3 = groups.permutation.Symmetric(3) # optional - sage.groups - sage: Sigma3.nerve().is_connected() # optional - sage.graphs sage.groups + sage: Sigma3 = groups.permutation.Symmetric(3) # needs sage.groups + sage: Sigma3.nerve().is_connected() # needs sage.groups True """ from sage.graphs.graph import Graph @@ -1700,14 +1711,14 @@ def is_connected(self): sage: T = simplicial_sets.Torus() sage: K = simplicial_sets.KleinBottle() - sage: X = T.disjoint_union(K) # optional - sage.graphs - sage: T.is_connected() # optional - sage.graphs + sage: X = T.disjoint_union(K) + sage: T.is_connected() True - sage: K.is_connected() # optional - sage.graphs + sage: K.is_connected() True - sage: X.is_connected() # optional - sage.graphs + sage: X.is_connected() False - sage: simplicial_sets.Sphere(0).is_connected() # optional - sage.graphs + sage: simplicial_sets.Sphere(0).is_connected() False """ return self.graph().is_connected() @@ -1757,12 +1768,13 @@ def subsimplicial_set(self, simplices): A subsimplicial set knows about its ambient space and the inclusion map into it:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups - sage: M = RP4.n_skeleton(2); M # optional - sage.groups + sage: # needs sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: M = RP4.n_skeleton(2); M Simplicial set with 3 non-degenerate simplices - sage: M.ambient_space() # optional - sage.groups + sage: M.ambient_space() RP^4 - sage: M.inclusion_map() # optional - sage.groups + sage: M.inclusion_map() Simplicial set morphism: From: Simplicial set with 3 non-degenerate simplices To: RP^4 @@ -1770,12 +1782,13 @@ def subsimplicial_set(self, simplices): An infinite ambient simplicial set:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: BxB = B.product(B) # optional - sage.groups - sage: BxB.n_cells(2)[5:] # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: BxB = B.product(B) + sage: BxB.n_cells(2)[5:] [(s_0 f, s_1 f), (s_1 f, f * f), (s_1 f, s_0 f), (s_1 s_0 1, f * f)] - sage: BxB.subsimplicial_set(BxB.n_cells(2)[5:]) # optional - sage.groups + sage: BxB.subsimplicial_set(BxB.n_cells(2)[5:]) Simplicial set with 8 non-degenerate simplices TESTS: @@ -1810,7 +1823,7 @@ def subsimplicial_set(self, simplices): sage: K = CP2.quotient(sub) sage: K.f_vector() [1, 0, 16, 30, 16] - sage: K.homology() + sage: K.homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: 0, 4: Z} Try to construct a subcomplex from a simplicial complex which @@ -1910,17 +1923,17 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, EXAMPLES:: - sage: simplicial_sets.Sphere(5).chain_complex() + sage: simplicial_sets.Sphere(5).chain_complex() # needs sage.modules Chain complex with at most 3 nonzero terms over Integer Ring - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.chain_complex(range(4), base_ring=GF(3)) # optional - sage.groups sage.rings.finite_rings + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.chain_complex(range(4), base_ring=GF(3)) # needs sage.groups sage.modules Chain complex with at most 4 nonzero terms over Finite Field of size 3 TESTS:: - sage: BC3.chain_complex() # optional - sage.groups sage.rings.finite_rings + sage: BC3.chain_complex() # needs sage.groups Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing its chain complex @@ -1966,34 +1979,35 @@ def homology(self, dim=None, **kwds): EXAMPLES:: - sage: simplicial_sets.Sphere(5).homology() # optional - sage.modules + sage: simplicial_sets.Sphere(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.homology(range(4), base_ring=GF(3)) # optional - sage.groups sage.modules sage.rings.finite_rings + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.homology(range(4), base_ring=GF(3)) # needs sage.groups sage.modules {0: Vector space of dimension 0 over Finite Field of size 3, 1: Vector space of dimension 1 over Finite Field of size 3, 2: Vector space of dimension 1 over Finite Field of size 3, 3: Vector space of dimension 1 over Finite Field of size 3} - sage: C2 = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: BC2 = simplicial_sets.ClassifyingSpace(C2) # optional - sage.groups - sage: BK = BC2.product(BC2) # optional - sage.groups - sage: BK.homology(range(4)) # optional - sage.groups sage.modules + sage: # needs sage.groups + sage: C2 = groups.misc.MultiplicativeAbelian([2]) + sage: BC2 = simplicial_sets.ClassifyingSpace(C2) + sage: BK = BC2.product(BC2) + sage: BK.homology(range(4)) # needs sage.modules {0: 0, 1: C2 x C2, 2: C2, 3: C2 x C2 x C2} TESTS:: sage: S3 = simplicial_sets.Sphere(3) - sage: S3.homology(0) # optional - sage.modules + sage: S3.homology(0) # needs sage.modules 0 - sage: S3.homology((0,)) # optional - sage.modules + sage: S3.homology((0,)) # needs sage.modules {0: 0} - sage: S3.homology(0, reduced=False) # optional - sage.modules + sage: S3.homology(0, reduced=False) # needs sage.modules Z - sage: BC3.homology() # optional - sage.groups sage.modules + sage: BC3.homology() # needs sage.groups sage.modules Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology @@ -2049,21 +2063,22 @@ def cohomology(self, dim=None, **kwds): EXAMPLES:: - sage: simplicial_sets.KleinBottle().homology(1) + sage: simplicial_sets.KleinBottle().homology(1) # needs sage.modules Z x C2 - sage: simplicial_sets.KleinBottle().cohomology(1) + sage: simplicial_sets.KleinBottle().cohomology(1) # needs sage.modules Z - sage: simplicial_sets.KleinBottle().cohomology(2) + sage: simplicial_sets.KleinBottle().cohomology(2) # needs sage.modules C2 TESTS:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.cohomology() + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.cohomology() # needs sage.groups Traceback (most recent call last): ... - NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology + NotImplementedError: this simplicial set may be infinite, + so specify dimensions when computing homology """ return self.homology(dim=dim, cohomology=True, **kwds) @@ -2096,12 +2111,12 @@ def betti(self, dim=None, subcomplex=None): Build the two-sphere as a three-fold join of a two-point space with itself:: - sage: simplicial_sets.Sphere(5).betti() + sage: simplicial_sets.Sphere(5).betti() # needs sage.modules {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1} - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # optional - sage.groups - sage: BC3.betti(range(4)) # optional - sage.groups sage.modules + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.betti(range(4)) # needs sage.groups sage.modules {0: 1, 1: 0, 2: 0, 3: 0} """ dict = {} @@ -2138,14 +2153,16 @@ def n_chains(self, n, base_ring=ZZ, cochains=False): EXAMPLES:: sage: S3 = simplicial_sets.Sphere(3) - sage: C = S3.n_chains(3, cochains=True) - sage: list(C.basis()) + sage: C = S3.n_chains(3, cochains=True) # needs sage.modules + sage: list(C.basis()) # needs sage.modules [\chi_sigma_3] - sage: Sigma3 = groups.permutation.Symmetric(3) # optional - sage.groups - sage: BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3) # optional - sage.groups - sage: list(BSigma3.n_chains(1).basis()) # optional - sage.groups + + sage: # needs sage.groups + sage: Sigma3 = groups.permutation.Symmetric(3) + sage: BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3) + sage: list(BSigma3.n_chains(1).basis()) # needs sage.modules [(1,2), (1,2,3), (1,3), (1,3,2), (2,3)] - sage: list(BSigma3.n_chains(1, cochains=True).basis()) # optional - sage.groups + sage: list(BSigma3.n_chains(1, cochains=True).basis()) # needs sage.modules [\chi_(1,2), \chi_(1,2,3), \chi_(1,3), \chi_(1,3,2), \chi_(2,3)] """ if self.is_finite(): @@ -2193,41 +2210,41 @@ def quotient(self, subcomplex, vertex_name='*'): sage: e = AbstractSimplex(1, name='e') sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, w), f: (v, w)}) - sage: Y = X.quotient([f]) # optional - sage.graphs - sage: Y.nondegenerate_simplices() # optional - sage.graphs + sage: Y = X.quotient([f]) + sage: Y.nondegenerate_simplices() [*, e] - sage: Y.homology(1) # optional - sage.graphs + sage: Y.homology(1) # needs sage.modules Z sage: E = SimplicialSet({e: (v, w)}) - sage: Z = E.quotient([v, w]) # optional - sage.graphs - sage: Z.nondegenerate_simplices() # optional - sage.graphs + sage: Z = E.quotient([v, w]) + sage: Z.nondegenerate_simplices() [*, e] - sage: Z.homology(1) # optional - sage.graphs + sage: Z.homology(1) # needs sage.modules Z - sage: F = E.quotient([v]) # optional - sage.graphs - sage: F.nondegenerate_simplices() # optional - sage.graphs + sage: F = E.quotient([v]) + sage: F.nondegenerate_simplices() [*, w, e] - sage: F.base_point() # optional - sage.graphs + sage: F.base_point() * + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.graphs - sage: RP5_2.homology(base_ring=GF(2)) # optional - sage.graphs sage.modules sage.rings.finite_rings + sage: RP5_2 = RP5.quotient(RP2) + sage: RP5_2.homology(base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 0 over Finite Field of size 2, 3: Vector space of dimension 1 over Finite Field of size 2, 4: Vector space of dimension 1 over Finite Field of size 2, 5: Vector space of dimension 1 over Finite Field of size 2} - - sage: RP5_2.ambient() # optional - sage.graphs + sage: RP5_2.ambient() RP^5 - sage: RP5_2.subcomplex() # optional - sage.graphs + sage: RP5_2.subcomplex() Simplicial set with 3 non-degenerate simplices - sage: RP5_2.quotient_map() # optional - sage.graphs + sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) @@ -2242,7 +2259,7 @@ def quotient(self, subcomplex, vertex_name='*'): sage: L = K.subsimplicial_set([K.n_cells(1)[-1]]) sage: L.nondegenerate_simplices() [(2,), (3,), (2, 3)] - sage: K.quotient([K.n_cells(1)[-1]]).base_point() # optional - sage.graphs + sage: K.quotient([K.n_cells(1)[-1]]).base_point() * sage: K = K.set_base_point(K.n_cells(0)[0]) @@ -2251,14 +2268,14 @@ def quotient(self, subcomplex, vertex_name='*'): sage: L = K.subsimplicial_set([K.n_cells(1)[-1]]) sage: L.nondegenerate_simplices() [(2,), (3,), (2, 3)] - sage: K.quotient(L).base_point() # optional - sage.graphs + sage: K.quotient(L).base_point() (0,) TESTS:: - sage: pt = RP5.quotient(RP5.n_skeleton(5)); pt # optional - sage.graphs sage.groups + sage: pt = RP5.quotient(RP5.n_skeleton(5)); pt # needs sage.groups Quotient: (RP^5/RP^5) - sage: len(pt.nondegenerate_simplices()) # optional - sage.graphs sage.groups + sage: len(pt.nondegenerate_simplices()) # needs sage.groups 1 """ from .simplicial_set_constructions import SubSimplicialSet @@ -2304,37 +2321,37 @@ def disjoint_union(self, *others): sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, v)}) sage: Y = SimplicialSet({f: (v, w)}) - sage: Z = X.disjoint_union(Y) # optional - sage.graphs + sage: Z = X.disjoint_union(Y) Since ``X`` and ``Y`` have simplices in common, Sage uses a copy of ``Y`` when constructing the disjoint union. Note the name conflict in the list of simplices: ``v`` appears twice:: - sage: Z = X.disjoint_union(Y) # optional - sage.graphs - sage: Z.nondegenerate_simplices() # optional - sage.graphs + sage: Z = X.disjoint_union(Y) + sage: Z.nondegenerate_simplices() [v, v, w, e, f] Factors and inclusion maps:: sage: T = simplicial_sets.Torus() sage: S2 = simplicial_sets.Sphere(2) - sage: A = T.disjoint_union(S2) # optional - sage.graphs - sage: A.factors() # optional - sage.graphs + sage: A = T.disjoint_union(S2) + sage: A.factors() (Torus, S^2) - sage: i = A.inclusion_map(0) # optional - sage.graphs - sage: i.domain() # optional - sage.graphs + sage: i = A.inclusion_map(0) + sage: i.domain() Torus - sage: i.codomain() # optional - sage.graphs + sage: i.codomain() Disjoint union: (Torus u S^2) Empty factors are ignored:: sage: from sage.topology.simplicial_set_examples import Empty sage: E = Empty() - sage: K = S2.disjoint_union(S2, E, E, S2) # optional - sage.graphs - sage: K == S2.disjoint_union(S2, S2) # optional - sage.graphs + sage: K = S2.disjoint_union(S2, E, E, S2) + sage: K == S2.disjoint_union(S2, S2) True - sage: K.factors() # optional - sage.graphs + sage: K.factors() (S^2, S^2, S^2) """ from .simplicial_set_constructions import DisjointUnionOfSimplicialSets, \ @@ -2365,25 +2382,26 @@ def coproduct(self, *others): sage: Y = S2.unset_base_point() sage: Z = K.unset_base_point() - sage: S2.coproduct(K).is_pointed() # optional - sage.graphs + sage: + sage: S2.coproduct(K).is_pointed() True - sage: S2.coproduct(K) # optional - sage.graphs + sage: S2.coproduct(K) Wedge: (S^2 v Klein bottle) - sage: D3.coproduct(Y, Z).is_pointed() # optional - sage.graphs + sage: D3.coproduct(Y, Z).is_pointed() False - sage: D3.coproduct(Y, Z) # optional - sage.graphs + sage: D3.coproduct(Y, Z) Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices u Simplicial set with 6 non-degenerate simplices) The coproduct comes equipped with an inclusion map from each summand, as long as the summands are all finite:: - sage: S2.coproduct(K).inclusion_map(0) # optional - sage.graphs + sage: S2.coproduct(K).inclusion_map(0) Simplicial set morphism: From: S^2 To: Wedge: (S^2 v Klein bottle) Defn: [v_0, sigma_2] --> [*, sigma_2] - sage: D3.coproduct(Y, Z).inclusion_map(2) # optional - sage.graphs + sage: D3.coproduct(Y, Z).inclusion_map(2) Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: Disjoint union: (3-simplex @@ -2394,7 +2412,7 @@ def coproduct(self, *others): TESTS:: - sage: D3.coproduct(S2, Z) # optional - sage.graphs + sage: D3.coproduct(S2, Z) Traceback (most recent call last): ... ValueError: some, but not all, of the simplicial sets are pointed, @@ -2447,7 +2465,7 @@ def product(self, *others): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) - sage: T.homology(reduced=False) # optional - sage.modules + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} Since ``S1`` is pointed, so is ``T``:: @@ -2464,7 +2482,7 @@ def product(self, *others): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: S2xS3 = S2.product(S3) - sage: S2xS3.homology(reduced=False) + sage: S2xS3.homology(reduced=False) # needs sage.modules {0: Z, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} sage: S2xS3.factors() == (S2, S3) @@ -2472,10 +2490,11 @@ def product(self, *others): sage: S2xS3.factors() == (S3, S2) False - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.rename('RP^oo') - sage: X = B.product(B, S2) - sage: X + sage: X = B.product(B, S2); X RP^oo x RP^oo x S^2 sage: X.factor(1) RP^oo @@ -2489,7 +2508,7 @@ def product(self, *others): From: S^2 x S^3 To: S^2 Defn: ... - sage: S2xS3.wedge_as_subset().homology() + sage: S2xS3.wedge_as_subset().homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z} In the case of pointed simplicial sets, there is an inclusion @@ -2547,7 +2566,7 @@ def pushout(self, *maps): sage: K = simplicial_sets.Simplex(4) sage: L = K.n_skeleton(3) - sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()); S4 # optional - sage.graphs + sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()); S4 Pushout of maps: Simplicial set morphism: From: Simplicial set with 30 non-degenerate simplices @@ -2569,9 +2588,9 @@ def pushout(self, *maps): (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] - sage: len(S4.nondegenerate_simplices()) # optional - sage.graphs + sage: len(S4.nondegenerate_simplices()) 2 - sage: S4.homology(4) # optional - sage.graphs sage.modules + sage: S4.homology(4) # needs sage.modules Z The associated maps:: @@ -2579,41 +2598,41 @@ def pushout(self, *maps): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) - sage: W = S1.wedge(T) # wedge, constructed as a pushout # optional - sage.graphs - sage: W.defining_map(1) # optional - sage.graphs + sage: W = S1.wedge(T) # wedge, constructed as a pushout + sage: W.defining_map(1) Simplicial set morphism: From: Point To: S^1 x S^1 Defn: Constant map at (v_0, v_0) - sage: W.structure_map(0) # optional - sage.graphs + sage: W.structure_map(0) Simplicial set morphism: From: S^1 To: Wedge: (S^1 v S^1 x S^1) Defn: [v_0, sigma_1] --> [*, sigma_1] - sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], # optional - sage.graphs sage.modules + sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}) The maps `f: S^1 \to T` and `1: T \to T` induce a map `S^1 \vee T \to T`:: - sage: g = W.universal_property(f, Hom(T,T).identity()) # optional - sage.graphs sage.modules - sage: g.domain() == W # optional - sage.graphs sage.modules + sage: g = W.universal_property(f, Hom(T,T).identity()) + sage: g.domain() == W True - sage: g.codomain() == T # optional - sage.graphs sage.modules + sage: g.codomain() == T True TESTS:: sage: K = simplicial_sets.Simplex(5) - sage: K.pushout() # optional - sage.graphs + sage: K.pushout() Empty simplicial set sage: S0 = simplicial_sets.Sphere(0) sage: pt_map = S0.base_point_map() - sage: pt_map.domain().pushout(pt_map) == S0 # optional - sage.graphs + sage: pt_map.domain().pushout(pt_map) == S0 True - sage: K.pushout(K.constant_map(), pt_map) # optional - sage.graphs + sage: K.pushout(K.constant_map(), pt_map) Traceback (most recent call last): ... ValueError: the domains of the maps must be equal @@ -2665,7 +2684,7 @@ def pullback(self, *maps): sage: S2 = simplicial_sets.Sphere(2) sage: pt = simplicial_sets.Point() sage: P = pt.pullback(S2.constant_map(), S2.constant_map()) - sage: P.homology(2) + sage: P.homology(2) # needs sage.modules Z x Z If the pullback is defined via maps `f_i: X_i \to Y`, then @@ -2676,7 +2695,7 @@ def pullback(self, *maps): sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() sage: P = S2.pullback(one, one) - sage: P.homology() + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: P.defining_map(0) == one @@ -2702,13 +2721,13 @@ def pullback(self, *maps): sage: K = T.factor(0, as_subset=True) sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}) - sage: D = S1.cone() # the cone C(S^1) # optional - sage.graphs - sage: g = D.map_from_base() # map from S^1 to C(S^1) # optional - sage.graphs - sage: P = T.product(D) # optional - sage.graphs - sage: h = P.universal_property(f, g) # optional - sage.graphs - sage: h.domain() == S1 # optional - sage.graphs + sage: D = S1.cone() # the cone C(S^1) + sage: g = D.map_from_base() # map from S^1 to C(S^1) + sage: P = T.product(D) + sage: h = P.universal_property(f, g) + sage: h.domain() == S1 True - sage: h.codomain() == P # optional - sage.graphs + sage: h.codomain() == P True TESTS:: @@ -2759,25 +2778,25 @@ def wedge(self, *others): sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, v)}, base_point=v) sage: Y = SimplicialSet({f: (w, w)}, base_point=w) - sage: W = X.wedge(Y) # optional - sage.graphs - sage: W.nondegenerate_simplices() # optional - sage.graphs + sage: W = X.wedge(Y) + sage: W.nondegenerate_simplices() [*, e, f] - sage: W.homology() # optional - sage.graphs + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z} sage: S2 = simplicial_sets.Sphere(2) - sage: X.wedge(S2).homology(reduced=False) # optional - sage.graphs + sage: X.wedge(S2).homology(reduced=False) # needs sage.modules {0: Z, 1: Z, 2: Z} - sage: X.wedge(X).nondegenerate_simplices() # optional - sage.graphs + sage: X.wedge(X).nondegenerate_simplices() [*, e, e] sage: S3 = simplicial_sets.Sphere(3) - sage: W = S2.wedge(S3, S2) # optional - sage.graphs - sage: W.inclusion_map(2) # optional - sage.graphs + sage: W = S2.wedge(S3, S2) + sage: W.inclusion_map(2) Simplicial set morphism: From: S^2 To: Wedge: (S^2 v S^3 v S^2) Defn: [v_0, sigma_2] --> [*, sigma_2] - sage: W.projection_map(1) # optional - sage.graphs + sage: W.projection_map(1) Simplicial set morphism: From: Wedge: (S^2 v S^3 v S^2) To: Quotient: (Wedge: (S^2 v S^3 v S^2)/Simplicial set with 3 non-degenerate simplices) @@ -2789,15 +2808,15 @@ def wedge(self, *others): sage: S2.f_vector() [1, 0, 1] - sage: W.projection_map(2).codomain().f_vector() # optional - sage.graphs + sage: W.projection_map(2).codomain().f_vector() [1, 0, 1] - sage: (W.projection_map(2) * W.inclusion_map(2)).is_bijective() # optional - sage.graphs + sage: (W.projection_map(2) * W.inclusion_map(2)).is_bijective() True TESTS:: sage: Z = SimplicialSet({e: (v,w)}) - sage: X.wedge(Z) # optional - sage.graphs + sage: X.wedge(Z) Traceback (most recent call last): ... ValueError: the simplicial sets must be pointed @@ -2832,18 +2851,18 @@ def cone(self): sage: v = AbstractSimplex(0, name='v') sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, v)}) - sage: CX = X.cone() # unreduced cone, since X not pointed # optional - sage.graphs - sage: CX.nondegenerate_simplices() # optional - sage.graphs + sage: CX = X.cone() # unreduced cone, since X not pointed + sage: CX.nondegenerate_simplices() [*, v, (v,*), e, (e,*)] - sage: CX.base_point() # optional - sage.graphs + sage: CX.base_point() * `X` as a subset of the cone, and also the map from `X`, in the unreduced case:: - sage: CX.base_as_subset() # optional - sage.graphs + sage: CX.base_as_subset() Simplicial set with 2 non-degenerate simplices - sage: CX.map_from_base() # optional - sage.graphs + sage: CX.map_from_base() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices To: Cone of Simplicial set with 2 non-degenerate simplices @@ -2852,10 +2871,10 @@ def cone(self): In the reduced case, only the map from `X` is available:: sage: X = X.set_base_point(v) - sage: CX = X.cone() # reduced cone # optional - sage.graphs - sage: CX.nondegenerate_simplices() # optional - sage.graphs + sage: CX = X.cone() # reduced cone + sage: CX.nondegenerate_simplices() [*, e, (e,*)] - sage: CX.map_from_base() # optional - sage.graphs + sage: CX.map_from_base() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices To: Reduced cone of Simplicial set with 2 non-degenerate simplices @@ -2890,25 +2909,26 @@ def suspension(self, n=1): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups - sage: S1 = simplicial_sets.Sphere(1) # optional - sage.groups - sage: SigmaRP4 = RP4.suspension() # optional - sage.graphs sage.groups - sage: S1_smash_RP4 = S1.smash_product(RP4) # optional - sage.graphs sage.groups - sage: SigmaRP4.homology() == S1_smash_RP4.homology() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: S1 = simplicial_sets.Sphere(1) + sage: SigmaRP4 = RP4.suspension() + sage: S1_smash_RP4 = S1.smash_product(RP4) + sage: SigmaRP4.homology() == S1_smash_RP4.homology() True The version of the suspension obtained by the smash product is typically less efficient than the reduced suspension produced here:: - sage: SigmaRP4.f_vector() # optional - sage.graphs sage.groups + sage: SigmaRP4.f_vector() # needs sage.groups [1, 0, 1, 1, 1, 1] - sage: S1_smash_RP4.f_vector() # optional - sage.graphs sage.groups + sage: S1_smash_RP4.f_vector() # needs sage.groups [1, 1, 4, 6, 8, 5] TESTS:: - sage: RP4.suspension(-3) # optional - sage.graphs sage.groups + sage: RP4.suspension(-3) # needs sage.groups Traceback (most recent call last): ... ValueError: n must be non-negative @@ -2965,22 +2985,22 @@ def reduce(self): sage: K = simplicial_sets.Simplex(2) sage: K.is_reduced() False - sage: X = K.reduce() # optional - sage.graphs - sage: X.is_reduced() # optional - sage.graphs + sage: X = K.reduce() + sage: X.is_reduced() True ``X`` is reduced, so calling ``reduce`` on it again returns ``X`` itself:: - sage: X is X.reduce() # optional - sage.graphs + sage: X is X.reduce() True - sage: K is K.reduce() # optional - sage.graphs + sage: K is K.reduce() False Raise an error for disconnected simplicial sets:: sage: S0 = simplicial_sets.Sphere(0) - sage: S0.reduce() # optional - sage.graphs + sage: S0.reduce() Traceback (most recent call last): ... ValueError: this simplicial set is not connected @@ -3238,7 +3258,7 @@ def __init__(self, data, base_point=None, name=None, check=True, sage: skip = ["_test_pickling", "_test_elements"] sage: TestSuite(S1).run(skip=skip) sage: TestSuite(simplicial_sets.Sphere(5)).run(skip=skip) - sage: TestSuite(simplicial_sets.RealProjectiveSpace(6)).run(skip=skip) # optional - sage.groups + sage: TestSuite(simplicial_sets.RealProjectiveSpace(6)).run(skip=skip) # needs sage.groups """ def face(sigma, i): """ @@ -3455,7 +3475,7 @@ def __copy__(self): False sage: T.n_cells(0)[0] == copy(T).n_cells(0)[0] False - sage: T.homology() == copy(T).homology() + sage: T.homology() == copy(T).homology() # needs sage.modules True """ return SimplicialSet(dict(copy.deepcopy(self._data))) @@ -3575,7 +3595,7 @@ def euler_characteristic(self): EXAMPLES:: - sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic() # optional - sage.groups + sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic() # needs sage.groups 1 sage: simplicial_sets.Sphere(6).euler_characteristic() 2 @@ -3623,21 +3643,22 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: degen = v.apply_degeneracies(1, 0) # s_1 s_0 applied to v sage: sigma = AbstractSimplex(3) - sage: S3 = SimplicialSet({sigma: (degen, degen, degen, degen)}) # the 3-sphere - sage: S3.chain_complex().homology() # optional - sage.modules + sage: S3 = SimplicialSet({sigma: (degen, degen, degen, degen)}) # the 3-sphere + sage: S3.chain_complex().homology() {0: Z, 3: Z} - sage: S3.chain_complex(augmented=True).homology() # optional - sage.modules + sage: S3.chain_complex(augmented=True).homology() {-1: 0, 0: 0, 3: Z} - sage: S3.chain_complex(dimensions=range(3), base_ring=QQ).homology() # optional - sage.modules + sage: S3.chain_complex(dimensions=range(3), base_ring=QQ).homology() {0: Vector space of dimension 1 over Rational Field} - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP5.chain_complex(subcomplex=RP2).homology() # optional - sage.groups sage.modules + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP5.chain_complex(subcomplex=RP2).homology() # needs sage.groups sage.modules {0: Z, 3: C2, 4: 0, 5: Z} TESTS: @@ -3645,14 +3666,15 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, Convert some simplicial complexes and `\Delta`-complexes to simplicial sets, and compare homology calculations:: + sage: # needs sage.modules sage: T = simplicial_complexes.Torus() - sage: T.homology() == SimplicialSet(T).homology() # optional - sage.modules + sage: T.homology() == SimplicialSet(T).homology() True - sage: RP2 = delta_complexes.RealProjectivePlane() # optional - sage.groups sage.modules - sage: RP2.homology() == SimplicialSet(RP2).homology() # optional - sage.groups sage.modules + sage: RP2 = delta_complexes.RealProjectivePlane() + sage: RP2.homology() == SimplicialSet(RP2).homology() True - sage: cohoRP2 = RP2.cohomology(base_ring=GF(2)) # optional - sage.groups sage.modules sage.rings.finite_rings - sage: cohoRP2 == SimplicialSet(RP2).cohomology(base_ring=GF(2)) # optional - sage.groups sage.modules sage.rings.finite_rings + sage: cohoRP2 = RP2.cohomology(base_ring=GF(2)) + sage: cohoRP2 == SimplicialSet(RP2).cohomology(base_ring=GF(2)) True """ from sage.homology.chain_complex import ChainComplex @@ -3792,15 +3814,16 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: - sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # optional - sage.groups - sage: phi, M = RP2.algebraic_topological_model(GF(2)) # optional - sage.groups sage.rings.finite_rings - sage: M.homology() # optional - sage.groups sage.modules sage.rings.finite_rings + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: phi, M = RP2.algebraic_topological_model(GF(2)) # needs sage.groups + sage: M.homology() # needs sage.groups sage.modules {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} + sage: T = simplicial_sets.Torus() - sage: phi, M = T.algebraic_topological_model(QQ) - sage: M.homology() # optional - sage.modules + sage: phi, M = T.algebraic_topological_model(QQ) # needs sage.modules + sage: M.homology() # needs sage.modules {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -4051,29 +4074,29 @@ def shrink_simplicial_complex(K): sage: from sage.topology.simplicial_set import shrink_simplicial_complex sage: K = simplicial_complexes.Simplex(3) - sage: X = shrink_simplicial_complex(K) # optional - sage.graphs - sage: X.f_vector() # optional - sage.graphs + sage: X = shrink_simplicial_complex(K) + sage: X.f_vector() [1] sage: Y = simplicial_complexes.Sphere(2) - sage: S2 = shrink_simplicial_complex(Y); S2 # optional - sage.graphs + sage: S2 = shrink_simplicial_complex(Y); S2 Quotient: (Simplicial set with 14 non-degenerate simplices/Simplicial set with 13 non-degenerate simplices) - sage: S2.f_vector() # optional - sage.graphs + sage: S2.f_vector() [1, 0, 1] - sage: S2.homology() # optional - sage.graphs sage.modules + sage: S2.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: Z = simplicial_complexes.SurfaceOfGenus(3) sage: Z.f_vector() [1, 15, 57, 38] - sage: Z.homology() # optional - sage.modules + sage: Z.homology() # needs sage.modules {0: 0, 1: Z^6, 2: Z} - sage: M = shrink_simplicial_complex(Z) # optional - sage.graphs - sage: M.f_vector() # random # optional - sage.graphs + sage: M = shrink_simplicial_complex(Z) + sage: M.f_vector() # random [1, 32, 27] - sage: M.homology() # optional - sage.graphs sage.modules + sage: M.homology() # needs sage.modules {0: 0, 1: Z^6, 2: Z} """ L = K._contractible_subcomplex() diff --git a/src/sage/topology/simplicial_set_catalog.py b/src/sage/topology/simplicial_set_catalog.py index 94208f14dac..0269c8f6628 100644 --- a/src/sage/topology/simplicial_set_catalog.py +++ b/src/sage/topology/simplicial_set_catalog.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Catalog of simplicial sets @@ -34,14 +35,14 @@ EXAMPLES:: - sage: RP10 = simplicial_sets.RealProjectiveSpace(8) # optional - sage.groups - sage: RP10.homology() # optional - sage.groups sage.modules + sage: RP10 = simplicial_sets.RealProjectiveSpace(8) # needs sage.groups + sage: RP10.homology() # needs sage.groups sage.modules {0: 0, 1: C2, 2: 0, 3: C2, 4: 0, 5: C2, 6: 0, 7: C2, 8: 0} sage: eta = simplicial_sets.HopfMap() sage: S3 = eta.domain() sage: S2 = eta.codomain() - sage: S3.wedge(S2).homology() # optional - sage.graphs sage.modules + sage: S3.wedge(S2).homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z} """ diff --git a/src/sage/topology/simplicial_set_constructions.py b/src/sage/topology/simplicial_set_constructions.py index b2b6bbbae7c..ae98821df8a 100644 --- a/src/sage/topology/simplicial_set_constructions.py +++ b/src/sage/topology/simplicial_set_constructions.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Methods of constructing simplicial sets @@ -15,14 +15,14 @@ sage: K = simplicial_sets.Simplex(1) sage: endpoints = K.n_skeleton(0) - sage: circle = K.quotient(endpoints) # optional - sage.graphs + sage: circle = K.quotient(endpoints) The mapping cone of a morphism of simplicial sets is constructed as a pushout:: sage: eta = simplicial_sets.HopfMap() - sage: CP2 = eta.mapping_cone() # optional - sage.graphs - sage: type(CP2) # optional - sage.graphs + sage: CP2 = eta.mapping_cone() + sage: type(CP2) See the main documentation for simplicial sets, as well as for the @@ -34,7 +34,7 @@ for example, if ``K`` is a simplicial set, calling ``K.suspension()`` twice returns the same result both times:: - sage: CP2.suspension() is CP2.suspension() # optional - sage.graphs + sage: CP2.suspension() is CP2.suspension() True So on one hand, a command like ``simplicial_sets.Sphere(2)`` @@ -48,7 +48,7 @@ sage: S2 = simplicial_sets.Sphere(2) sage: S2.product(S2) == S2.product(S2) True - sage: S2.disjoint_union(CP2, S2) == S2.disjoint_union(CP2, S2) # optional - sage.graphs + sage: S2.disjoint_union(CP2, S2) == S2.disjoint_union(CP2, S2) True AUTHORS: @@ -144,14 +144,14 @@ def __init__(self, data, ambient=None): sage: S3 = simplicial_sets.Sphere(3) sage: K = simplicial_sets.KleinBottle() - sage: X = S3.disjoint_union(K) # optional - sage.graphs - sage: Y = X.structure_map(0).image() # the S3 summand # optional - sage.graphs - sage: Y.inclusion_map() # optional - sage.graphs + sage: X = S3.disjoint_union(K) + sage: Y = X.structure_map(0).image() # the S3 summand + sage: Y.inclusion_map() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices To: Disjoint union: (S^3 u Klein bottle) Defn: [v_0, sigma_3] --> [v_0, sigma_3] - sage: Y.ambient_space() # optional - sage.graphs + sage: Y.ambient_space() Disjoint union: (S^3 u Klein bottle) TESTS:: @@ -192,9 +192,9 @@ def inclusion_map(self): EXAMPLES:: - sage: RP6 = simplicial_sets.RealProjectiveSpace(6) # optional - sage.groups - sage: K = RP6.n_skeleton(2) # optional - sage.groups - sage: K.inclusion_map() # optional - sage.groups + sage: RP6 = simplicial_sets.RealProjectiveSpace(6) # needs sage.groups + sage: K = RP6.n_skeleton(2) # needs sage.groups + sage: K.inclusion_map() # needs sage.groups Simplicial set morphism: From: Simplicial set with 3 non-degenerate simplices To: RP^6 @@ -203,7 +203,7 @@ def inclusion_map(self): `RP^6` itself is constructed as a subsimplicial set of `RP^\infty`:: - sage: latex(RP6.inclusion_map()) # optional - sage.groups + sage: latex(RP6.inclusion_map()) # needs sage.groups RP^{6} \to RP^{\infty} """ return self._inclusion @@ -218,7 +218,7 @@ def ambient_space(self): sage: eight = T.wedge_as_subset() sage: eight Simplicial set with 3 non-degenerate simplices - sage: eight.fundamental_group() # optional - sage.groups + sage: eight.fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > sage: eight.ambient_space() Torus @@ -268,10 +268,11 @@ def __init__(self, maps=None): base point map gives a simplicial set isomorphic to the original subcomplex:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: K = RP5.quotient(RP5.n_skeleton(2)) # optional - sage.groups - sage: X = K.pullback(K.quotient_map(), K.base_point_map()) # optional - sage.groups - sage: X.homology() == RP5.n_skeleton(2).homology() # optional - sage.groups sage.modules + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: K = RP5.quotient(RP5.n_skeleton(2)) + sage: X = K.pullback(K.quotient_map(), K.base_point_map()) + sage: X.homology() == RP5.n_skeleton(2).homology() # needs sage.modules True Pullbacks of identity maps:: @@ -279,7 +280,7 @@ def __init__(self, maps=None): sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() sage: P = S2.pullback(one, one) - sage: P.homology() # optional - sage.modules + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} The pullback is constructed in terms of the product -- of @@ -320,18 +321,19 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: one = Hom(B,B).identity() # optional - sage.groups - sage: c = Hom(B,B).constant_map() # optional - sage.groups - sage: P = B.pullback(one, c) # optional - sage.groups - sage: P.n_skeleton(2) # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: one = Hom(B,B).identity() + sage: c = Hom(B,B).constant_map() + sage: P = B.pullback(one, c) + sage: P.n_skeleton(2) Pullback of maps: Simplicial set endomorphism of Simplicial set with 3 non-degenerate simplices Defn: Identity map Simplicial set endomorphism of Simplicial set with 3 non-degenerate simplices Defn: Constant map at 1 - sage: P.n_skeleton(3).homology() # optional - sage.groups sage.modules + sage: P.n_skeleton(3).homology() # needs sage.modules {0: 0, 1: C2, 2: 0, 3: Z} """ if self.is_finite(): @@ -364,15 +366,16 @@ def defining_map(self, i): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: K = RP5.quotient(RP5.n_skeleton(2)) # optional - sage.groups - sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) # optional - sage.groups - sage: Y.defining_map(1) # optional - sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: K = RP5.quotient(RP5.n_skeleton(2)) + sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) + sage: Y.defining_map(1) Simplicial set morphism: From: Point To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) Defn: Constant map at * - sage: Y.defining_map(0).domain() # optional - sage.groups + sage: Y.defining_map(0).domain() RP^5 """ return self._maps[i] @@ -446,11 +449,12 @@ def __init__(self, maps=None): sage: S2.pullback(eta, c).is_finite() True - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: one = Hom(B,B).identity() # optional - sage.groups - sage: c = Hom(B,B).constant_map() # optional - sage.groups - sage: B.pullback(one, c).is_finite() # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: one = Hom(B,B).identity() + sage: c = Hom(B,B).constant_map() + sage: B.pullback(one, c).is_finite() False TESTS:: @@ -617,10 +621,11 @@ def structure_map(self, i): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: K = RP5.quotient(RP5.n_skeleton(2)) # optional - sage.groups - sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) # optional - sage.groups - sage: Y.structure_map(0) # optional - sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: K = RP5.quotient(RP5.n_skeleton(2)) + sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) + sage: Y.structure_map(0) Simplicial set morphism: From: Pullback of maps: Simplicial set morphism: @@ -634,12 +639,12 @@ def structure_map(self, i): Defn: Constant map at * To: RP^5 Defn: [(1, *), (f, s_0 *), (f * f, s_1 s_0 *)] --> [1, f, f * f] - sage: Y.structure_map(1).codomain() # optional - sage.groups + sage: Y.structure_map(1).codomain() Point These maps are also accessible via :meth:`projection_map`:: - sage: Y.projection_map(1).codomain() # optional - sage.groups + sage: Y.projection_map(1).codomain() # needs sage.groups Point """ if len(self._maps) == 1: @@ -722,11 +727,11 @@ def factors(self): EXAMPLES:: - sage: S2 = simplicial_sets.Sphere(2) # optional - sage.graphs - sage: S3 = simplicial_sets.Sphere(3) # optional - sage.graphs - sage: S2.wedge(S3).factors() == (S2, S3) # optional - sage.graphs + sage: S2 = simplicial_sets.Sphere(2) + sage: S3 = simplicial_sets.Sphere(3) + sage: S2.wedge(S3).factors() == (S2, S3) True - sage: S2.product(S3).factors()[0] # optional - sage.graphs + sage: S2.product(S3).factors()[0] S^2 """ return self._factors @@ -743,15 +748,17 @@ def factor(self, i): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) - sage: K = S2.disjoint_union(S3) # optional - sage.graphs - sage: K.factor(0) # optional - sage.graphs + sage: K = S2.disjoint_union(S3) + sage: K.factor(0) S^2 - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: X = B.wedge(S3, B) # optional - sage.groups - sage: X.factor(1) # optional - sage.groups + + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: X = B.wedge(S3, B) + sage: X.factor(1) S^3 - sage: X.factor(2) # optional - sage.groups + sage: X.factor(2) Classifying space of Multiplicative Abelian group isomorphic to C2 """ return self.factors()[i] @@ -822,7 +829,7 @@ def __init__(self, factors=None): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) - sage: T.homology(reduced=False) # optional - sage.modules + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} Since ``S1`` is pointed, so is ``T``:: @@ -839,24 +846,25 @@ def __init__(self, factors=None): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: Z = S2.product(S3) - sage: Z.homology() # optional - sage.modules + sage: Z.homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} Products involving infinite simplicial sets:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.rename('RP^oo') - sage: X = B.product(B) - sage: X + sage: X = B.product(B); X RP^oo x RP^oo sage: X.n_cells(1) [(f, f), (f, s_0 1), (s_0 1, f)] - sage: X.homology(range(3), base_ring=GF(2)) # optional - sage.modules + sage: X.homology(range(3), base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 2 over Finite Field of size 2, 2: Vector space of dimension 3 over Finite Field of size 2} sage: Y = B.product(S2) - sage: Y.homology(range(5), base_ring=GF(2)) # optional - sage.modules + sage: Y.homology(range(5), base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 2 over Finite Field of size 2, @@ -889,10 +897,11 @@ def n_skeleton(self, n): sage: S2.product(S3).n_skeleton(2) Simplicial set with 2 non-degenerate simplices - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: X = B.product(B) # optional - sage.groups - sage: X.n_skeleton(2) # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: X = B.product(B) + sage: X.n_skeleton(2) Simplicial set with 13 non-degenerate simplices """ n_skel = SimplicialSet_finite.n_skeleton @@ -938,7 +947,7 @@ def factor(self, i, as_subset=False): sage: K.factor(0, as_subset=True) Simplicial set with 2 non-degenerate simplices - sage: K.factor(0, as_subset=True).homology() # optional - sage.groups + sage: K.factor(0, as_subset=True).homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: K.factor(0) is S2 @@ -970,11 +979,11 @@ def _repr_(self): sage: S2 = simplicial_sets.Sphere(2) sage: K = simplicial_sets.KleinBottle() - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: S2.product(S2) # optional - sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: B = simplicial_sets.ClassifyingSpace(G) # needs sage.groups + sage: S2.product(S2) S^2 x S^2 - sage: S2.product(K, B) # optional - sage.groups + sage: S2.product(K, B) # needs sage.groups S^2 x Klein bottle x Classifying space of Multiplicative Abelian group isomorphic to C2 """ return ' x '.join(str(X) for X in self._factors) @@ -988,8 +997,8 @@ def _latex_(self): sage: S2 = simplicial_sets.Sphere(2) sage: latex(S2.product(S2)) S^{2} \times S^{2} - sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) # optional - sage.groups - sage: latex(S2.product(RPoo, S2)) # optional - sage.groups + sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) # needs sage.groups + sage: latex(S2.product(RPoo, S2)) # needs sage.groups S^{2} \times RP^{\infty} \times S^{2} """ return ' \\times '.join(latex(X) for X in self._factors) @@ -1018,7 +1027,7 @@ def __init__(self, factors=None): sage: e = AbstractSimplex(1) sage: X = SimplicialSet({e: (v, v)}) sage: W = X.product(X, X) - sage: W.homology() # optional - sage.groups + sage: W.homology() # needs sage.groups {0: 0, 1: Z x Z x Z, 2: Z x Z x Z, 3: Z} sage: W.is_pointed() False @@ -1050,7 +1059,9 @@ def projection_map(self, i): sage: T = simplicial_sets.Torus() sage: f_0 = T.projection_map(0) sage: f_1 = T.projection_map(1) - sage: m_0 = f_0.induced_homology_morphism().to_matrix(1) # matrix in dim 1 + + sage: # needs sage.modules + sage: m_0 = f_0.induced_homology_morphism().to_matrix(1) # matrix in dim 1 sage: m_1 = f_1.induced_homology_morphism().to_matrix(1) sage: m_0.rank() 1 @@ -1079,7 +1090,7 @@ def wedge_as_subset(self): sage: W = P.wedge_as_subset() sage: W.nondegenerate_simplices() [(v, w), (e, s_0 w), (s_0 v, f)] - sage: W.homology() # optional - sage.groups + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z} """ basept_factors = [sset.base_point() for sset in self.factors()] @@ -1111,7 +1122,7 @@ def fat_wedge_as_subset(self): sage: S1 = simplicial_sets.Sphere(1) sage: X = S1.product(S1, S1) sage: W = X.fat_wedge_as_subset() - sage: W.homology() # optional - sage.groups + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z x Z, 2: Z x Z x Z} """ basept_factors = [sset.base_point() for sset in self.factors()] @@ -1196,17 +1207,17 @@ def __init__(self, maps=None, vertex_name=None): sage: f1_data = {a:v, b:v, e2:v.apply_degeneracies(0)} sage: f0 = X.Hom(Y0)(f0_data) sage: f1 = X.Hom(Y1)(f1_data) - sage: P = X.pushout(f0, f1) # optional - sage.graphs - sage: P.nondegenerate_simplices() # optional - sage.graphs + sage: P = X.pushout(f0, f1) + sage: P.nondegenerate_simplices() [a, c, e_0, e_1] There are defining maps `f_i: X \to Y_i` and structure maps `\bar{f}_i: Y_i \to P`; the latter are only implemented in Sage when each `Y_i` is finite. :: - sage: P.defining_map(0) == f0 # optional - sage.graphs + sage: P.defining_map(0) == f0 True - sage: P.structure_map(1) # optional - sage.graphs + sage: P.structure_map(1) Simplicial set morphism: From: 0-simplex To: Pushout of maps: @@ -1219,9 +1230,9 @@ def __init__(self, maps=None, vertex_name=None): To: 0-simplex Defn: Constant map at (0,) Defn: Constant map at a - sage: P.structure_map(0).domain() == Y0 # optional - sage.graphs + sage: P.structure_map(0).domain() == Y0 True - sage: P.structure_map(0).codomain() == P # optional - sage.graphs + sage: P.structure_map(0).codomain() == P True An inefficient way of constructing a suspension for an @@ -1232,31 +1243,31 @@ def __init__(self, maps=None, vertex_name=None): sage: T = T.unset_base_point() sage: CT = T.cone() sage: inc = CT.base_as_subset().inclusion_map() - sage: P = T.pushout(inc, inc) # optional - sage.graphs - sage: P.homology() # optional - sage.graphs sage.modules + sage: P = T.pushout(inc, inc) + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z x Z, 3: Z} - sage: len(P.nondegenerate_simplices()) # optional - sage.graphs + sage: len(P.nondegenerate_simplices()) 20 It is more efficient to construct the suspension as the quotient `CX/X`:: - sage: len(CT.quotient(CT.base_as_subset()).nondegenerate_simplices()) # optional - sage.graphs + sage: len(CT.quotient(CT.base_as_subset()).nondegenerate_simplices()) 8 It is more efficient still if the original simplicial set has a base point:: sage: T = simplicial_sets.Torus() - sage: len(T.suspension().nondegenerate_simplices()) # optional - sage.graphs + sage: len(T.suspension().nondegenerate_simplices()) 6 sage: S1 = simplicial_sets.Sphere(1) sage: pt = simplicial_sets.Point() - sage: bouquet = pt.pushout(S1.base_point_map(), # optional - sage.graphs + sage: bouquet = pt.pushout(S1.base_point_map(), ....: S1.base_point_map(), ....: S1.base_point_map()) - sage: bouquet.homology(1) # optional - sage.graphs sage.modules + sage: bouquet.homology(1) # needs sage.modules Z x Z x Z """ # Import this here to prevent circular imports. @@ -1290,11 +1301,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: K = B.n_skeleton(3) # optional - sage.groups - sage: Q = K.pushout(K.inclusion_map(), K.constant_map()) # optional - sage.groups - sage: Q.n_skeleton(5).homology() # optional - sage.groups sage.modules + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: K = B.n_skeleton(3) + sage: Q = K.pushout(K.inclusion_map(), K.constant_map()) + sage: Q.n_skeleton(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: Z} Of course, computing the `n`-skeleton and then taking homology @@ -1302,7 +1314,7 @@ def n_skeleton(self, n): dimension `n`, since the latter computation will use the `(n+1)`-skeleton:: - sage: Q.homology(range(6)) # optional - sage.groups sage.modules + sage: Q.homology(range(6)) # needs sage.groups sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: C2} """ if self.is_finite(): @@ -1340,15 +1352,15 @@ def defining_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: T = simplicial_sets.Torus() - sage: X = S1.wedge(T) # a pushout # optional - sage.graphs - sage: X.defining_map(0) # optional - sage.graphs + sage: X = S1.wedge(T) # a pushout + sage: X.defining_map(0) Simplicial set morphism: From: Point To: S^1 Defn: Constant map at v_0 - sage: X.defining_map(1).domain() # optional - sage.graphs + sage: X.defining_map(1).domain() Point - sage: X.defining_map(1).codomain() # optional - sage.graphs + sage: X.defining_map(1).codomain() Torus """ return self._maps[i] @@ -1362,7 +1374,7 @@ def _repr_(self): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: pt = simplicial_sets.Point() - sage: pt.pushout(S2.base_point_map(), S3.base_point_map()) # optional - sage.graphs + sage: pt.pushout(S2.base_point_map(), S3.base_point_map()) Pushout of maps: Simplicial set morphism: From: Point @@ -1400,7 +1412,7 @@ def __classcall_private__(cls, maps=None, vertex_name=None): sage: from sage.topology.simplicial_set_constructions import PushoutOfSimplicialSets_finite sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() - sage: PushoutOfSimplicialSets_finite([one, one]) == PushoutOfSimplicialSets_finite((one, one)) # optional - sage.graphs + sage: PushoutOfSimplicialSets_finite([one, one]) == PushoutOfSimplicialSets_finite((one, one)) True """ if maps: @@ -1424,9 +1436,9 @@ def __init__(self, maps=None, vertex_name=None): sage: from sage.topology.simplicial_set_constructions import PushoutOfSimplicialSets_finite sage: T = simplicial_sets.Torus() sage: S2 = simplicial_sets.Sphere(2) - sage: PushoutOfSimplicialSets_finite([T.base_point_map(), S2.base_point_map()]).n_cells(0)[0] # optional - sage.graphs + sage: PushoutOfSimplicialSets_finite([T.base_point_map(), S2.base_point_map()]).n_cells(0)[0] * - sage: PushoutOfSimplicialSets_finite([T.base_point_map(), S2.base_point_map()], vertex_name='v').n_cells(0)[0] # optional - sage.graphs + sage: PushoutOfSimplicialSets_finite([T.base_point_map(), S2.base_point_map()], vertex_name='v').n_cells(0)[0] v """ from sage.graphs.graph import Graph @@ -1597,15 +1609,15 @@ def structure_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: T = simplicial_sets.Torus() - sage: X = S1.disjoint_union(T) # a pushout # optional - sage.graphs - sage: X.structure_map(0) # optional - sage.graphs + sage: X = S1.disjoint_union(T) # a pushout + sage: X.structure_map(0) Simplicial set morphism: From: S^1 To: Disjoint union: (S^1 u Torus) Defn: [v_0, sigma_1] --> [v_0, sigma_1] - sage: X.structure_map(1).domain() # optional - sage.graphs + sage: X.structure_map(1).domain() Torus - sage: X.structure_map(1).codomain() # optional - sage.graphs + sage: X.structure_map(1).codomain() Disjoint union: (S^1 u Torus) """ return self._structure[i] @@ -1640,12 +1652,12 @@ def universal_property(self, *maps): sage: f_0 = Hom(X, Y_0)({v:v, w:w, x:x, evw:evw, evx:evx}) sage: f_1 = Hom(X, Y_1)({v:v, w:v, x:x, ....: evw:v.apply_degeneracies(0), evx:evx}) - sage: P = X.pushout(f_0, f_1) # optional - sage.graphs + sage: P = X.pushout(f_0, f_1) sage: one = Hom(Y_1, Y_1).identity() sage: g = Hom(Y_0, Y_1)({v:v, w:v, x:x, ....: evw:v.apply_degeneracies(0), evx:evx, ewx:evx}) - sage: P.universal_property(g, one) # optional - sage.graphs + sage: P.universal_property(g, one) Simplicial set morphism: From: Pushout of maps: Simplicial set morphism: @@ -1698,11 +1710,12 @@ def __init__(self, inclusion, vertex_name='*'): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP5_2 = RP5.quotient(RP2); RP5_2 # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: RP2 = RP5.n_skeleton(2) + sage: RP5_2 = RP5.quotient(RP2); RP5_2 Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - sage: RP5_2.quotient_map() # optional - sage.graphs sage.groups + sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) @@ -1727,17 +1740,19 @@ def ambient(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.graphs sage.groups - sage: RP5_2.ambient() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: RP2 = RP5.n_skeleton(2) + sage: RP5_2 = RP5.quotient(RP2) + sage: RP5_2.ambient() RP^5 - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: K = B.n_skeleton(3) # optional - sage.groups - sage: Q = B.quotient(K) # optional - sage.graphs sage.groups - sage: Q.ambient() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: K = B.n_skeleton(3) + sage: Q = B.quotient(K) + sage: Q.ambient() Classifying space of Multiplicative Abelian group isomorphic to C2 """ return self._maps[0].codomain() @@ -1750,17 +1765,19 @@ def subcomplex(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.graphs sage.groups - sage: RP5_2.subcomplex() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: RP2 = RP5.n_skeleton(2) + sage: RP5_2 = RP5.quotient(RP2) + sage: RP5_2.subcomplex() Simplicial set with 3 non-degenerate simplices - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: K = B.n_skeleton(3) # optional - sage.groups - sage: Q = B.quotient(K) # optional - sage.graphs sage.groups - sage: Q.subcomplex() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: K = B.n_skeleton(3) + sage: Q = B.quotient(K) + sage: Q.subcomplex() Simplicial set with 4 non-degenerate simplices """ return self._maps[0].domain() @@ -1781,15 +1798,16 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: K = B.n_skeleton(3) # optional - sage.groups - sage: Q = B.quotient(K) # optional - sage.graphs sage.groups - sage: Q.n_skeleton(6) # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: K = B.n_skeleton(3) + sage: Q = B.quotient(K) + sage: Q.n_skeleton(6) Quotient: (Simplicial set with 7 non-degenerate simplices/Simplicial set with 4 non-degenerate simplices) - sage: Q.n_skeleton(6).homology() # optional - sage.graphs sage.groups sage.modules + sage: Q.n_skeleton(6).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: C2, 6: 0} """ if self.is_finite(): @@ -1817,7 +1835,7 @@ def _repr_(self): EXAMPLES:: sage: T = simplicial_sets.Torus() - sage: T.quotient(T.n_skeleton(1)) # optional - sage.graphs + sage: T.quotient(T.n_skeleton(1)) Quotient: (Torus/Simplicial set with 4 non-degenerate simplices) """ return 'Quotient: ({}/{})'.format(self.ambient(), self.subcomplex()) @@ -1828,10 +1846,11 @@ def _latex_(self): EXAMPLES:: - sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) # optional - sage.groups - sage: RP3 = RPoo.n_skeleton(3) # optional - sage.groups - sage: RP3.rename_latex('RP^{3}') # optional - sage.groups - sage: latex(RPoo.quotient(RP3)) # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) + sage: RP3 = RPoo.n_skeleton(3) + sage: RP3.rename_latex('RP^{3}') + sage: latex(RPoo.quotient(RP3)) RP^{\infty} / RP^{3} """ return '{} / {}'.format(latex(self.ambient()), latex(self.subcomplex())) @@ -1853,11 +1872,12 @@ def __init__(self, inclusion, vertex_name='*'): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP5_2 = RP5.quotient(RP2); RP5_2 # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: RP2 = RP5.n_skeleton(2) + sage: RP5_2 = RP5.quotient(RP2); RP5_2 Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - sage: RP5_2.quotient_map() # optional - sage.graphs sage.groups + sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) @@ -1881,16 +1901,16 @@ def quotient_map(self): EXAMPLES:: sage: K = simplicial_sets.Simplex(1) - sage: S1 = K.quotient(K.n_skeleton(0)) # optional - sage.graphs - sage: q = S1.quotient_map() # optional - sage.graphs - sage: q # optional - sage.graphs + sage: S1 = K.quotient(K.n_skeleton(0)) + sage: q = S1.quotient_map() + sage: q Simplicial set morphism: From: 1-simplex To: Quotient: (1-simplex/Simplicial set with 2 non-degenerate simplices) Defn: [(0,), (1,), (0, 1)] --> [*, *, (0, 1)] - sage: q.domain() == K # optional - sage.graphs + sage: q.domain() == K True - sage: q.codomain() == S1 # optional - sage.graphs + sage: q.codomain() == S1 True """ return self.structure_map(0) @@ -1905,7 +1925,7 @@ def __classcall__(cls, factors=None): sage: from sage.topology.simplicial_set_constructions import SmashProductOfSimplicialSets_finite as Smash sage: S2 = simplicial_sets.Sphere(2) - sage: Smash([S2, S2]) == Smash((S2, S2)) # optional - sage.graphs + sage: Smash([S2, S2]) == Smash((S2, S2)) True """ if factors: @@ -1933,7 +1953,7 @@ def __init__(self, factors=None): sage: T = simplicial_sets.Torus() sage: S2 = simplicial_sets.Sphere(2) - sage: T.smash_product(S2).homology() == T.suspension(2).homology() # optional - sage.graphs sage.modules + sage: T.smash_product(S2).homology() == T.suspension(2).homology() # needs sage.modules True """ if any(not space.is_pointed() for space in factors): @@ -1949,9 +1969,9 @@ def _repr_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups - sage: S1 = simplicial_sets.Sphere(1) # optional - sage.groups - sage: S1.smash_product(RP4, S1) # optional - sage.graphs sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups + sage: S1 = simplicial_sets.Sphere(1) + sage: S1.smash_product(RP4, S1) # needs sage.groups Smash product: (S^1 ^ RP^4 ^ S^1) """ s = 'Smash product: (' @@ -1965,9 +1985,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups - sage: S1 = simplicial_sets.Sphere(1) # optional - sage.groups - sage: latex(S1.smash_product(RP4, S1)) # optional - sage.graphs sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups + sage: S1 = simplicial_sets.Sphere(1) + sage: latex(S1.smash_product(RP4, S1)) # needs sage.groups S^{1} \wedge RP^{4} \wedge S^{1} """ return ' \\wedge '.join(latex(X) for X in self._factors) @@ -1981,7 +2001,7 @@ def __classcall__(cls, factors=None): sage: from sage.topology.simplicial_set_constructions import WedgeOfSimplicialSets sage: S2 = simplicial_sets.Sphere(2) - sage: WedgeOfSimplicialSets([S2, S2]) == WedgeOfSimplicialSets((S2, S2)) # optional - sage.graphs + sage: WedgeOfSimplicialSets([S2, S2]) == WedgeOfSimplicialSets((S2, S2)) True """ if factors: @@ -2011,27 +2031,27 @@ def __init__(self, factors=None): sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) sage: K = simplicial_sets.KleinBottle() - sage: W = CP2.wedge(K) # optional - sage.graphs - sage: W.homology() # optional - sage.graphs sage.modules + sage: W = CP2.wedge(K) + sage: W.homology() # needs sage.modules {0: 0, 1: Z x C2, 2: Z, 3: 0, 4: Z} - sage: W.inclusion_map(1) # optional - sage.graphs + sage: W.inclusion_map(1) Simplicial set morphism: From: Klein bottle To: Wedge: (CP^2 v Klein bottle) Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [*, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] - sage: W.projection_map(0).domain() # optional - sage.graphs + sage: W.projection_map(0).domain() Wedge: (CP^2 v Klein bottle) - sage: W.projection_map(0).codomain() # copy of CP^2 # optional - sage.graphs + sage: W.projection_map(0).codomain() # copy of CP^2 Quotient: (Wedge: (CP^2 v Klein bottle)/Simplicial set with 6 non-degenerate simplices) - sage: W.projection_map(0).codomain().homology() # optional - sage.graphs sage.modules + sage: W.projection_map(0).codomain().homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: 0, 4: Z} An error occurs if any of the factors is not pointed:: - sage: CP2.wedge(simplicial_sets.Simplex(1)) # optional - sage.graphs + sage: CP2.wedge(simplicial_sets.Simplex(1)) Traceback (most recent call last): ... ValueError: the simplicial sets must be pointed @@ -2057,7 +2077,7 @@ def _repr_(self): EXAMPLES:: sage: K = simplicial_sets.KleinBottle() - sage: K.wedge(K, K) # optional - sage.graphs + sage: K.wedge(K, K) Wedge: (Klein bottle v Klein bottle v Klein bottle) """ s = 'Wedge: (' @@ -2071,9 +2091,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups - sage: S1 = simplicial_sets.Sphere(1) # optional - sage.groups - sage: latex(S1.wedge(RP4, S1)) # optional - sage.graphs sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups + sage: S1 = simplicial_sets.Sphere(1) + sage: latex(S1.wedge(RP4, S1)) # needs sage.groups S^{1} \vee RP^{4} \vee S^{1} """ return ' \\vee '.join(latex(X) for X in self._factors) @@ -2099,7 +2119,7 @@ def __init__(self, factors=None): sage: from sage.topology.simplicial_set_constructions import WedgeOfSimplicialSets_finite sage: K = simplicial_sets.Simplex(3) - sage: WedgeOfSimplicialSets_finite((K,K)) # optional - sage.graphs + sage: WedgeOfSimplicialSets_finite((K,K)) Traceback (most recent call last): ... ValueError: the simplicial sets must be pointed @@ -2123,15 +2143,15 @@ def inclusion_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: S2 = simplicial_sets.Sphere(2) - sage: W = S1.wedge(S2, S1) # optional - sage.graphs - sage: W.inclusion_map(1) # optional - sage.graphs + sage: W = S1.wedge(S2, S1) + sage: W.inclusion_map(1) Simplicial set morphism: From: S^2 To: Wedge: (S^1 v S^2 v S^1) Defn: [v_0, sigma_2] --> [*, sigma_2] - sage: W.inclusion_map(0).domain() # optional - sage.graphs + sage: W.inclusion_map(0).domain() S^1 - sage: W.inclusion_map(2).domain() # optional - sage.graphs + sage: W.inclusion_map(2).domain() S^1 """ return self.structure_map(i) @@ -2144,16 +2164,16 @@ def projection_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: S2 = simplicial_sets.Sphere(2) - sage: W = S1.wedge(S2, S1) # optional - sage.graphs - sage: W.projection_map(1) # optional - sage.graphs + sage: W = S1.wedge(S2, S1) + sage: W.projection_map(1) Simplicial set morphism: From: Wedge: (S^1 v S^2 v S^1) To: Quotient: (Wedge: (S^1 v S^2 v S^1)/Simplicial set with 3 non-degenerate simplices) Defn: [*, sigma_1, sigma_1, sigma_2] --> [*, s_0 *, s_0 *, sigma_2] - sage: W.projection_map(1).image().homology(1) # optional - sage.graphs sage.modules + sage: W.projection_map(1).image().homology(1) # needs sage.modules 0 - sage: W.projection_map(1).image().homology(2) # optional - sage.graphs sage.modules + sage: W.projection_map(1).image().homology(2) # needs sage.modules Z """ m = len(self._factors) @@ -2202,11 +2222,11 @@ def __init__(self, factors=None): sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) sage: K = simplicial_sets.KleinBottle() - sage: W = CP2.disjoint_union(K) # optional - sage.graphs - sage: W.homology() # optional - sage.graphs sage.modules + sage: W = CP2.disjoint_union(K) + sage: W.homology() # needs sage.modules {0: Z, 1: Z x C2, 2: Z, 3: 0, 4: Z} - sage: W.inclusion_map(1) # optional - sage.graphs + sage: W.inclusion_map(1) Simplicial set morphism: From: Klein bottle To: Disjoint union: (CP^2 u Klein bottle) @@ -2235,11 +2255,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: T = simplicial_sets.Torus() # optional - sage.groups - sage: X = B.disjoint_union(T) # optional - sage.groups - sage: X.n_skeleton(3).homology() # optional - sage.groups sage.modules + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: T = simplicial_sets.Torus() + sage: X = B.disjoint_union(T) + sage: X.n_skeleton(3).homology() # needs sage.modules {0: Z, 1: Z x Z x C2, 2: Z, 3: Z} """ if self.is_finite(): @@ -2265,8 +2286,8 @@ def _repr_(self): EXAMPLES:: sage: T = simplicial_sets.Torus() - sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # optional - sage.groups - sage: T.disjoint_union(T, RP3) # optional - sage.groups + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # needs sage.groups + sage: T.disjoint_union(T, RP3) # needs sage.groups Disjoint union: (Torus u Torus u RP^3) """ s = 'Disjoint union: (' @@ -2280,9 +2301,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # optional - sage.groups + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: latex(S1.disjoint_union(RP4, S1)) # optional - sage.graphs sage.groups + sage: latex(S1.disjoint_union(RP4, S1)) # needs sage.groups S^{1} \amalg RP^{4} \amalg S^{1} """ return ' \\amalg '.join(latex(X) for X in self._factors) @@ -2311,9 +2332,9 @@ def __init__(self, factors=None): sage: from sage.topology.simplicial_set_constructions import DisjointUnionOfSimplicialSets_finite sage: from sage.topology.simplicial_set_examples import Empty sage: S = simplicial_sets.Sphere(4) - sage: DisjointUnionOfSimplicialSets_finite((S,S,S)) # optional - sage.graphs + sage: DisjointUnionOfSimplicialSets_finite((S,S,S)) Disjoint union: (S^4 u S^4 u S^4) - sage: DisjointUnionOfSimplicialSets_finite([Empty(), Empty()]) == Empty() # optional - sage.graphs + sage: DisjointUnionOfSimplicialSets_finite([Empty(), Empty()]) == Empty() True """ if not factors: @@ -2331,15 +2352,15 @@ def inclusion_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: S2 = simplicial_sets.Sphere(2) - sage: W = S1.disjoint_union(S2, S1) # optional - sage.graphs - sage: W.inclusion_map(1) # optional - sage.graphs + sage: W = S1.disjoint_union(S2, S1) + sage: W.inclusion_map(1) Simplicial set morphism: From: S^2 To: Disjoint union: (S^1 u S^2 u S^1) Defn: [v_0, sigma_2] --> [v_0, sigma_2] - sage: W.inclusion_map(0).domain() # optional - sage.graphs + sage: W.inclusion_map(0).domain() S^1 - sage: W.inclusion_map(2).domain() # optional - sage.graphs + sage: W.inclusion_map(2).domain() S^1 """ return self.structure_map(i) @@ -2397,11 +2418,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: X = B.disjoint_union(B) # optional - sage.graphs sage.groups - sage: CX = B.cone() # optional - sage.graphs sage.groups - sage: CX.n_skeleton(3).homology() # optional - sage.graphs sage.groups sage.modules + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: X = B.disjoint_union(B) + sage: CX = B.cone() + sage: CX.n_skeleton(3).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ if self.is_finite(): @@ -2422,7 +2444,7 @@ def _repr_(self): EXAMPLES:: - sage: simplicial_sets.Simplex(3).cone() # optional - sage.graphs + sage: simplicial_sets.Simplex(3).cone() Cone of 3-simplex """ return 'Cone of {}'.format(self._base) @@ -2433,7 +2455,7 @@ def _latex_(self): EXAMPLES:: - sage: latex(simplicial_sets.Simplex(3).cone()) # optional - sage.graphs + sage: latex(simplicial_sets.Simplex(3).cone()) C \Delta^{3} """ return 'C {}'.format(latex(self._base)) @@ -2504,11 +2526,12 @@ def base_as_subset(self): EXAMPLES:: - sage: X = simplicial_sets.RealProjectiveSpace(4).unset_base_point() # optional - sage.groups - sage: Y = X.cone() # optional - sage.graphs sage.groups - sage: Y.base_as_subset() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: X = simplicial_sets.RealProjectiveSpace(4).unset_base_point() + sage: Y = X.cone() + sage: Y.base_as_subset() Simplicial set with 5 non-degenerate simplices - sage: Y.base_as_subset() == X # optional - sage.graphs sage.groups + sage: Y.base_as_subset() == X True """ X = self._base @@ -2521,8 +2544,8 @@ def map_from_base(self): EXAMPLES:: sage: X = simplicial_sets.Simplex(2).n_skeleton(1) - sage: Y = X.cone() # optional - sage.graphs - sage: Y.map_from_base() # optional - sage.graphs + sage: Y = X.cone() + sage: Y.map_from_base() Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: Cone of Simplicial set with 6 non-degenerate simplices @@ -2557,8 +2580,8 @@ def __init__(self, base): sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, v)}) sage: X = X.set_base_point(v) - sage: CX = X.cone() # indirect doctest # optional - sage.graphs - sage: CX.nondegenerate_simplices() # optional - sage.graphs + sage: CX = X.cone() # indirect doctest + sage: CX.nondegenerate_simplices() [*, e, (e,*)] """ C = ConeOfSimplicialSet(base) @@ -2589,9 +2612,9 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: B.cone().n_skeleton(3).homology() # optional - sage.graphs sage.groups sage.modules + sage: G = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: B = simplicial_sets.ClassifyingSpace(G) # needs sage.groups + sage: B.cone().n_skeleton(3).homology() # needs sage.groups sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ if self.is_finite(): @@ -2612,7 +2635,7 @@ def _repr_(self): EXAMPLES:: sage: X = simplicial_sets.Sphere(4) - sage: X.cone() # optional - sage.graphs + sage: X.cone() Reduced cone of S^4 """ return 'Reduced cone of {}'.format(self._base) @@ -2623,7 +2646,7 @@ def _latex_(self): EXAMPLES:: - sage: latex(simplicial_sets.Sphere(4).cone()) # optional - sage.graphs + sage: latex(simplicial_sets.Sphere(4).cone()) C S^{4} """ return 'C {}'.format(latex(self._base)) @@ -2655,8 +2678,8 @@ def __init__(self, base): sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, v)}) sage: X = X.set_base_point(v) - sage: CX = X.cone() # indirect doctest # optional - sage.graphs - sage: CX.nondegenerate_simplices() # optional - sage.graphs + sage: CX = X.cone() # indirect doctest + sage: CX.nondegenerate_simplices() [*, e, (e,*)] """ C = ConeOfSimplicialSet_finite(base) @@ -2684,8 +2707,8 @@ def map_from_base(self): EXAMPLES:: sage: S3 = simplicial_sets.Sphere(3) - sage: CS3 = S3.cone() # optional - sage.graphs - sage: CS3.map_from_base() # optional - sage.graphs + sage: CS3 = S3.cone() + sage: CS3.map_from_base() Simplicial set morphism: From: S^3 To: Reduced cone of S^3 @@ -2719,19 +2742,20 @@ def __init__(self, base): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: B.suspension() # optional - sage.graphs sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: B.suspension() Sigma(Classifying space of Multiplicative Abelian group isomorphic to C2) - sage: B.suspension().n_skeleton(3).homology() # optional - sage.graphs sage.groups sage.modules + sage: B.suspension().n_skeleton(3).homology() # needs sage.modules {0: 0, 1: 0, 2: C2, 3: 0} If ``X`` is finite, the suspension comes with a quotient map from the cone:: sage: S3 = simplicial_sets.Sphere(3) - sage: S4 = S3.suspension() # optional - sage.graphs - sage: S4.quotient_map() # optional - sage.graphs + sage: S4 = S3.suspension() + sage: S4.quotient_map() Simplicial set morphism: From: Reduced cone of S^3 To: Sigma(S^3) @@ -2739,11 +2763,11 @@ def __init__(self, base): TESTS:: - sage: S3.suspension() == S3.suspension() # optional - sage.graphs + sage: S3.suspension() == S3.suspension() True - sage: S3.suspension() == simplicial_sets.Sphere(3).suspension() # optional - sage.graphs + sage: S3.suspension() == simplicial_sets.Sphere(3).suspension() False - sage: B.suspension() == B.suspension() # optional - sage.graphs sage.groups + sage: B.suspension() == B.suspension() # needs sage.groups True """ Cat = SimplicialSets() @@ -2776,10 +2800,11 @@ def n_skeleton(self, n): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: SigmaB = B.suspension() # optional - sage.graphs sage.groups - sage: SigmaB.n_skeleton(4).homology(base_ring=GF(2)) # optional - sage.graphs sage.groups sage.modules sage.rings.finite_rings + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: SigmaB = B.suspension() + sage: SigmaB.n_skeleton(4).homology(base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2, @@ -2812,10 +2837,10 @@ def __repr_or_latex__(self, output_type=None): EXAMPLES:: sage: T = simplicial_sets.Torus() - sage: K = T.suspension(10) # optional - sage.graphs - sage: K.__repr_or_latex__() # optional - sage.graphs + sage: K = T.suspension(10) + sage: K.__repr_or_latex__() 'Sigma^10(Torus)' - sage: K.__repr_or_latex__('latex') # optional - sage.graphs + sage: K.__repr_or_latex__('latex') '\\Sigma^{10}(S^{1} \\times S^{1})' """ latex_output = (output_type == 'latex') @@ -2853,12 +2878,12 @@ def _repr_(self): EXAMPLES:: sage: S2 = simplicial_sets.Sphere(2) - sage: S2.suspension(3) # optional - sage.graphs + sage: S2.suspension(3) Sigma^3(S^2) sage: K = simplicial_sets.Simplex(2) - sage: K.suspension(3) # optional - sage.graphs + sage: K.suspension(3) S^3(2-simplex) - sage: K.suspension() # optional - sage.graphs + sage: K.suspension() S(2-simplex) """ return self.__repr_or_latex__() @@ -2873,12 +2898,12 @@ def _latex_(self): EXAMPLES:: sage: S2 = simplicial_sets.Sphere(2) - sage: latex(S2.suspension(3)) # optional - sage.graphs + sage: latex(S2.suspension(3)) \Sigma^{3}(S^{2}) sage: K = simplicial_sets.Simplex(2) - sage: latex(K.suspension(3)) # optional - sage.graphs + sage: latex(K.suspension(3)) S^{3}(\Delta^{2}) - sage: latex(K.suspension()) # optional - sage.graphs + sage: latex(K.suspension()) S(\Delta^{2}) """ return self.__repr_or_latex__('latex') @@ -2902,10 +2927,10 @@ def __init__(self, base): EXAMPLES:: sage: X = simplicial_sets.Sphere(3) - sage: X.suspension(2) # optional - sage.graphs + sage: X.suspension(2) Sigma^2(S^3) sage: Y = X.unset_base_point() - sage: Y.suspension(2) # optional - sage.graphs + sage: Y.suspension(2) S^2(Simplicial set with 2 non-degenerate simplices) """ self._base = base diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index b4f59901505..2bb46ac1f5a 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Examples of simplicial sets. @@ -107,11 +107,12 @@ def __eq__(self, other): EXAMPLES:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: C3.nerve() == C3.nerve() # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: C3.nerve() == C3.nerve() False - sage: BC3 = C3.nerve() # optional - sage.groups - sage: BC3 == BC3 # optional - sage.groups + sage: BC3 = C3.nerve() + sage: BC3 == BC3 True """ return (isinstance(other, Nerve) @@ -124,11 +125,12 @@ def __ne__(self, other): EXAMPLES:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) # optional - sage.groups - sage: G3 = groups.permutation.Cyclic(3) # optional - sage.groups - sage: C3.nerve() != G3.nerve() # optional - sage.groups + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: G3 = groups.permutation.Cyclic(3) + sage: C3.nerve() != G3.nerve() True - sage: C3.nerve() != C3.nerve() # optional - sage.groups + sage: C3.nerve() != C3.nerve() True """ return not self == other @@ -140,17 +142,18 @@ def __hash__(self): EXAMPLES:: - sage: G3 = groups.permutation.Cyclic(3) # optional - sage.groups - sage: hash(G3.nerve()) # random # optional - sage.groups + sage: G3 = groups.permutation.Cyclic(3) # needs sage.groups + sage: hash(G3.nerve()) # random # needs sage.groups 17 Different instances yield different base points, hence different hashes:: - sage: X = G3.nerve() # optional - sage.groups - sage: Y = G3.nerve() # optional - sage.groups - sage: X.base_point() != Y.base_point() # optional - sage.groups + sage: # needs sage.groups + sage: X = G3.nerve() + sage: Y = G3.nerve() + sage: X.base_point() != Y.base_point() True - sage: hash(X) != hash(Y) # optional - sage.groups + sage: hash(X) != hash(Y) True """ return hash(self._monoid) ^ hash(self.base_point()) @@ -168,13 +171,14 @@ def n_skeleton(self, n): EXAMPLES:: - sage: K4 = groups.misc.MultiplicativeAbelian([2,2]) # optional - sage.groups - sage: BK4 = simplicial_sets.ClassifyingSpace(K4) # optional - sage.groups - sage: BK4.n_skeleton(3) # optional - sage.groups + sage: # needs sage.groups + sage: K4 = groups.misc.MultiplicativeAbelian([2,2]) + sage: BK4 = simplicial_sets.ClassifyingSpace(K4) + sage: BK4.n_skeleton(3) Simplicial set with 40 non-degenerate simplices - sage: BK4.n_cells(1) == BK4.n_skeleton(3).n_cells(1) # optional - sage.groups + sage: BK4.n_cells(1) == BK4.n_skeleton(3).n_cells(1) True - sage: BK4.n_cells(3) == BK4.n_skeleton(1).n_cells(3) # optional - sage.groups + sage: BK4.n_cells(3) == BK4.n_skeleton(1).n_cells(3) False """ from .simplicial_set_constructions import SubSimplicialSet @@ -313,16 +317,17 @@ def ClassifyingSpace(group): EXAMPLES:: - sage: C2 = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: BC2 = simplicial_sets.ClassifyingSpace(C2) # optional - sage.groups - sage: H = BC2.homology(range(9), base_ring=GF(2)) # optional - sage.groups sage.modules sage.rings.finite_rings - sage: [H[i].dimension() for i in range(9)] # optional - sage.groups sage.modules sage.rings.finite_rings + sage: # needs sage.groups + sage: C2 = groups.misc.MultiplicativeAbelian([2]) + sage: BC2 = simplicial_sets.ClassifyingSpace(C2) + sage: H = BC2.homology(range(9), base_ring=GF(2)) # needs sage.modules + sage: [H[i].dimension() for i in range(9)] # needs sage.modules [0, 1, 1, 1, 1, 1, 1, 1, 1] - sage: Klein4 = groups.misc.MultiplicativeAbelian([2, 2]) # optional - sage.groups - sage: BK = simplicial_sets.ClassifyingSpace(Klein4); BK # optional - sage.groups + sage: Klein4 = groups.misc.MultiplicativeAbelian([2, 2]) # needs sage.groups + sage: BK = simplicial_sets.ClassifyingSpace(Klein4); BK # needs sage.groups Classifying space of Multiplicative Abelian group isomorphic to C2 x C2 - sage: BK.homology(range(5), base_ring=GF(2)) # long time (1 second) # optional - sage.groups sage.modules sage.rings.finite_rings + sage: BK.homology(range(5), base_ring=GF(2)) # long time (1 second) # needs sage.groups sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 2 over Finite Field of size 2, 2: Vector space of dimension 3 over Finite Field of size 2, @@ -344,18 +349,19 @@ def RealProjectiveSpace(n): EXAMPLES:: - sage: simplicial_sets.RealProjectiveSpace(7) # optional - sage.groups + sage: # needs sage.groups + sage: simplicial_sets.RealProjectiveSpace(7) RP^7 - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP5.homology() # optional - sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) + sage: RP5.homology() {0: 0, 1: C2, 2: 0, 3: C2, 4: 0, 5: Z} - sage: RP5 # optional - sage.groups + sage: RP5 RP^5 - sage: latex(RP5) # optional - sage.groups + sage: latex(RP5) RP^{5} - sage: BC2 = simplicial_sets.RealProjectiveSpace(Infinity) # optional - sage.groups - sage: latex(BC2) # optional - sage.groups + sage: BC2 = simplicial_sets.RealProjectiveSpace(Infinity) # needs sage.groups + sage: latex(BC2) # needs sage.groups RP^{\infty} """ if n == Infinity: @@ -383,7 +389,7 @@ def KleinBottle(): sage: K = simplicial_sets.KleinBottle() sage: K.f_vector() [1, 3, 2] - sage: K.homology(reduced=False) # optional - sage.modules + sage: K.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x C2, 2: 0} sage: K Klein bottle @@ -408,7 +414,7 @@ def Torus(): sage: T = simplicial_sets.Torus() sage: T.f_vector() [1, 3, 2] - sage: T.homology(reduced=False) # optional - sage.modules + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} """ S1 = Sphere(1) @@ -532,25 +538,25 @@ def ComplexProjectiveSpace(n): EXAMPLES:: - sage: simplicial_sets.ComplexProjectiveSpace(2).homology(reduced=False) + sage: simplicial_sets.ComplexProjectiveSpace(2).homology(reduced=False) # needs sage.modules {0: Z, 1: 0, 2: Z, 3: 0, 4: Z} - sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3) # optional - pyparsing - sage: CP3 # optional - pyparsing + sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3); CP3 # needs pyparsing CP^3 - sage: latex(CP3) # optional - pyparsing + sage: latex(CP3) # needs pyparsing CP^{3} - sage: CP3.f_vector() # optional - pyparsing + sage: CP3.f_vector() # needs pyparsing [1, 0, 3, 10, 25, 30, 15] - sage: K = CP3.suspension() # long time (1 second) # optional - pyparsing - sage: R = K.cohomology_ring(GF(2)) # long time # optional - pyparsing - sage: R.gens() # long time # optional - pyparsing + sage: # long time, needs pyparsing sage.modules + sage: K = CP3.suspension() # long time (1 second) + sage: R = K.cohomology_ring(GF(2)) + sage: R.gens() (h^{0,0}, h^{3,0}, h^{5,0}, h^{7,0}) - sage: x = R.gens()[1] # long time # optional - pyparsing - sage: x.Sq(2) # long time # optional - pyparsing + sage: x = R.gens()[1] + sage: x.Sq(2) h^{5,0} - sage: simplicial_sets.ComplexProjectiveSpace(4).f_vector() # optional - pyparsing + sage: simplicial_sets.ComplexProjectiveSpace(4).f_vector() # needs pyparsing [1, 0, 4, 22, 97, 255, 390, 315, 105] sage: simplicial_sets.ComplexProjectiveSpace(5) @@ -644,8 +650,8 @@ def simplicial_data_from_kenzo_output(filename): sage: from sage.topology.simplicial_set_examples import simplicial_data_from_kenzo_output sage: from sage.topology.simplicial_set import SimplicialSet sage: sphere = os.path.join(SAGE_ENV['SAGE_EXTCODE'], 'kenzo', 'S4.txt') - sage: S4 = SimplicialSet(simplicial_data_from_kenzo_output(sphere)) # optional - pyparsing - sage: S4.homology(reduced=False) # optional - pyparsing + sage: S4 = SimplicialSet(simplicial_data_from_kenzo_output(sphere)) # needs pyparsing + sage: S4.homology(reduced=False) # needs pyparsing {0: Z, 1: 0, 2: 0, 3: 0, 4: Z} """ from pyparsing import OneOrMore, nestedExpr @@ -732,14 +738,14 @@ def HopfMap(): Using the Hopf map to attach a cell:: - sage: X = g.mapping_cone() # optional - sage.graphs - sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) # optional - sage.graphs - sage: X.homology() == CP2.homology() # optional - sage.graphs + sage: X = g.mapping_cone() + sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) + sage: X.homology() == CP2.homology() # needs sage.modules True - sage: X.f_vector() # optional - sage.graphs + sage: X.f_vector() [1, 0, 5, 9, 6] - sage: CP2.f_vector() # optional - sage.graphs + sage: CP2.f_vector() [1, 0, 2, 3, 3] """ # The 2-sphere and its simplices. @@ -811,17 +817,18 @@ def PresentationComplex(G): EXAMPLES:: - sage: G = SymmetricGroup(2).as_finitely_presented_group(); G # optional - sage.groups + sage: # needs sage.groups + sage: G = SymmetricGroup(2).as_finitely_presented_group(); G Finitely presented group < a | a^2 > - sage: S = simplicial_sets.PresentationComplex(G); S # optional - sage.groups + sage: S = simplicial_sets.PresentationComplex(G); S Simplicial set with 5 non-degenerate simplices - sage: S.face_data() # optional - sage.groups + sage: S.face_data() {Delta^0: None, a: (Delta^0, Delta^0), a^-1: (Delta^0, Delta^0), Ta: (a, s_0 Delta^0, a^-1), a^2: (a, s_0 Delta^0, a)} - sage: S.fundamental_group() # optional - sage.groups + sage: S.fundamental_group() Finitely presented group < e0 | e0^2 > """ O = AbstractSimplex(0) diff --git a/src/sage/topology/simplicial_set_morphism.py b/src/sage/topology/simplicial_set_morphism.py index 133c3b4f62e..df5d004b3e1 100644 --- a/src/sage/topology/simplicial_set_morphism.py +++ b/src/sage/topology/simplicial_set_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Morphisms and homsets for simplicial sets @@ -35,12 +36,14 @@ from sage.categories.homset import Hom, Homset from sage.categories.morphism import Morphism from sage.categories.simplicial_sets import SimplicialSets -from sage.matrix.constructor import matrix, zero_matrix from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ from .simplicial_set import SimplicialSet_arbitrary +lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix']) + class SimplicialSetHomset(Homset): r""" @@ -102,8 +105,8 @@ def diagonal_morphism(self): EXAMPLES:: - sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # optional - sage.groups - sage: Hom(RP2, RP2.product(RP2)).diagonal_morphism() # optional - sage.groups + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: Hom(RP2, RP2.product(RP2)).diagonal_morphism() # needs sage.groups Simplicial set morphism: From: RP^2 To: RP^2 x RP^2 @@ -269,7 +272,7 @@ def __iter__(self): From: S^1 To: Torus Defn: Constant map at (v_0, v_0)] - sage: [f.induced_homology_morphism().to_matrix() for f in H] + sage: [f.induced_homology_morphism().to_matrix() for f in H] # needs sage.modules [ [ 1| 0] [1|0] [1|0] [1|0] [--+--] [-+-] [-+-] [-+-] @@ -620,9 +623,9 @@ def __call__(self, x): sage: one(e) == e True - sage: B = AbelianGroup([2]).nerve() # optional - sage.groups - sage: c = B.constant_map() # optional - sage.groups - sage: c(B.n_cells(2)[0]) # optional - sage.groups + sage: B = AbelianGroup([2]).nerve() # needs sage.groups + sage: c = B.constant_map() # needs sage.groups + sage: c(B.n_cells(2)[0]) # needs sage.groups s_1 s_0 * """ if x not in self.domain(): @@ -667,7 +670,7 @@ def _composition_(self, right, homset): Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)] sage: (g*f).image() Simplicial set with 2 non-degenerate simplices - sage: f.image().homology() # optional - sage.modules + sage: f.image().homology() # needs sage.modules {0: 0, 1: Z} """ if self.is_identity(): @@ -697,14 +700,15 @@ def image(self): Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)] sage: f.image() Simplicial set with 2 non-degenerate simplices - sage: f.image().homology() # optional - sage.modules + sage: f.image().homology() # needs sage.modules {0: 0, 1: Z} - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: B.constant_map().image() # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: B.constant_map().image() Point - sage: Hom(B,B).identity().image() == B # optional - sage.groups + sage: Hom(B,B).identity().image() == B True """ if self._is_identity: @@ -744,20 +748,21 @@ def is_identity(self): True sage: (f*g).is_identity() False - sage: (f*g).induced_homology_morphism().to_matrix(1) + sage: (f*g).induced_homology_morphism().to_matrix(1) # needs sage.modules [0] - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP5.n_skeleton(2).inclusion_map().is_identity() # optional - sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP5.n_skeleton(2).inclusion_map().is_identity() # needs sage.groups False - sage: RP5.n_skeleton(5).inclusion_map().is_identity() # optional - sage.groups + sage: RP5.n_skeleton(5).inclusion_map().is_identity() # needs sage.groups True - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: Hom(B,B).identity().is_identity() # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: Hom(B,B).identity().is_identity() True - sage: Hom(B,B).constant_map().is_identity() # optional - sage.groups + sage: Hom(B,B).constant_map().is_identity() False """ ans = (self._is_identity or @@ -773,18 +778,18 @@ def is_surjective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP2.inclusion_map().is_surjective() # optional - sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_surjective() # needs sage.groups False - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.groups - sage: RP5_2.quotient_map().is_surjective() # optional - sage.groups + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_surjective() # needs sage.groups True - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # optional - sage.groups - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # optional - sage.groups - sage: f.is_surjective() # optional - sage.groups + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_surjective() # needs sage.groups True """ return self._is_identity or self.image() == self.codomain() @@ -795,18 +800,18 @@ def is_injective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP2.inclusion_map().is_injective() # optional - sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_injective() # needs sage.groups True - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.groups - sage: RP5_2.quotient_map().is_injective() # optional - sage.groups + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_injective() # needs sage.groups False - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # optional - sage.groups - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # optional - sage.groups - sage: f.is_injective() # optional - sage.groups + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_injective() # needs sage.groups True """ if self._is_identity: @@ -825,18 +830,18 @@ def is_bijective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # optional - sage.groups - sage: RP2 = RP5.n_skeleton(2) # optional - sage.groups - sage: RP2.inclusion_map().is_bijective() # optional - sage.groups + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_bijective() # needs sage.groups False - sage: RP5_2 = RP5.quotient(RP2) # optional - sage.groups - sage: RP5_2.quotient_map().is_bijective() # optional - sage.groups + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_bijective() # needs sage.groups False - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # optional - sage.groups - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # optional - sage.groups - sage: f.is_bijective() # optional - sage.groups + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_bijective() # needs sage.groups True """ return self.is_injective() and self.is_surjective() @@ -918,7 +923,7 @@ def pushout(self, *others): sage: K = simplicial_sets.KleinBottle() sage: init_T = T._map_from_empty_set() sage: init_K = K._map_from_empty_set() - sage: D = init_T.pushout(init_K); D # the disjoint union as a pushout # optional - sage.graphs + sage: D = init_T.pushout(init_K); D # the disjoint union as a pushout Pushout of maps: Simplicial set morphism: From: Empty simplicial set @@ -1058,7 +1063,7 @@ def coequalizer(self, other): sage: f = K.inclusion_map() sage: v,w = K.n_cells(0) sage: g = Hom(K,L)({v:pt, w:pt, e:pt.apply_degeneracies(0)}) - sage: P = f.coequalizer(g); P # optional - sage.graphs + sage: P = f.coequalizer(g); P Pushout of maps: Simplicial set morphism: From: Disjoint union: (Simplicial set with 3 non-degenerate simplices u 2-simplex) @@ -1102,13 +1107,14 @@ def mapping_cone(self): Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: S^1 - Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] --> [v_0, v_0, v_0, sigma_1, s_0 v_0, sigma_1] - sage: h.induced_homology_morphism().to_matrix() + Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] + --> [v_0, v_0, v_0, sigma_1, s_0 v_0, sigma_1] + sage: h.induced_homology_morphism().to_matrix() # needs sage.modules [1|0] [-+-] [0|2] - sage: X = h.mapping_cone() # optional - sage.graphs - sage: X.homology() == simplicial_sets.RealProjectiveSpace(2).homology() # optional - sage.graphs sage.modules + sage: X = h.mapping_cone() + sage: X.homology() == simplicial_sets.RealProjectiveSpace(2).homology() # needs sage.groups sage.modules True """ dom = self.domain() @@ -1155,10 +1161,10 @@ def coproduct(self, *others): sage: S1 = simplicial_sets.Sphere(1) sage: f = Hom(S1,S1).identity() - sage: f.coproduct(f).is_bijective() # optional - sage.graphs + sage: f.coproduct(f).is_bijective() True sage: g = S1.constant_map(S1) - sage: g.coproduct(g).is_bijective() # optional - sage.graphs + sage: g.coproduct(g).is_bijective() False """ codomain = self.codomain().coproduct(*[g.codomain() for g in others]) @@ -1178,9 +1184,9 @@ def suspension(self, n=1): EXAMPLES:: sage: eta = simplicial_sets.HopfMap() - sage: mc_susp_eta = eta.suspension().mapping_cone() # optional - sage.graphs - sage: susp_mc_eta = eta.mapping_cone().suspension() # optional - sage.graphs - sage: mc_susp_eta.homology() == susp_mc_eta.homology() # optional - sage.graphs sage.modules + sage: mc_susp_eta = eta.suspension().mapping_cone() + sage: susp_mc_eta = eta.mapping_cone().suspension() + sage: mc_susp_eta.homology() == susp_mc_eta.homology() # needs sage.modules True This uses reduced suspensions if the original morphism is @@ -1190,19 +1196,19 @@ def suspension(self, n=1): sage: L = simplicial_sets.Simplex(1) sage: L.constant_map().is_pointed() False - sage: f = L.constant_map().suspension() # optional - sage.graphs - sage: f.is_constant() # optional - sage.graphs + sage: f = L.constant_map().suspension() + sage: f.is_constant() False sage: K = simplicial_sets.Sphere(3) sage: K.constant_map().is_pointed() True - sage: g = K.constant_map().suspension() # optional - sage.graphs - sage: g.is_constant() # optional - sage.graphs + sage: g = K.constant_map().suspension() + sage: g.is_constant() True - sage: h = K.identity().suspension() # optional - sage.graphs - sage: h.is_identity() # optional - sage.graphs + sage: h = K.identity().suspension() + sage: h.is_identity() True """ domain = self.domain() @@ -1250,14 +1256,15 @@ def n_skeleton(self, n, domain=None, codomain=None): EXAMPLES:: - sage: G = groups.misc.MultiplicativeAbelian([2]) # optional - sage.groups - sage: B = simplicial_sets.ClassifyingSpace(G) # optional - sage.groups - sage: one = Hom(B,B).identity() # optional - sage.groups - sage: one.n_skeleton(3) # optional - sage.groups + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) + sage: one = Hom(B,B).identity() + sage: one.n_skeleton(3) Simplicial set endomorphism of Simplicial set with 4 non-degenerate simplices Defn: Identity map - sage: c = Hom(B,B).constant_map() # optional - sage.groups - sage: c.n_skeleton(3) # optional - sage.groups + sage: c = Hom(B,B).constant_map() + sage: c.n_skeleton(3) Simplicial set endomorphism of Simplicial set with 4 non-degenerate simplices Defn: Constant map at 1 @@ -1308,7 +1315,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, sage: e = S1.n_cells(1)[0] sage: f = {v0: v0, e: v0.apply_degeneracies(0)} # constant map sage: g = Hom(S1, S1)(f) - sage: g.associated_chain_complex_morphism().to_matrix() + sage: g.associated_chain_complex_morphism().to_matrix() # needs sage.modules [1|0] [-+-] [0|0] @@ -1377,6 +1384,7 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): EXAMPLES:: + sage: # needs sage.modules sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') @@ -1386,13 +1394,13 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: Y = SimplicialSet({e: (v, v)}) sage: H = Hom(X, Y) sage: f = H({v: v, w: v, e: e, f: e}) - sage: g = f.induced_homology_morphism() # optional - sage.modules - sage: g.to_matrix() # optional - sage.modules + sage: g = f.induced_homology_morphism() + sage: g.to_matrix() [1|0] [-+-] [0|2] - sage: g3 = f.induced_homology_morphism(base_ring=GF(3), cohomology=True) # optional - sage.modules sage.rings.finite_rings - sage: g3.to_matrix() # optional - sage.modules sage.rings.finite_rings + sage: g3 = f.induced_homology_morphism(base_ring=GF(3), cohomology=True) + sage: g3.to_matrix() [1|0] [-+-] [0|2] diff --git a/src/sage/typeset/ascii_art.py b/src/sage/typeset/ascii_art.py index fe2fd4c419b..f2ea6a73738 100644 --- a/src/sage/typeset/ascii_art.py +++ b/src/sage/typeset/ascii_art.py @@ -26,7 +26,7 @@ n *log(x) --------- pi - sage: ascii_art(list(Partitions(6))) + sage: ascii_art(list(Partitions(6))) # needs sage.combinat sage.libs.flint [ * ] [ ** * ] [ *** ** * * ] @@ -232,21 +232,21 @@ def ascii_art(*obj, **kwds): We can specify a separator object:: sage: ident = lambda n: identity_matrix(ZZ, n) - sage: ascii_art(ident(1), ident(2), ident(3), sep=' : ') + sage: ascii_art(ident(1), ident(2), ident(3), sep=' : ') # needs sage.modules [1 0 0] [1 0] [0 1 0] [1] : [0 1] : [0 0 1] We can specify the baseline:: - sage: ascii_art(ident(2), baseline=-1) + ascii_art(ident(3)) + sage: ascii_art(ident(2), baseline=-1) + ascii_art(ident(3)) # needs sage.modules [1 0][1 0 0] [0 1][0 1 0] [0 0 1] We can determine the baseline of the separator:: - sage: ascii_art(ident(1), ident(2), ident(3), sep=' -- ', sep_baseline=-1) + sage: ascii_art(ident(1), ident(2), ident(3), sep=' -- ', sep_baseline=-1) # needs sage.modules [1 0 0] -- [1 0] -- [0 1 0] [1] [0 1] [0 0 1] @@ -255,7 +255,7 @@ def ascii_art(*obj, **kwds): an ascii art separator:: sage: sep_line = ascii_art('\n'.join(' | ' for _ in range(6)), baseline=6) - sage: ascii_art(*Partitions(6), separator=sep_line, sep_baseline=0) + sage: ascii_art(*Partitions(6), separator=sep_line, sep_baseline=0) # needs sage.combinat sage.libs.flint | | | | | | | | | | * | | | | | | | | | ** | * | | | | | | *** | | ** | * | * diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index a4de0e23964..2229455de82 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -161,10 +161,10 @@ def __format__(self, fmt): EXAMPLES:: - sage: M = matrix([[1,2],[3,4]]) - sage: format(ascii_art(M)) + sage: M = matrix([[1,2],[3,4]]) # needs sage.modules + sage: format(ascii_art(M)) # needs sage.modules '[1 2]\n[3 4]' - sage: format(unicode_art(M)) + sage: format(unicode_art(M)) # needs sage.modules '\u239b1 2\u239e\n\u239d3 4\u23a0' """ return format(self._string_type(self), fmt) diff --git a/src/sage/typeset/character_art_factory.py b/src/sage/typeset/character_art_factory.py index d83aa4da4f5..cc3855d8f10 100644 --- a/src/sage/typeset/character_art_factory.py +++ b/src/sage/typeset/character_art_factory.py @@ -84,9 +84,9 @@ def build(self, obj, baseline=None): EXAMPLES:: - sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) + sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic / | | 2 @@ -99,14 +99,14 @@ def build(self, obj, baseline=None): TESTS:: - sage: n = var('n') - sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) + sage: n = var('n') # needs sage.symbolic + sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) # needs sage.symbolic / _________ \ -\2*x + \/ 1 - 4*x - 1/ ------------------------- _________ 2*x*\/ 1 - 4*x - sage: ascii_art(list(DyckWords(3))) + sage: ascii_art(list(DyckWords(3))) # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] @@ -161,10 +161,10 @@ def build_from_magic_method(self, obj, baseline=None): EXAMPLES:: sage: from sage.typeset.ascii_art import _ascii_art_factory as factory - sage: out = factory.build_from_magic_method(identity_matrix(2)); out + sage: out = factory.build_from_magic_method(identity_matrix(2)); out # needs sage.modules [1 0] [0 1] - sage: type(out) + sage: type(out) # needs sage.modules """ magic_method = getattr(obj, self.magic_method_name) @@ -243,12 +243,12 @@ def build_container(self, content, left_border, right_border, baseline=0): TESTS:: - sage: l = ascii_art(list(DyckWords(3))) # indirect doctest - sage: l + sage: l = ascii_art(list(DyckWords(3))) # indirect doctest # needs sage.combinat + sage: l # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] - sage: l._breakpoints + sage: l._breakpoints # needs sage.combinat [9, 17, 25, 33] Check that zero-height strings are handled (:trac:`28527`):: @@ -289,7 +289,7 @@ def build_set(self, s, baseline=0): iteration over sets is non-deterministic so too is the results of this test:: - sage: ascii_art(set(DyckWords(3))) # indirect doctest random + sage: ascii_art(set(DyckWords(3))) # indirect doctest random # needs sage.combinat { /\ } { /\ /\/\ /\ / \ } { / \/\, / \, /\/\/\, /\/ \, / \ } @@ -298,7 +298,7 @@ def build_set(self, s, baseline=0): a set, but still obtain the same output formatting:: sage: from sage.typeset.ascii_art import _ascii_art_factory as factory - sage: factory.build_set(sorted(set(DyckWords(3)))) + sage: factory.build_set(sorted(set(DyckWords(3)))) # needs sage.combinat { /\ } { /\ /\ /\/\ / \ } { /\/\/\, /\/ \, / \/\, / \, / \ } @@ -315,6 +315,7 @@ def build_dict(self, d, baseline=0): TESTS:: + sage: # needs sage.combinat sage: from collections import OrderedDict sage: d = OrderedDict(enumerate(DyckWords(3))) sage: art = ascii_art(d) # indirect doctest @@ -357,18 +358,18 @@ def build_list(self, l, baseline=0): TESTS:: - sage: l = ascii_art(list(DyckWords(3))) # indirect doctest - sage: l + sage: l = ascii_art(list(DyckWords(3))) # indirect doctest # needs sage.combinat + sage: l # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] - sage: l._breakpoints + sage: l._breakpoints # needs sage.combinat [9, 17, 25, 33] The breakpoints of the object are used as breakpoints:: - sage: l = ascii_art([DyckWords(2).list(), DyckWords(2).list()]) - sage: l._breakpoints + sage: l = ascii_art([DyckWords(2).list(), DyckWords(2).list()]) # needs sage.combinat + sage: l._breakpoints # needs sage.combinat [(2, [7]), 17, (18, [7])] The parentheses only stretch as high as the content (:trac:`28527`):: @@ -399,7 +400,7 @@ def build_tuple(self, t, baseline=0): TESTS:: - sage: ascii_art(tuple(DyckWords(3))) # indirect doctest + sage: ascii_art(tuple(DyckWords(3))) # indirect doctest # needs sage.combinat ( /\ ) ( /\ /\ /\/\ / \ ) ( /\/\/\, /\/ \, / \/\, / \, / \ ) @@ -440,8 +441,8 @@ def concatenate(self, iterable, separator, empty=None, baseline=0, EXAMPLES:: - sage: i2 = identity_matrix(2) - sage: ascii_art(i2, i2, i2, sep=ascii_art(1/x)) + sage: i2 = identity_matrix(2) # needs sage.modules + sage: ascii_art(i2, i2, i2, sep=ascii_art(1/x)) # needs sage.modules sage.symbolic 1 1 [1 0]-[1 0]-[1 0] [0 1]x[0 1]x[0 1] diff --git a/src/sage/typeset/unicode_art.py b/src/sage/typeset/unicode_art.py index caed3475afe..4bbd0045c84 100644 --- a/src/sage/typeset/unicode_art.py +++ b/src/sage/typeset/unicode_art.py @@ -98,7 +98,7 @@ def unicode_art(*obj, **kwds): ⎮ x + π ⌡ sage: ident = lambda n: identity_matrix(ZZ, n) - sage: unicode_art(ident(1), ident(2), ident(3), sep=' : ') + sage: unicode_art(ident(1), ident(2), ident(3), sep=' : ') # needs sage.modules ⎛1 0 0⎞ ⎛1 0⎞ ⎜0 1 0⎟ (1) : ⎝0 1⎠ : ⎝0 0 1⎠ @@ -107,7 +107,7 @@ def unicode_art(*obj, **kwds): an unicode art separator:: sage: sep_line = unicode_art('\n'.join(' ⎟ ' for _ in range(5)), baseline=5) - sage: unicode_art(*AlternatingSignMatrices(3), + sage: unicode_art(*AlternatingSignMatrices(3), # needs sage.combinat sage.modules ....: separator=sep_line, sep_baseline=1) ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎛1 0 0⎞ ⎟ ⎛0 1 0⎞ ⎟ ⎛1 0 0⎞ ⎟ ⎛ 0 1 0⎞ ⎟ ⎛0 0 1⎞ ⎟ ⎛0 1 0⎞ ⎟ ⎛0 0 1⎞ diff --git a/src/sage/version.py b/src/sage/version.py index 4d55e0375ec..f07340c8a03 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.1.beta8' -date = '2023-07-30' -banner = 'SageMath version 10.1.beta8, Release Date: 2023-07-30' +version = '10.1.rc0' +date = '2023-08-13' +banner = 'SageMath version 10.1.rc0, Release Date: 2023-08-13'