diff --git a/.ci/write-dockerfile.sh b/.ci/write-dockerfile.sh index cfd4fb20810..973444bec72 100755 --- a/.ci/write-dockerfile.sh +++ b/.ci/write-dockerfile.sh @@ -275,11 +275,11 @@ cat <- ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ + logs_artifact: false # All platforms. This duplicates the default platform, but why not, # it makes it more robust regarding random timeouts. diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 5eb5e932da9..f46317ecda7 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -154,6 +154,7 @@ jobs: git config --global user.email "ci-sage@example.com" git config --global user.name "Build documentation workflow" unzip doc.zip + rm doc.zip PR_NUMBER="" if [[ "$GITHUB_REF" =~ refs/pull/([0-9]+)/merge ]]; then PR_NUMBER="${BASH_REMATCH[1]}" @@ -202,6 +203,10 @@ jobs: if: steps.docbuild.outcome == 'success' run: | set -ex + # Remove any existing html directory before copying a new one + if [ -d "doc/html" ]; then + rm -rf doc/html + fi # Simpler "docker cp --follow-link ... doc" does not work mkdir -p doc mkdir -p temp @@ -217,7 +222,7 @@ jobs: fi # If so, then create CHANGES.html if [[ -n "$PR_NUMBER" ]]; then - (cd doc && git commit -a -m 'new') + (cd doc && git add -A && git commit --quiet -m 'new') # Wipe out chronic diffs of new doc against old doc before creating CHANGES.html (cd doc && \ find . -name "*.html" | xargs sed -i -e '/This is documentation/ s/ built with GitHub PR .* for development/ for development/' \ @@ -229,7 +234,7 @@ jobs: # Since HEAD is at commit 'wipe-out', HEAD~1 is commit 'new' (new doc), HEAD~2 is commit 'old' (old doc) (cd doc && git diff $(git rev-parse HEAD~2) -- "*.html") > diff.txt # Restore the new doc dropping changes by "wipe out" - (cd doc && git checkout -q -f HEAD~1) + (cd doc && git checkout --quiet -f HEAD~1) .ci/create-changes-html.sh diff.txt doc # Sometimes rm -rf .git errors out because of some diehard hidden files # So we simply move it out of the doc directory diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a7d5ecc8835..96427164eae 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -85,6 +85,9 @@ on: description: 'Elapsed time (seconds) at which to kill the build' default: 20000 type: number + logs_artifact: + default: true + type: boolean # # Publishing to GitHub Packages # @@ -260,11 +263,12 @@ jobs: cp -r .tox/$TOX_ENV/* "artifacts/$LOGS_ARTIFACT_NAME" rm -rf "artifacts/$LOGS_ARTIFACT_NAME"/{bin,lib,pyvenv.cfg} if: always() - - uses: actions/upload-artifact@v4 + - name: Upload logs artifact + uses: actions/upload-artifact@v4 with: path: artifacts name: ${{ env.LOGS_ARTIFACT_NAME }} - if: always() + if: always() && inputs.logs_artifact - name: Print out logs for immediate inspection # and markup the output with GitHub Actions logging commands run: | diff --git a/.gitignore b/.gitignore index 0df6ef10d98..5fde73e92c2 100644 --- a/.gitignore +++ b/.gitignore @@ -56,10 +56,6 @@ /src/setup.cfg /src/requirements.txt -/src/Pipfile -/src/Pipfile.lock -/Pipfile -/Pipfile.lock # Various editors *~ diff --git a/.upstream.d/20-github.com-sagemath-sage-releases b/.upstream.d/20-github.com-sagemath-sage-releases index 399ee84dbd6..ed442b3039e 100644 --- a/.upstream.d/20-github.com-sagemath-sage-releases +++ b/.upstream.d/20-github.com-sagemath-sage-releases @@ -1,5 +1,5 @@ # Upstream packages as uploaded as GitHub release assets. # This file is automatically updated by the sage-update-version script. +https://github.com/sagemath/sage/releases/download/10.6/ https://github.com/sagemath/sage/releases/download/10.5/ https://github.com/sagemath/sage/releases/download/10.4/ -https://github.com/sagemath/sage/releases/download/10.3/ diff --git a/.vscode/settings.json b/.vscode/settings.json index bf6ab3e7c3a..c38aafb376d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,10 +24,90 @@ ], "python.testing.unittestEnabled": false, "cSpell.words": [ - "furo", + "adic", + "arccos", + "arccosh", + "arcsin", + "arcsinh", + "arctan", + "arctanh", + "Bejger", + "bigcup", + "cachefunc", + "charpoly", + "classmethod", + "clopen", + "codim", + "codomain", + "coframe", + "coframes", "Conda", + "cputime", + "cysignals", + "Cython", + "d'Alembertian", + "dalembertian", + "disp", + "doctest", + "doctests", + "emptyset", + "figsize", + "Florentin", + "fontsize", + "forall", + "furo", + "Gourgoulhon", + "grayskull", + "groebner", + "homeomorphic", + "homset", + "homsets", + "hypersurfaces", + "infty", + "Jaffredo", + "Katsura", + "Koeppe", + "longmapsto", + "longrightarrow", + "mapsto", + "mathbb", + "mathrm", + "Michal", + "micjung", + "Minkowski", + "Möbius", + "mpfr", + "nabla", + "Nullspace", + "padics", + "pari", + "prandom", + "Pynac", + "rightarrow", "sagemath", - "Cython" + "scalarfield", + "SEEALSO", + "setminus", + "smithform", + "subchart", + "subcharts", + "subframe", + "subframes", + "subobjects", + "subring", + "superchart", + "supercharts", + "supersets", + "sympy", + "tensorfield", + "trigsimp", + "varphi", + "vbundle", + "vecmat", + "vectorfield", + "walltime", + "zmax", + "zmin" ], "editor.formatOnType": true, "esbonio.sphinx.confDir": "" diff --git a/CITATION.cff b/CITATION.cff index c2d778402ac..b3774971e4a 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.5.rc0 +version: 10.6.beta0 doi: 10.5281/zenodo.8042260 -date-released: 2024-11-16 +date-released: 2024-12-08 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/Makefile b/Makefile index 96d1ba62e94..4bfe8e5c0e4 100644 --- a/Makefile +++ b/Makefile @@ -175,7 +175,6 @@ bootstrap-clean: rm -f src/doc/en/installation/*.txt find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -exec rm -f {} \+ for a in environment environment-optional src/environment src/environment-dev src/environment-optional; do rm -f $$a.yml $$a-3.[89].yml $$a-3.1[0-9].yml; done - rm -f src/Pipfile rm -f src/requirements.txt rm -f src/setup.cfg rm -f build/pkgs/cypari/version_requirements.txt diff --git a/Pipfile.m4 b/Pipfile.m4 deleted file mode 100644 index e7dd86744a0..00000000000 --- a/Pipfile.m4 +++ /dev/null @@ -1,40 +0,0 @@ -## Pipfile with all packages in the Sage distribution and version information locked -## FIXME: Many packages still missing. -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -pkgconfig = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pkgconfig/package-version.txt)')" -cython = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)')" -pycodestyle = "*" -ipykernel = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipykernel/package-version.txt)')" -tox = "*" -jinja2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../jinja2/package-version.txt)')" -pytest = "*" -ipywidgets = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipywidgets/package-version.txt)')" -sphinx = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../sphinx/package-version.txt)')" -rope = "*" -six = "*" -jupyter-core = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../jupyter_core/package-version.txt)')" - -[packages] -numpy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../numpy/package-version.txt)')" -cysignals = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cysignals/package-version.txt)')" -cypari2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cypari/package-version.txt)')" -gmpy2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../gmpy2/package-version.txt)')" -pexpect = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pexpect/package-version.txt)')" -ipython = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipython/package-version.txt)')" -sympy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../sympy/package-version.txt)')" -scipy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../scipy/package-version.txt)')" -pplpy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pplpy/package-version.txt)')" -matplotlib = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../matplotlib/package-version.txt)')" -cvxopt = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cvxopt/package-version.txt)')" -rpy2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../rpy2/package-version.txt)')" -networkx = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../networkx/package-version.txt)')" - -sagemath-standard = { path = "src" } - -[requires] -python_version = "3.9" diff --git a/VERSION.txt b/VERSION.txt index 539643e825a..75a4802e431 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.5.rc0, Release Date: 2024-11-16 +SageMath version 10.6.beta0, Release Date: 2024-12-08 diff --git a/bootstrap b/bootstrap index 9d19e756a38..695e3a1550c 100755 --- a/bootstrap +++ b/bootstrap @@ -227,7 +227,6 @@ save () { src/doc/en/installation/*.txt \ $(find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -print) \ environment-3.[89].yml environment-3.1[0-9].yml \ - src/Pipfile \ src/pyproject.toml \ src/requirements.txt \ src/setup.cfg \ diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index f8bbaed10be..af25b3b9917 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=87648980fa41bbd38f9bf45beb7bcdb90e12d613 -sha256=cb5129b2e60af70968a6d8de8937b0f9365a2146762bf34a09b4ad7a88c56b8b +sha1=ca942ace2e5104f3ae9e57946c8228b0bdb580c5 +sha256=99c0a76943170a85d2eb868d72dd673c6b0df529d99b808458bdb3b285dec8fe diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 91cad63eb79..036f9ad2756 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -d9c38a7c581e6ed54fbe420122b8bba488b16074 +d129e08e85a0c6530fa140dfc04c86ac0b74e05e diff --git a/build/pkgs/ecm/patches/assembler.patch b/build/pkgs/ecm/patches/assembler.patch deleted file mode 100644 index 2e3d6c94b6d..00000000000 --- a/build/pkgs/ecm/patches/assembler.patch +++ /dev/null @@ -1,67 +0,0 @@ -*** a/x86_64/Makefile.in Mon Nov 4 14:08:05 2024 ---- b/x86_64/Makefile.in Mon Nov 4 14:15:46 2024 -*************** -*** 355,361 **** - all: all-am - - .SUFFIXES: -! .SUFFIXES: .asm .lo .o .obj .s - $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ ---- 355,361 ---- - all: all-am - - .SUFFIXES: -! .SUFFIXES: .asm .lo .o .obj .sx - $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ -*************** -*** 406,418 **** - distclean-compile: - -rm -f *.tab.c - -! .s.o: - $(AM_V_CCAS)$(CCASCOMPILE) -c -o $@ $< - -! .s.obj: - $(AM_V_CCAS)$(CCASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -! .s.lo: - $(AM_V_CCAS)$(LTCCASCOMPILE) -c -o $@ $< - - mostlyclean-libtool: ---- 406,418 ---- - distclean-compile: - -rm -f *.tab.c - -! .sx.o: - $(AM_V_CCAS)$(CCASCOMPILE) -c -o $@ $< - -! .sx.obj: - $(AM_V_CCAS)$(CCASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -! .sx.lo: - $(AM_V_CCAS)$(LTCCASCOMPILE) -c -o $@ $< - - mostlyclean-libtool: -*************** -*** 706,713 **** - mulredc1_20.asm: mulredc1.m4 - $(M4) -DLENGTH=20 $< > $@ - -! .asm.s: -! $(M4) -I../ -DOPERATION_$* `test -f $< || echo '$(srcdir)/'`$< >$*.s - # Nothing here needs the C preprocessor, and including this rule causes - # "make" to build .S, then .s files which fails on case-insensitive - # filesystems ---- 706,713 ---- - mulredc1_20.asm: mulredc1.m4 - $(M4) -DLENGTH=20 $< > $@ - -! .asm.sx: -! $(M4) -I../ -DOPERATION_$* `test -f $< || echo '$(srcdir)/'`$< >$*.sx - # Nothing here needs the C preprocessor, and including this rule causes - # "make" to build .S, then .s files which fails on case-insensitive - # filesystems diff --git a/build/pkgs/libbraiding/checksums.ini b/build/pkgs/libbraiding/checksums.ini index 5a956e027bf..0795b89fdf6 100644 --- a/build/pkgs/libbraiding/checksums.ini +++ b/build/pkgs/libbraiding/checksums.ini @@ -1,4 +1,4 @@ tarball=libbraiding-VERSION-actually-VERSION.tar.gz -sha1=b7e13778784fe1e36e7c0cbd7a4c234a090cd1b2 -sha256=73087d1145ace719eafeda1db1c28b5fe1c981b7e784dc59f2b1d6fc4ff75f80 +sha1=8c22d5d396e2c4d2dd032172589042933b651108 +sha256=d1738c3ad64a90ca0ad968d2e3c9069b0de08abcf37fb44a151a229d88203950 upstream_url=https://github.com/miguelmarco/libbraiding/releases/download/VERSION/libbraiding-VERSION.tar.gz diff --git a/build/pkgs/libbraiding/package-version.txt b/build/pkgs/libbraiding/package-version.txt index 5625e59da88..3a3cd8cc8b0 100644 --- a/build/pkgs/libbraiding/package-version.txt +++ b/build/pkgs/libbraiding/package-version.txt @@ -1 +1 @@ -1.2 +1.3.1 diff --git a/build/pkgs/libbraiding/spkg-configure.m4 b/build/pkgs/libbraiding/spkg-configure.m4 index 8fd86aa20ea..67d80d77a64 100644 --- a/build/pkgs/libbraiding/spkg-configure.m4 +++ b/build/pkgs/libbraiding/spkg-configure.m4 @@ -1,50 +1,9 @@ SAGE_SPKG_CONFIGURE([libbraiding], [ - # Since libbraiding is a C++ library with no pkg-config file, - # the best we can do here is compile and run a test program - # linked against it. - AC_LANG_PUSH(C++) - SAVED_LIBS=$LIBS - LIBS="$LIBS -lbraiding" - AC_MSG_CHECKING([if we can link against libbraiding]) - AC_RUN_IFELSE([ - AC_LANG_PROGRAM([ - #include - #include - using namespace Braiding; - ],[ - // Mimic BraidGroup(2)([1,1]).thurston_type() in SageMath. - // thurstontype == 1 corresponds to "periodic" - if (thurstontype(2, {1,1}) == 1) { return 0; } else { return 1; } - ]) - ], - [ - AC_MSG_RESULT([yes]) + PKG_CHECK_MODULES([libbraiding], [libbraiding >= 1.3.1], [ + AC_MSG_RESULT([found libbraiding >= 1.3.1, will use installed version]) sage_spkg_install_libbraiding=no - ], - [ - AC_MSG_RESULT([no]) - sage_spkg_install_libbraiding=yes ],[ - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([ - #include - #include - using namespace Braiding; - ],[ - // Mimic BraidGroup(2)([1,1]).thurston_type() in SageMath. - // thurstontype == 1 corresponds to "periodic" - if (thurstontype(2, {1,1}) == 1) { return 0; } else { return 1; } - ]) - ], - [ - AC_MSG_RESULT([yes]) - sage_spkg_install_libbraiding=no - ], - [ - AC_MSG_RESULT([no]) - sage_spkg_install_libbraiding=yes - ]) + AC_MSG_RESULT([couldn't find libbraiding >= 1.3.1. It will be installed]) + sage_spkg_install_libbraiding=yes ]) - LIBS=$SAVED_LIBS - AC_LANG_POP ]) diff --git a/build/pkgs/python3/dependencies b/build/pkgs/python3/dependencies index c00db7fa1e0..d703ce7ab69 100644 --- a/build/pkgs/python3/dependencies +++ b/build/pkgs/python3/dependencies @@ -1,4 +1,4 @@ -zlib readline sqlite libpng bzip2 liblzma libffi openssl | xz +zlib readline sqlite libpng bzip2 liblzma libffi openssl | xz pkgconf ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index 75a00f0f83b..1528604151d 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.5rc0 +sage-conf ~= 10.6b0 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index 6e02f12a485..64078134018 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.5rc0 +sage-docbuild ~= 10.6b0 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index af4273ca5a6..e5b0998d572 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.5rc0 +sage-setup ~= 10.6b0 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index f6461b249ee..1aec16d1739 100644 --- a/build/pkgs/sage_sws2rst/version_requirements.txt +++ b/build/pkgs/sage_sws2rst/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.5rc0 +sage-sws2rst ~= 10.6b0 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index a5764ac2ff3..a01ffdf92ed 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.5rc0 +sagemath-standard ~= 10.6b0 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index 54e31199a21..637c4611451 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.5rc0 +sagemath-bliss ~= 10.6b0 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 24190dcde29..8e37771c3f9 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.5rc0 +sagemath-categories ~= 10.6b0 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index d583b886874..06dc600cfd7 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.5rc0 +sagemath-coxeter3 ~= 10.6b0 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 4c460e8258e..7e0f787af06 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.5rc0 +sagemath-environment ~= 10.6b0 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index 394ab1ab42c..3a2722024c4 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.5rc0 +sagemath-mcqd ~= 10.6b0 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index e3b1b8d80dd..3cb0d050fa5 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.5rc0 +sagemath-meataxe ~= 10.6b0 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index 84f9308c624..e8c44e2142e 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.5rc0 +sagemath-objects ~= 10.6b0 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index 124091c62c1..3df75b7c62a 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.5rc0 +sagemath-repl ~= 10.6b0 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index 57ed9f87891..2c8db8e59f7 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.5rc0 +sagemath-sirocco ~= 10.6b0 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index ea110e02460..1732fe39010 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.5rc0 +sagemath-tdlib ~= 10.6b0 diff --git a/configure.ac b/configure.ac index 1bf79ed7333..29812af6e97 100644 --- a/configure.ac +++ b/configure.ac @@ -222,7 +222,7 @@ dnl Exit autoconf with exit code 16 in this case. This will be dnl caught by the bootstrap script. m4_exit(16)]) -PKG_PROG_PKG_CONFIG([0.29], [PKG_CONFIG=false]) +PKG_PROG_PKG_CONFIG([0.29], [PKG_CONFIG=]) AC_CHECK_PROG(found_ranlib, ranlib, yes, no) if test x$found_ranlib != xyes @@ -431,7 +431,7 @@ AS_IF([test "x$enable_download_from_upstream_url" = "xyes"], [ ]) AC_SUBST([SAGE_SPKG_OPTIONS]) -AC_ARG_ENABLE([sagelib], +AC_ARG_ENABLE([sage_conf], AS_HELP_STRING([--disable-sage_conf], [disable build of the sage_conf package]), [ for pkg in sage_conf; do diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/pyproject.toml b/pyproject.toml index 47c125c4e26..9840e43b7a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,8 +90,8 @@ platforms = [ 'osx-64', 'linux-64', 'linux-aarch64', 'osx-arm64' ] -[external] # External dependencies in the format proposed by https://peps.python.org/pep-0725 +[external] build-requires = [ "virtual:compiler/c", "virtual:compiler/cpp", @@ -152,4 +152,23 @@ dependencies = [ "pkg:generic/tachyon", "pkg:generic/sagemath-polytopes-db", "pkg:generic/sagemath-elliptic-curves", + "pkg:generic/sagemath-graphs", +] + +[dependency-groups] +test = [ + "pytest", + "pytest-xdist", + "coverage", +] +docs = [ + "sphinx", + "sphinx-inline-tabs", + "furo", +] +lint = [ + "relint", + "ruff", + "pycodestyle", + "flake8-rst-docstrings", ] diff --git a/src/Pipfile.m4 b/src/Pipfile.m4 deleted file mode 100644 index feca57f7de9..00000000000 --- a/src/Pipfile.m4 +++ /dev/null @@ -1,22 +0,0 @@ -## Pipfile with all dependencies of sagelib and version information as free as possible -## (for developers to generate a dev environment) -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -## We do not list packages that are already declared as install_requires -## in setup.cfg -pycodestyle = "*" -tox = "*" -pytest = "*" -rope = "*" -six = "*" - -[packages] -## We do not list packages that are already declared as install_requires -## in setup.cfg - -[packages.e1839a8] -path = "." diff --git a/src/VERSION.txt b/src/VERSION.txt index 9228dedd0ce..bf89b51e25f 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.5.rc0 +10.6.beta0 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 9c1fb9c0309..8f940ae430b 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.5.rc0' -SAGE_RELEASE_DATE='2024-11-16' -SAGE_VERSION_BANNER='SageMath version 10.5.rc0, Release Date: 2024-11-16' +SAGE_VERSION='10.6.beta0' +SAGE_RELEASE_DATE='2024-12-08' +SAGE_VERSION_BANNER='SageMath version 10.6.beta0, Release Date: 2024-12-08' diff --git a/src/conftest.py b/src/conftest.py index 6bc7ee2e3fd..951d2fddfad 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -162,6 +162,7 @@ def pytest_addoption(parser): dest="doctest", ) + @pytest.fixture(autouse=True, scope="session") def add_imports(doctest_namespace: dict[str, Any]): """ diff --git a/src/doc/Makefile b/src/doc/Makefile index 98a3d138baf..9c03292b070 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -66,6 +66,8 @@ doc-html-other: doc-html-reference $(MAKE) $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-html--$(subst /,-,$(doc))) doc-html: doc-html-reference doc-html-other + SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") + find $${SAGE_DOC}/html -type d -path "*/jupyter_execute" -exec rm -rf {} + # Matches doc-pdf--developer, doc-pdf--reference-manifolds etc. doc-pdf--%: @@ -88,7 +90,8 @@ doc-pdf-other: doc-pdf-reference $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-pdf--$(subst /,-,$(doc))) doc-pdf: doc-pdf-reference doc-pdf-other - + SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") + find $${SAGE_DOC}/latex -type d -path "*/jupyter_execute" -exec rm -rf {} + .PHONY: all clean \ doc-src \ diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 5e15c4b2455..9b56de46ad0 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -6,7 +6,6 @@ General Conventions =================== - There are many ways to contribute to Sage, including sharing scripts and Jupyter notebooks that implement new functionality using Sage, improving to the Sage library, or to working on the many underlying @@ -1256,17 +1255,38 @@ framework. Here is a comprehensive list: Neither of this applies to files or directories which are explicitly given as command line arguments: those are always tested. -- **optional/needs:** A line tagged with ``optional - FEATURE`` - or ``needs FEATURE`` is not tested unless the ``--optional=KEYWORD`` flag - is passed to ``sage -t`` (see - :ref:`section-optional-doctest-flag`). The main applications are: +- **optional** or **needs:** A line tagged with ``optional - FEATURE`` or + ``needs FEATURE`` is tested if the feature is available in Sage. If + ``FEATURE`` starts with an exclamation point ``!``, then the condition is + negated, that is, the doctest runs only if the feature is not available. + + If the feature is included in the ``--optional=KEYWORD`` flag passed to + ``sage -t`` (see :ref:`section-optional-doctest-flag`), then the line is + tested regardless of the feature availability. + + The main applications are: - **optional packages:** When a line requires an optional package to be - installed (e.g. the ``sloane_database`` package):: + installed (e.g. the ``rubiks`` package):: + + sage: C = RubiksCube("R*L") + sage: C.solve() # optional - rubiks (a hybrid algorithm is used) + 'L R' + sage: C.solve() # optional - !rubiks (GAP is used) + 'L*R' + + - **features:** When a line requires a feature to be present:: sage: SloaneEncyclopedia[60843] # optional - sloane_database + [1, 6, 21, 107, 47176870] + + sage: SloaneEncyclopedia[60843] # optional - !sloane_database + Traceback (most recent call last): + ... + OSError: The Sloane Encyclopedia database must be installed. Use e.g. + 'SloaneEncyclopedia.install()' to download and install it. - - **internet:** For lines that require an internet connection:: + For lines that require an internet connection:: sage: oeis(60843) # optional - internet A060843: Busy Beaver problem: a(n) = maximal number of steps that an diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index bb08408777b..1ea6eebb317 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -786,13 +786,13 @@ the procedure below: class NewClass: ... - OldClass = NewClass # OldClass is deprecated. See Issue 12345. + OldClass = NewClass # OldClass is deprecated. See Issue #12345. * **Removing a class:** add a comment: .. CODE-BLOCK:: python - # OldClass is deprecated. See Issue 12345. + # OldClass is deprecated. See Issue #12345. class OldClass: diff --git a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst index 97cff1bb835..021a50f262e 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst @@ -45,3 +45,4 @@ whereas others have multiple bases. sage/rings/polynomial/polynomial_fateman sage/rings/polynomial/integer_valued_polynomials + sage/rings/polynomial/q_integer_valued_polynomials diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 45f5fbc090f..7af6ae3bf7d 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3214,6 +3214,10 @@ REFERENCES: The Electronic Journal of Combinatorics 11 (2004), #R77. http://www.combinatorics.org/Volume_11/PDF/v11i1r77.pdf +.. [HaHo2017] Nate Harman and Sam Hopkins, + *Quantum integer-valued polynomials*, + J. Alg. Comb. 2017, :doi:`10.1007/s10801-016-0717-3` + .. [Hai1989] M.D. Haiman, *On mixed insertion, symmetry, and shifted Young tableaux*. Journal of Combinatorial Theory, Series A Volume 50, Number 2 (1989), pp. 196-225. @@ -3227,7 +3231,7 @@ REFERENCES: http://www-math.mit.edu/~hajiagha/pp11.ps .. [Han1960] Haim Hanani, - On quadruple systems, + *On quadruple systems*, pages 145--157, vol. 12, Canadian Journal of Mathematics, 1960 diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 5e9fcf77db6..5eeddc3a7f6 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -132,7 +132,6 @@ This base class provides a lot more methods than a general parent:: 'integral_closure', 'is_commutative', 'is_field', - 'is_integrally_closed', 'krull_dimension', 'localization', 'ngens', diff --git a/src/doc/en/website/versions.txt b/src/doc/en/website/versions.txt index 12aed2b8cfe..6d1a9aa05ea 100644 --- a/src/doc/en/website/versions.txt +++ b/src/doc/en/website/versions.txt @@ -7,6 +7,7 @@ # The sage-update-version script adds a new line for a new stable release # when run by the Sage release manager to prepare a new release # +10.5 doc-10-5--sagemath.netlify.app 10.4 doc-10-4--sagemath.netlify.app 10.3 doc-10-3--sagemath.netlify.app 10.2 doc-10-2--sagemath.netlify.app diff --git a/src/doc/ja/tutorial/japanesesupport.py b/src/doc/ja/tutorial/japanesesupport.py index 6d954e3ddc9..f19aa9953e1 100644 --- a/src/doc/ja/tutorial/japanesesupport.py +++ b/src/doc/ja/tutorial/japanesesupport.py @@ -2,6 +2,7 @@ import re __RGX = re.compile(r'([^!-~])[\n\r\t]+([^!-~])') + def trunc_whitespace(app, doctree, docname): from docutils.nodes import Text, paragraph if not app.config.japanesesupport_trunc_whitespace: @@ -15,6 +16,7 @@ def trunc_whitespace(app, doctree, docname): #newtext = newtext.strip() node.parent.replace(node, Text(newtext)) + def setup(app): app.add_config_value('japanesesupport_trunc_whitespace', True, True) app.connect("doctree-resolved", trunc_whitespace) diff --git a/src/meson.build b/src/meson.build index 10ce96a8da2..1e528727a4f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -78,11 +78,7 @@ endif # that too to make the fallback detection with CMake work blas_order += ['cblas', 'openblas', 'OpenBLAS', 'flexiblas', 'blis', 'blas'] blas = dependency(blas_order) -gsl = dependency( - 'gsl', - version: '>=2.5', - required: true, -) +gsl = dependency('gsl', version: '>=2.5', required: true) gd = cc.find_library('gd') # Only some platforms have a standalone math library (https://mesonbuild.com/howtox.html#add-math-library-lm-portably) m = cc.find_library('m', required: false) @@ -115,8 +111,6 @@ singular = dependency('Singular') maxima = find_program('maxima', required: true) # Cannot be found via pkg-config ntl = cc.find_library('ntl') -# Cannot be found via pkg-config -meataxe = cc.find_library('meataxe', required: false, disabler: true) # Meson currently ignores include_directories for Cython modules, so we # have to add them manually. diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index fdcaeedaad8..7dadae0de4d 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -1559,7 +1559,7 @@ def homogeneous_parts(self): res[deg] = term return {i: res[i] for i in sorted(res.keys())} - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): r""" A dictionary that determines the element. @@ -1578,7 +1578,7 @@ def monomial_coefficients(self): sage: sorted(elt.dict().items()) [((0, 1, 1, 0), -5), ((1, 1, 0, 0), 1), ((1, 2, 3, 1), 7)] """ - return self.lift().monomial_coefficients() + return self.lift().monomial_coefficients(copy=copy) dict = monomial_coefficients diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 8b73482e7bf..a18e15c1df6 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -160,23 +160,24 @@ # *************************************************************************** -from sage.categories.rings import Rings - -from sage.monoids.free_monoid import FreeMonoid -from sage.monoids.free_monoid_element import FreeMonoidElement - from sage.algebras.free_algebra_element import FreeAlgebraElement - -from sage.structure.factory import UniqueFactory -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_import import lazy_import -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.integer_ring import ZZ from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.functor import Functor +from sage.categories.pushout import (ConstructionFunctor, + CompositeConstructionFunctor, + IdentityConstructionFunctor) +from sage.categories.rings import Rings from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.word import Word +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import +from sage.monoids.free_monoid import FreeMonoid +from sage.monoids.free_monoid_element import FreeMonoidElement +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.category_object import normalize_names - +from sage.structure.coerce_exceptions import CoercionException +from sage.structure.factory import UniqueFactory lazy_import('sage.algebras.letterplace.free_algebra_letterplace', 'FreeAlgebra_letterplace') @@ -199,12 +200,12 @@ class FreeAlgebraFactory(UniqueFactory): sage: FreeAlgebra(GF(5),3, 'abc') Free Algebra on 3 generators (a, b, c) over Finite Field of size 5 sage: FreeAlgebra(GF(5),1, 'z') - Free Algebra on 1 generators (z,) over Finite Field of size 5 + Free Algebra on 1 generator (z,) over Finite Field of size 5 sage: FreeAlgebra(GF(5),1, ['alpha']) - Free Algebra on 1 generators (alpha,) over Finite Field of size 5 + Free Algebra on 1 generator (alpha,) over Finite Field of size 5 sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x') Free Algebra on 2 generators (x0, x1) over - Free Algebra on 1 generators (a,) over Integer Ring + Free Algebra on 1 generator (a,) over Integer Ring Free algebras are globally unique:: @@ -264,7 +265,7 @@ class FreeAlgebraFactory(UniqueFactory): sage: s = a*b^2 * c^3; s a*b^2*c^3 sage: parent(s) - Free Algebra on 1 generators (c,) over + Free Algebra on 1 generator (c,) over Free Algebra on 2 generators (a, b) over Rational Field sage: c^3 * a * b^2 a*b^2*c^3 @@ -507,6 +508,17 @@ def __init__(self, R, n, names, degrees=None): else: self._degrees = {g: ZZ(d) for g, d in zip(self.monoid().gens(), degrees)} + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: F, R = algebras.Free(QQ,4,'x,y,z,t').construction(); F + Associative[x,y,z,t] + """ + return AssociativeFunctor(self.variable_names(), self._degrees), self.base_ring() + def one_basis(self): """ Return the index of the basis element `1`. @@ -554,16 +566,17 @@ def _repr_(self) -> str: sage: F # indirect doctest QQ<> sage: FreeAlgebra(ZZ, 1, ['a']) - Free Algebra on 1 generators (a,) over Integer Ring + Free Algebra on 1 generator (a,) over Integer Ring sage: FreeAlgebra(QQ, 2, ['x', 'y'], degrees=(2,1)) Free Algebra on 2 generators (x, y) with degrees (2, 1) over Rational Field """ + txt = "generator" if self.__ngens == 1 else "generators" if self._degrees is None: - return "Free Algebra on {} generators {} over {}".format( - self.__ngens, self.gens(), self.base_ring()) - return "Free Algebra on {} generators {} with degrees {} over {}".format( - self.__ngens, self.gens(), tuple(self._degrees.values()), self.base_ring()) + return "Free Algebra on {} {} {} over {}".format( + self.__ngens, txt, self.gens(), self.base_ring()) + return "Free Algebra on {} {} {} with degrees {} over {}".format( + self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring()) def _latex_(self) -> str: r""" @@ -634,13 +647,24 @@ def _element_constructor_(self, x): 1.00000000000000*x^2 * 1.00000000000000*y^3 sage: F(f) 1.00000000000000*x^2*y^3 + + Check for extended coercion:: + + sage: A = algebras.Free(QQ,['x','y']) + sage: B = algebras.Free(QQ,['y']) + sage: y, = B.gens() + sage: A(4+y) + 4 + y """ if isinstance(x, FreeAlgebraElement): P = x.parent() if P is self: return x - if P is not self.base_ring(): - return self.element_class(self, x) + # from another FreeAlgebra: + if x not in self.base_ring(): + D = {self.monoid()(T): cf + for T, cf in x.monomial_coefficients().items()} + return self.element_class(self, D) elif hasattr(x, 'letterplace_polynomial'): P = x.parent() if self.has_coerce_map_from(P): # letterplace versus generic @@ -678,21 +702,23 @@ def exp_to_monomial(T): return self.element_class(self, {}) return self.element_class(self, {self.one_basis(): x}) - def _coerce_map_from_(self, R): + def _coerce_map_from_(self, R) -> bool: """ Return ``True`` if there is a coercion from ``R`` into ``self`` and - ``False`` otherwise. The things that coerce into ``self`` are: + ``False`` otherwise. + + The things that coerce into ``self`` are: - This free algebra. - - Anything with a coercion into ``self.monoid()``. + - The PBW basis of ``self``. - - Free algebras in the same variables over a base with a coercion - map into ``self.base_ring()``. + - Free algebras in some subset of variables + over a base with a coercion map into ``self.base_ring()``. - The underlying monoid. - - The PBW basis of ``self``. + - Anything with a coercion into ``self.monoid()``. - Anything with a coercion into ``self.base_ring()``. @@ -706,7 +732,7 @@ def _coerce_map_from_(self, R): sage: G._coerce_map_from_(F) True sage: F._coerce_map_from_(H) - False + True sage: F._coerce_map_from_(QQ) False sage: G._coerce_map_from_(QQ) @@ -743,7 +769,7 @@ def _coerce_map_from_(self, R): # free algebras in the same variable over any base that coerces in: if isinstance(R, (FreeAlgebra_generic, FreeAlgebra_letterplace)): - if R.variable_names() == self.variable_names(): + if all(x in self.variable_names() for x in R.variable_names()): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, PBWBasisOfFreeAlgebra): return self.has_coerce_map_from(R._alg) @@ -808,7 +834,7 @@ def algebra_generators(self): return Family(self.variable_names(), lambda i: ret[i]) @cached_method - def gens(self): + def gens(self) -> tuple: """ Return the generators of ``self``. @@ -1302,7 +1328,7 @@ def _coerce_map_from_(self, R): sage: G._coerce_map_from_(F) True sage: F._coerce_map_from_(H) - False + True sage: F._coerce_map_from_(QQ) False sage: G._coerce_map_from_(QQ) @@ -1449,3 +1475,222 @@ def expand(self): x + x^2*y - 2*x*y*x + y*x^2 + y^4*x """ return self.parent().expansion(self) + + +class AssociativeFunctor(ConstructionFunctor): + """ + A constructor for free associative algebras. + + EXAMPLES:: + + sage: P = algebras.Free(ZZ, 2, 'x,y') + sage: x,y = P.gens() + sage: F = P.construction()[0]; F + Associative[x,y] + + sage: A = GF(5)['a,b'] + sage: a, b = A.gens() + sage: F(A) + Free Algebra on 2 generators (x, y) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + + sage: f = A.hom([a+b,a-b],A) + sage: F(f) + Generic endomorphism of Free Algebra on 2 generators (x, y) + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + + sage: F(f)(a * F(A)(x)) + (a+b)*x + """ + rank = 9 + + def __init__(self, vars, degs=None): + """ + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: F + Associative[x,y] + sage: F(ZZ) + Free Algebra on 2 generators (x, y) over Integer Ring + """ + Functor.__init__(self, Rings(), Rings()) + if not isinstance(vars, (list, tuple)): + raise TypeError("vars must be a list or tuple") + if degs is not None and not isinstance(degs, (list, tuple, dict)): + raise TypeError("degs must be a list, tuple or dict") + self.vars = vars + self.degs = degs + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: R = algebras.Free(ZZ, 3, 'x,y,z') + sage: F = R.construction()[0]; F + Associative[x,y,z] + sage: type(F) + + sage: F(ZZ) # indirect doctest + Free Algebra on 3 generators (x, y, z) over Integer Ring + """ + return FreeAlgebra(R, self.vars, self.degs) + + def _apply_functor_to_morphism(self, f): + """ + Apply the functor ``self`` to the ring morphism `f`. + + TESTS:: + + sage: R = algebras.Free(ZZ, 'x').construction()[0] + sage: R(ZZ.hom(GF(3))) # indirect doctest + Generic morphism: + From: Free Algebra on 1 generator (x,) over Integer Ring + To: Free Algebra on 1 generator (x,) over Finite Field of size 3 + """ + dom = self(f.domain()) + codom = self(f.codomain()) + + def action(x): + return codom._from_dict({a: f(b) + for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: F = algebras.Free(ZZ, 3, 'x,y,z').construction()[0] + sage: G = algebras.Free(QQ, 3, 'x,y,z').construction()[0] + sage: F == G + True + sage: G == loads(dumps(G)) + True + sage: G = algebras.Free(QQ, 2, 'x,y').construction()[0] + sage: F == G + False + """ + if not isinstance(other, AssociativeFunctor): + return False + return self.vars == other.vars and self.degs == other.degs + + def __mul__(self, other): + """ + If two Associative functors are given in a row, form a single Associative functor + with all of the variables. + + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: G = AssociativeFunctor(['t']) + sage: G * F + Associative[x,y,t] + """ + if isinstance(other, IdentityConstructionFunctor): + return self + if isinstance(other, AssociativeFunctor): + if set(self.vars).intersection(other.vars): + raise CoercionException("Overlapping variables (%s,%s)" % + (self.vars, other.vars)) + return AssociativeFunctor(other.vars + self.vars) + elif (isinstance(other, CompositeConstructionFunctor) and + isinstance(other.all[-1], AssociativeFunctor)): + return CompositeConstructionFunctor(other.all[:-1], + self * other.all[-1]) + else: + return CompositeConstructionFunctor(other, self) + + def merge(self, other): + """ + Merge ``self`` with another construction functor, or return ``None``. + + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: G = AssociativeFunctor(['t']) + sage: F.merge(G) + Associative[x,y,t] + sage: F.merge(F) + Associative[x,y] + + With degrees:: + + sage: F = AssociativeFunctor(['x','y'], (2,3)) + sage: G = AssociativeFunctor(['t'], (4,)) + sage: H = AssociativeFunctor(['z','y'], (5,3)) + sage: F.merge(G) + Associative[x,y,t] with degrees (2, 3, 4) + sage: F.merge(H) + Associative[x,y,z] with degrees (2, 3, 5) + + Now some actual use cases:: + + sage: R = algebras.Free(ZZ, 3, 'x,y,z') + sage: x,y,z = R.gens() + sage: 1/2 * x + 1/2*x + sage: parent(1/2 * x) + Free Algebra on 3 generators (x, y, z) over Rational Field + + sage: S = algebras.Free(QQ, 2, 'z,t') + sage: z,t = S.gens() + sage: x + t + t + x + sage: parent(x + t) + Free Algebra on 4 generators (z, t, x, y) over Rational Field + + TESTS:: + + sage: F = AssociativeFunctor(['x','y'], (2,3)) + sage: H = AssociativeFunctor(['z','y'], (5,4)) + sage: F.merge(H) + """ + if isinstance(other, AssociativeFunctor): + if self.vars == other.vars and self.degs == other.degs: + return self + + ret = list(self.vars) + self_vars = set(ret) + ret.extend(v for v in other.vars if v not in self_vars) + + # first case: no degrees + if self.degs is None and other.degs is None: + return AssociativeFunctor(tuple(ret)) + + # second case: merge the degrees + if self.degs is None: + deg = [1] * len(self.vars) + else: + deg = list(self.degs) + if other.degs is None: + o_degs = [1] * len(other.vars) + else: + o_degs = list(other.degs) + self_table = {w: d for w, d in zip(self.vars, deg)} + for v, d in zip(other.vars, o_degs): + if v not in self_vars: + deg.append(d) + elif d != self_table[v]: + # incompatible degrees + return None + return AssociativeFunctor(tuple(ret), tuple(deg)) + + return None + + def _repr_(self) -> str: + """ + TESTS:: + + sage: algebras.Free(QQ,4,'x,y,z,t').construction()[0] + Associative[x,y,z,t] + sage: algebras.Free(QQ,4,'x,y,z,t',degrees=(1,2,3,4)).construction()[0] + Associative[x,y,z,t] with degrees {x: 1, y: 2, z: 3, t: 4} + """ + vars = ','.join(self.vars) + if self.degs is None: + return f"Associative[{vars}]" + return f"Associative[{vars}] with degrees {self.degs}" diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index f5217231263..e841be77a59 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -202,7 +202,7 @@ def _construct_UEA(self): Free Algebra on 2 generators (x, y) over Rational Field sage: L. = LieAlgebra(QQ) sage: L._construct_UEA() - Free Algebra on 1 generators (x,) over Rational Field + Free Algebra on 1 generator (x,) over Rational Field """ return FreeAlgebra(self.base_ring(), len(self._names), self._names) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 43d72ed7470..eac48c03dfb 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -102,7 +102,7 @@ def is_unit(self): return super().is_unit() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): r""" Return the dictionary of ``self`` according to its lift to the cover. @@ -119,13 +119,15 @@ def monomial_coefficients(self): sage: f.dict() {0: 42, 1: 1} """ - return self.lift().monomial_coefficients() + return self.lift().monomial_coefficients(copy=copy) dict = monomial_coefficients # ------------------------------------------------------------------------------------------------------------------ # Parent class of the splitting algebra # -------------------------------------------------------------------------------------------------------- + + class SplittingAlgebra(PolynomialQuotientRing_domain): r""" For a given monic polynomial `p(t)` of degree `n` over a commutative diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 7de8ff07798..f8e8f724adc 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -447,13 +447,17 @@ def inverse_g(self, i): sage: Y = algebras.YokonumaHecke(2, 4) sage: [2*Y.inverse_g(i) for i in range(1, 4)] - [(q^-1+q) + 2*g[1] + (q^-1+q)*t1*t2, - (q^-1+q) + 2*g[2] + (q^-1+q)*t2*t3, - (q^-1+q) + 2*g[3] + (q^-1+q)*t3*t4] + [(q^-1-q) + 2*g[1] + (q^-1-q)*t1*t2, + (q^-1-q) + 2*g[2] + (q^-1-q)*t2*t3, + (q^-1-q) + 2*g[3] + (q^-1-q)*t3*t4] + sage: all(Y.inverse_g(i) * Y.g(i) == Y.one() for i in range(1, 4)) + True + sage: all(Y.g(i) * Y.inverse_g(i) == Y.one() for i in range(1, 4)) + True """ if i < 1 or i >= self._n: raise ValueError("invalid index") - return self.g(i) + (~self._q + self._q) * self.e(i) + return self.g(i) + (~self._q - self._q) * self.e(i) class Element(CombinatorialFreeModule.Element): def __invert__(self): @@ -468,10 +472,15 @@ def __invert__(self): sage: t.inverse() # indirect doctest t1^2*t2^2*t3^2 sage: [3*~(t*g) for g in Y.g()] - [(q^-1+q)*t2*t3^2 + (q^-1+q)*t1*t3^2 - + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[1], - (q^-1+q)*t1^2*t3 + (q^-1+q)*t1^2*t2 - + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[2]] + [(q^-1-q)*t2*t3^2 + (q^-1-q)*t1*t3^2 + + (q^-1-q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[1], + (q^-1-q)*t1^2*t3 + (q^-1-q)*t1^2*t2 + + (q^-1-q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[2]] + sage: g = prod(Y.g()) + sage: ~g * g == Y.one() + True + sage: g * ~g == Y.one() + True TESTS: diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 0eff675f3d4..516c6ffbc91 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -6375,6 +6375,7 @@ def dedekind_psi(N): N = Integer(N) return Integer(N * prod(1 + 1 / p for p in N.prime_divisors())) + def smooth_part(x, base): r""" Given an element ``x`` of a Euclidean domain and a factor base ``base``, @@ -6423,6 +6424,7 @@ def smooth_part(x, base): from sage.structure.factorization import Factorization return Factorization(fs) + def coprime_part(x, base): r""" Given an element ``x`` of a Euclidean domain and a factor base ``base``, diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ef4854db676..64881aba812 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -387,6 +387,7 @@ Ensure that :issue:`25626` is fixed. As the form of the answer is dependent of the giac version, we simplify it (see :issue:`34037`):: + sage: # needs sage.libs.giac sage: t = SR.var('t') sage: integrate(exp(t)/(t + 1)^2, t, algorithm='giac').full_simplify() ((t + 1)*Ei(t + 1) - e^(t + 1))/(t*e + e) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 179e5751894..643442ac714 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -31,7 +31,10 @@ from cysignals.signals cimport sig_on, sig_off from memory_allocator cimport MemoryAllocator from sage.rings.real_double import RDF -from sage.libs.gsl.all cimport * +from sage.libs.gsl.errno cimport gsl_set_error_handler_off +from sage.libs.gsl.integration cimport * +from sage.libs.gsl.monte cimport * +from sage.libs.gsl.rng cimport * from sage.misc.sageinspect import sage_getargspec from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf from sage.ext.fast_callable import fast_callable diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 2addf3e7f81..80eaf228533 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -22,7 +22,8 @@ from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off from sage.misc.sageinspect import sage_getargspec -from sage.libs.gsl.all cimport * +from sage.libs.gsl.types cimport * +from sage.libs.gsl.odeiv cimport * import sage.calculus.interpolation diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 10e829fd7fb..2589773dd31 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -402,7 +402,7 @@ def convolution_product(self, *maps): for mor in T[:-1]: # ALGORITHM: - # `split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + # ``split_convolve`` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. def split_convolve(x_y): x, y = x_y return (((xy1, y2), c * d) diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index de62a0109f0..01455011c40 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -458,7 +458,7 @@ def _subcategory_hook_(self, C): ....: VectorSpaces(GF(3)).parent_class) True - Check that :issue:`16618` is fixed: this `_subcategory_hook_` + Check that :issue:`16618` is fixed: this ``_subcategory_hook_`` method is only valid for :class:`Category_over_base_ring`, not :class:`Category_over_base`:: diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index a708164ff1b..f00808b64cf 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -206,11 +206,12 @@ def is_field(self, proof=True): """ return True - def is_integrally_closed(self): + def is_integrally_closed(self) -> bool: r""" - Return ``True``, as per :meth:`IntegralDomain.is_integrally_closed`: - for every field `F`, `F` is its own field of fractions, - hence every element of `F` is integral over `F`. + Return whether ``self`` is integrally closed. + + For every field `F`, `F` is its own field of fractions. + Therefore every element of `F` is integral over `F`. EXAMPLES:: @@ -222,6 +223,8 @@ def is_integrally_closed(self): Finite Field of size 5 sage: Z5.is_integrally_closed() True + sage: Frac(ZZ['x,y']).is_integrally_closed() + True """ return True diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 173a14cf25f..4dd66a9277b 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -1,6 +1,27 @@ # sage_setup: distribution = sagemath-categories r""" Integral domains + +TEST: + +A few tests for the method ``is_integrally_closed``:: + + sage: ZZ.is_integrally_closed() + True + sage: QQ.is_integrally_closed() + True + sage: QQbar.is_integrally_closed() # needs sage.rings.number_field + True + sage: GF(5).is_integrally_closed() + True + sage: Z5 = Integers(5); Z5 + Ring of integers modulo 5 + sage: Z5.is_integrally_closed() + Traceback (most recent call last): + ... + NotImplementedError + +Note that this raises a :exc:`NotImplementedError` if the answer is not known. """ # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 489f2f97dbb..cda4ecdca68 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1860,6 +1860,18 @@ def leading_item(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_item() # needs sage.combinat sage.modules ([3], -5) + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((0, 4, 0), 1) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((1, 2, 0), 3) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((0, 1, 3), 2) """ k = self.leading_support(*args, **kwds) return k, self[k] @@ -1890,6 +1902,18 @@ def leading_monomial(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_monomial() # needs sage.combinat sage.modules s[3] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + y^4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + x*y^2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + y*z^3 """ return self.parent().monomial(self.leading_support(*args, **kwds)) @@ -1919,6 +1943,18 @@ def leading_coefficient(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_coefficient() # needs sage.combinat sage.modules -5 + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 1 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 2 """ return self.leading_item(*args, **kwds)[1] @@ -1948,6 +1984,18 @@ def leading_term(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_term() # needs sage.combinat sage.modules -5*s[3] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + y^4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + 3*x*y^2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + 2*y*z^3 """ return self.parent().term(*self.leading_item(*args, **kwds)) @@ -2005,6 +2053,18 @@ def trailing_item(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_item() # needs sage.combinat sage.modules ([1], 2) + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((1, 1, 1), 4) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((0, 1, 3), 2) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((1, 2, 0), 3) """ k = self.trailing_support(*args, **kwds) return k, self[k] @@ -2035,6 +2095,18 @@ def trailing_monomial(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_monomial() # needs sage.combinat sage.modules s[1] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + x*y*z + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + y*z^3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + x*y^2 """ return self.parent().monomial(self.trailing_support(*args, **kwds)) @@ -2064,6 +2136,18 @@ def trailing_coefficient(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_coefficient() # needs sage.combinat sage.modules 2 + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 3 """ return self.trailing_item(*args, **kwds)[1] @@ -2093,6 +2177,18 @@ def trailing_term(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_term() # needs sage.combinat sage.modules 2*s[1] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 4*x*y*z + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 2*y*z^3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 3*x*y^2 """ return self.parent().term(*self.trailing_item(*args, **kwds)) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 8db71edfb9c..adfc75c00ec 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -423,6 +423,29 @@ def is_integral_domain(self, proof=True) -> bool: return False + def is_integrally_closed(self) -> bool: + r""" + Return whether this ring is integrally closed. + + This is the default implementation that + raises a :exc:`NotImplementedError`. + + EXAMPLES:: + + sage: x = polygen(ZZ, 'x') + sage: K. = NumberField(x^2 + 189*x + 394) + sage: R = K.order(2*a) + sage: R.is_integrally_closed() + False + sage: R + Order of conductor 2 generated by 2*a in Number Field in a with defining polynomial x^2 + 189*x + 394 + sage: S = K.maximal_order(); S + Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 189*x + 394 + sage: S.is_integrally_closed() + True + """ + raise NotImplementedError + def is_noetherian(self): """ Return ``True`` if this ring is Noetherian. @@ -621,8 +644,8 @@ def _mul_(self, x, switch_sides=False): INPUT: - - `x`, an object to multiply with. - - `switch_sides` (optional bool): If ``False``, + - ``x``, an object to multiply with. + - ``switch_sides`` (optional bool): If ``False``, the product is ``self*x``; if ``True``, the product is ``x*self``. diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 76030be831b..f30ed0ffeb2 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -444,29 +444,31 @@ def covering_map(self, character): sage: # needs sage.graphs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: W = S1.wedge(S1) + sage: S1_ = simplicial_sets.Sphere(1) + sage: S1_.n_cells(1)[0].rename("sigma_1'") + sage: W = S1.wedge(S1_) sage: G = CyclicPermutationGroup(3) sage: a, b = W.n_cells(1) sage: C = W.covering_map({a : G.gen(0), b : G.one()}); C Simplicial set morphism: From: Simplicial set with 9 non-degenerate simplices To: Wedge: (S^1 v S^1) - Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1, ()), - (sigma_1, ()), (sigma_1, (1,2,3)), (sigma_1, (1,2,3)), - (sigma_1, (1,3,2)), (sigma_1, (1,3,2))] - --> [*, *, *, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1] + Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1', ()), + (sigma_1', (1,2,3)), (sigma_1', (1,3,2)), (sigma_1, ()), + (sigma_1, (1,2,3)), (sigma_1, (1,3,2))] + --> [*, *, *, sigma_1', sigma_1', sigma_1', sigma_1, sigma_1, sigma_1] sage: C.domain() Simplicial set with 9 non-degenerate simplices sage: C.domain().face_data() {(*, ()): None, (*, (1,2,3)): None, (*, (1,3,2)): None, + (sigma_1', ()): ((*, ()), (*, ())), + (sigma_1', (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), + (sigma_1', (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), (sigma_1, ()): ((*, (1,2,3)), (*, ())), - (sigma_1, ()): ((*, ()), (*, ())), (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), - (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), - (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2)))} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2)))} """ from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet from sage.topology.simplicial_set_morphism import SimplicialSetMorphism @@ -530,7 +532,9 @@ def cover(self, character): sage: # needs sage.graphs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: W = S1.wedge(S1) + sage: S1_ = simplicial_sets.Sphere(1) + sage: S1_.n_cells(1)[0].rename("sigma_1'") + sage: W = S1.wedge(S1_) sage: G = CyclicPermutationGroup(3) sage: (a, b) = W.n_cells(1) sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}) @@ -538,12 +542,12 @@ def cover(self, character): {(*, ()): None, (*, (1,2,3)): None, (*, (1,3,2)): None, + (sigma_1', ()): ((*, (1,3,2)), (*, ())), + (sigma_1', (1,2,3)): ((*, ()), (*, (1,2,3))), + (sigma_1', (1,3,2)): ((*, (1,2,3)), (*, (1,3,2))), (sigma_1, ()): ((*, (1,2,3)), (*, ())), - (sigma_1, ()): ((*, (1,3,2)), (*, ())), (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), - (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), - (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2)))} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2)))} sage: C.homology(1) # needs sage.modules Z x Z x Z x Z sage: C.fundamental_group() diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index d94eb1ca309..3d1fe305dbc 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -324,9 +324,9 @@ def __iter__(self): r""" Return an error message requiring to override ``__iter__`` in ``self``. - As one has to implement specific category related methods (`__iter__` and - `__contains__`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `__iter__` has to fail. + As one has to implement specific category related methods (``__iter__`` and + ``__contains__``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``__iter__`` has to fail. EXAMPLES: @@ -352,9 +352,9 @@ def __contains__(self, c): r""" Return an error message requiring to override ``__contains__`` in ``self``. - As one has to implement specific category related methods (`__iter__` and - `__contains__`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `__contains__` has to fail. + As one has to implement specific category related methods (``__iter__`` and + ``__contains__``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``__contains__`` has to fail. EXAMPLES: @@ -448,9 +448,9 @@ def _repr_(self): r""" Return an error message requiring to override ``_repr_`` in ``self``. - As one has to implement specific representation methods (`_repr_` and - `_latex_`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `_repr_` has to fail. + As one has to implement specific representation methods (``_repr_`` and + ``_latex_``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``_repr_`` has to fail. EXAMPLES: @@ -476,9 +476,9 @@ def _latex_(self): r""" Return an error message requiring to override ``_latex_`` in ``self``. - As one has to implement specific representation methods (`_repr_` and - `_latex_`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `_latex_` has to fail. + As one has to implement specific representation methods (``_repr_`` and + ``_latex_``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``_latex_`` has to fail. EXAMPLES: diff --git a/src/sage/coding/binary_code.pxd b/src/sage/coding/binary_code.pxd index 38be220c731..44a793d15df 100644 --- a/src/sage/coding/binary_code.pxd +++ b/src/sage/coding/binary_code.pxd @@ -115,4 +115,3 @@ cdef class BinaryCodeClassifier: cdef void record_automorphism(self, int *, int) noexcept cdef void aut_gp_and_can_label(self, BinaryCode, int) noexcept - diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index a5bf1cf345f..e909c3a0bf3 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -389,7 +389,7 @@ def get_tau(s, l): # Either s or l is set, but not both. First a shared local function def find_integral_max(real_max, f): """Given a real (local) maximum of a function `f`, return that of - the integers around `real_max` which gives the (local) integral + the integers around ``real_max`` which gives the (local) integral maximum, and the value of at that point.""" if real_max in ZZ: int_max = ZZ(real_max) diff --git a/src/sage/combinat/abstract_tree.py b/src/sage/combinat/abstract_tree.py index 8ea604428f1..8359b3a8198 100644 --- a/src/sage/combinat/abstract_tree.py +++ b/src/sage/combinat/abstract_tree.py @@ -1857,7 +1857,7 @@ def __setitem__(self, idx, value): The tree ``self`` must be in a mutable state. See :mod:`sage.structure.list_clone` for more details about mutability. The default implementation here assume that the - container of the node implement a method `_setitem` with signature + container of the node implement a method ``_setitem`` with signature `self._setitem(idx, value)`. It is usually provided by inheriting from :class:`~sage.structure.list_clone.ClonableArray`. diff --git a/src/sage/combinat/bijectionist.py b/src/sage/combinat/bijectionist.py index ce1bf8aca13..2020b729917 100644 --- a/src/sage/combinat/bijectionist.py +++ b/src/sage/combinat/bijectionist.py @@ -69,52 +69,52 @@ sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌───────────┬────────┬────────┬────────┐ - │ a | α_1(a) | α_2(a) | α_3(a) | + │ a │ α_1(a) │ α_2(a) │ α_3(a) │ ╞═══════════╪════════╪════════╪════════╡ - │ [] | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | 2 | + │ [1, 2] │ 2 │ 2 │ 2 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 1] | 2 | 1 | 0 | + │ [2, 1] │ 2 │ 1 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | 3 | + │ [1, 2, 3] │ 3 │ 3 │ 3 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 3, 2] | 3 | 2 | 1 | + │ [1, 3, 2] │ 3 │ 2 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 1, 3] | 3 | 2 | 1 | + │ [2, 1, 3] │ 3 │ 2 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 3, 1] | 3 | 2 | 0 | + │ [2, 3, 1] │ 3 │ 2 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [3, 1, 2] | 3 | 1 | 0 | + │ [3, 1, 2] │ 3 │ 1 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [3, 2, 1] | 3 | 2 | 1 | + │ [3, 2, 1] │ 3 │ 2 │ 1 │ └───────────┴────────┴────────┴────────┘ sage: table(b, header_row=True, frame=True) ┌───────────┬───┬────────┬────────┬────────┐ - │ b | τ | β_1(b) | β_2(b) | β_3(b) | + │ b │ τ │ β_1(b) │ β_2(b) │ β_3(b) │ ╞═══════════╪═══╪════════╪════════╪════════╡ - │ [] | 0 | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | 1 | 0 | + │ [1, 2] │ 2 │ 2 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 1] | 1 | 2 | 2 | 2 | + │ [2, 1] │ 1 │ 2 │ 2 │ 2 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | 1 | 0 | + │ [1, 2, 3] │ 3 │ 3 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 3, 2] | 2 | 3 | 2 | 1 | + │ [1, 3, 2] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 1, 3] | 2 | 3 | 2 | 1 | + │ [2, 1, 3] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 3, 1] | 2 | 3 | 2 | 1 | + │ [2, 3, 1] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [3, 1, 2] | 2 | 3 | 2 | 0 | + │ [3, 1, 2] │ 2 │ 3 │ 2 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [3, 2, 1] | 1 | 3 | 3 | 3 | + │ [3, 2, 1] │ 1 │ 3 │ 3 │ 3 │ └───────────┴───┴────────┴────────┴────────┘ sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition @@ -849,51 +849,51 @@ def statistics_table(self, header=True): sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌───────────┬────────┬────────┐ - │ a | α_1(a) | α_2(a) | + │ a │ α_1(a) │ α_2(a) │ ╞═══════════╪════════╪════════╡ - │ [] | 0 | 0 | + │ [] │ 0 │ 0 │ ├───────────┼────────┼────────┤ - │ [1] | 1 | 1 | + │ [1] │ 1 │ 1 │ ├───────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | + │ [1, 2] │ 2 │ 2 │ ├───────────┼────────┼────────┤ - │ [2, 1] | 1 | 0 | + │ [2, 1] │ 1 │ 0 │ ├───────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | + │ [1, 2, 3] │ 3 │ 3 │ ├───────────┼────────┼────────┤ - │ [1, 3, 2] | 2 | 1 | + │ [1, 3, 2] │ 2 │ 1 │ ├───────────┼────────┼────────┤ - │ [2, 1, 3] | 2 | 1 | + │ [2, 1, 3] │ 2 │ 1 │ ├───────────┼────────┼────────┤ - │ [2, 3, 1] | 2 | 0 | + │ [2, 3, 1] │ 2 │ 0 │ ├───────────┼────────┼────────┤ - │ [3, 1, 2] | 1 | 0 | + │ [3, 1, 2] │ 1 │ 0 │ ├───────────┼────────┼────────┤ - │ [3, 2, 1] | 2 | 1 | + │ [3, 2, 1] │ 2 │ 1 │ └───────────┴────────┴────────┘ sage: table(b, header_row=True, frame=True) ┌───────────┬───┬────────┬────────┐ - │ b | τ | β_1(b) | β_2(b) | + │ b │ τ │ β_1(b) │ β_2(b) │ ╞═══════════╪═══╪════════╪════════╡ - │ [] | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [1, 2] | 2 | 1 | 0 | + │ [1, 2] │ 2 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [2, 1] | 1 | 2 | 2 | + │ [2, 1] │ 1 │ 2 │ 2 │ ├───────────┼───┼────────┼────────┤ - │ [1, 2, 3] | 3 | 1 | 0 | + │ [1, 2, 3] │ 3 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [1, 3, 2] | 2 | 2 | 1 | + │ [1, 3, 2] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [2, 1, 3] | 2 | 2 | 1 | + │ [2, 1, 3] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [2, 3, 1] | 2 | 2 | 1 | + │ [2, 3, 1] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [3, 1, 2] | 2 | 2 | 0 | + │ [3, 1, 2] │ 2 │ 2 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [3, 2, 1] | 1 | 3 | 3 | + │ [3, 2, 1] │ 1 │ 3 │ 3 │ └───────────┴───┴────────┴────────┘ TESTS: @@ -906,27 +906,27 @@ def statistics_table(self, header=True): sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌────────┐ - │ a | + │ a │ ╞════════╡ - │ [] | + │ [] │ ├────────┤ - │ [1] | + │ [1] │ ├────────┤ - │ [1, 2] | + │ [1, 2] │ ├────────┤ - │ [2, 1] | + │ [2, 1] │ └────────┘ sage: table(b, header_row=True, frame=True) ┌────────┬───┐ - │ b | τ | + │ b │ τ │ ╞════════╪═══╡ - │ [] | 0 | + │ [] │ 0 │ ├────────┼───┤ - │ [1] | 1 | + │ [1] │ 1 │ ├────────┼───┤ - │ [1, 2] | 2 | + │ [1, 2] │ 2 │ ├────────┼───┤ - │ [2, 1] | 1 | + │ [2, 1] │ 1 │ └────────┴───┘ We can omit the header:: diff --git a/src/sage/combinat/crystals/pbw_datum.pyx b/src/sage/combinat/crystals/pbw_datum.pyx index 03a7aee51d9..fa3be1ca72e 100644 --- a/src/sage/combinat/crystals/pbw_datum.pyx +++ b/src/sage/combinat/crystals/pbw_datum.pyx @@ -167,7 +167,7 @@ class PBWDatum(): def star(self): """ Return the starred version of ``self``, i.e., - with reversed `long_word` and `lusztig_datum` + with reversed ``long_word`` and ``lusztig_datum`` EXAMPLES:: diff --git a/src/sage/combinat/crystals/spins.pyx b/src/sage/combinat/crystals/spins.pyx index 5ff109602d0..28729fc93c0 100644 --- a/src/sage/combinat/crystals/spins.pyx +++ b/src/sage/combinat/crystals/spins.pyx @@ -65,7 +65,7 @@ def CrystalOfSpins(ct): Return the spin crystal of the given type `B`. This is a combinatorial model for the crystal with highest weight - `Lambda_n` (the `n`-th fundamental weight). It has + `\Lambda_n` (the `n`-th fundamental weight). It has `2^n` elements, here called Spins. See also :func:`~sage.combinat.crystals.letters.CrystalOfLetters`, :func:`~sage.combinat.crystals.spins.CrystalOfSpinsPlus`, @@ -108,7 +108,7 @@ def CrystalOfSpinsPlus(ct): r""" Return the plus spin crystal of the given type D. - This is the crystal with highest weight `Lambda_n` (the + This is the crystal with highest weight `\Lambda_n` (the `n`-th fundamental weight). INPUT: @@ -141,7 +141,7 @@ def CrystalOfSpinsMinus(ct): r""" Return the minus spin crystal of the given type D. - This is the crystal with highest weight `Lambda_{n-1}` + This is the crystal with highest weight `\Lambda_{n-1}` (the `(n-1)`-st fundamental weight). INPUT: diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 8fdf10c0bf1..e2a4d04b561 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -408,7 +408,7 @@ cdef class EvenlyDistributedSetsBacktracker: whether the set `f_{ij}(B)` is smaller than `B`. This is an internal function and should only be call by the backtracker - implemented in the method `__iter__`. + implemented in the method ``__iter__``. OUTPUT: ``False`` if ``self.B`` is not minimal diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 74a14fa1ecd..81e3a30508f 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -1361,8 +1361,8 @@ def _element_constructor_(self, generator): """ if isinstance(generator, AlternatingSignMatrix): SVM = generator.to_six_vertex_model() - elif isinstance(generator, SquareIceModel.Element) or \ - isinstance(generator, SixVertexConfiguration): + elif isinstance(generator, (SquareIceModel.Element, + SixVertexConfiguration)): SVM = generator else: # Not ASM nor SVM try: diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 475b5ef3e1b..d016f3495ea 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -154,7 +154,7 @@ cdef class dancing_linksWrapper: Initialization of the search algorithm. This adds the rows to the instance of dancing_links. This method is - used by `__init__` and `reinitialize` methods and should not be + used by ``__init__`` and ``reinitialize`` methods and should not be used directly. EXAMPLES:: diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py index 67fbcb4e70a..49131e3a5c7 100755 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -1885,7 +1885,7 @@ def __iter__(self): # iterate over blocks of letters over an alphabet if "alphabet" in self.constraints: A = self.constraints["alphabet"] - # establish a cutoff order `max_ell` + # establish a cutoff order ``max_ell`` max = self.constraints.get("max_length", infinity) max = self.constraints.get("length", max) max = max * len(A) diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index 094dafc8ddc..3e5afddf40e 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -8,4 +8,3 @@ cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) cpdef list right_action_product(list l, list r) - diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 978510c4ae9..db58f15f51e 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -74,7 +74,7 @@ cdef int next_swap(int n, int *c, int *o) noexcept: Note, Knuth's descriptions of algorithms tend to encourage one to think of finite state machines. For convenience, we have added comments to show what state the machine is - in at any given point in the algorithm. `plain_swap_reset` + in at any given point in the algorithm. ``plain_swap_reset`` sets the state to 1, and this function begins and ends in state 2. diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index e565eb3d2ee..2a4b2d24f48 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -794,7 +794,7 @@ class FinitePoset(UniqueRepresentation, Parent): corresponding to vertex ``i``. If ``elements`` is ``None``, then it is set to be the vertex set of the digraph. Note that if this option is set, then ``elements`` is considered as a specified linear extension of the poset - and the `linear_extension` attribute is set. + and the ``linear_extension`` attribute is set. - ``category`` -- :class:`FinitePosets`, or a subcategory thereof diff --git a/src/sage/combinat/rigged_configurations/rigged_partition.pxd b/src/sage/combinat/rigged_configurations/rigged_partition.pxd index e99258f33b2..031ab548020 100644 --- a/src/sage/combinat/rigged_configurations/rigged_partition.pxd +++ b/src/sage/combinat/rigged_configurations/rigged_partition.pxd @@ -12,4 +12,3 @@ cdef class RiggedPartition(SageObject): cdef class RiggedPartitionTypeB(RiggedPartition): pass - diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index 53dadb9864d..dfede775aa3 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -90,7 +90,7 @@ def __init__(self, types): ((1, 0), 5), ((1, 1), 6), ((1, 2), 7), ((1, 3), 8), ((1, 4), 9), ((1, 5), 10), ((2, 1), 11), ((2, 2), 12), ((2, 3), 13)] - Similarly, the attribute `_shifts` specifies by how much the + Similarly, the attribute ``_shifts`` specifies by how much the indices of the bases of the ambient spaces of the components are shifted in the ambient space of this Cartan type:: diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index 092e2f9dbb7..5078003c6f2 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -73,7 +73,11 @@ def _repr_(self): sage: S([[1,3],[2,4]]) {{1, 3}, {2, 4}} """ - return '{' + ', '.join('{' + repr(sorted(x))[1:-1] + '}' for x in self) + '}' + try: + s = [sorted(x) for x in self] + except TypeError: + s = [sorted(x, key=str) for x in self] + return '{' + ', '.join('{' + repr(x)[1:-1] + '}' for x in s) + '}' def __hash__(self): """ @@ -532,7 +536,7 @@ def pre_conjugate(sp): class SetPartition(AbstractSetPartition, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" A partition of a set. @@ -620,7 +624,11 @@ def __init__(self, parent, s, check=True): {} """ self._latex_options = {} - ClonableArray.__init__(self, parent, sorted(map(frozenset, s), key=min), check=check) + try: + s = sorted(map(frozenset, s), key=min) + except TypeError: + s = sorted(map(frozenset, s), key=lambda b: min(str(b))) + ClonableArray.__init__(self, parent, s, check=check) def check(self): """ @@ -2821,7 +2829,11 @@ def __iter__(self): sage: SetPartitions(["a", "b"]).list() [{{'a', 'b'}}, {{'a'}, {'b'}}] """ - for sp in set_partition_iterator(sorted(self._set)): + try: + s = sorted(self._set) + except TypeError: + s = sorted(self._set, key=str) + for sp in set_partition_iterator(s): yield self.element_class(self, sp, check=False) def base_set(self): @@ -3179,7 +3191,11 @@ def __iter__(self): sage: SetPartitions(["a", "b", "c"], 2).list() [{{'a', 'c'}, {'b'}}, {{'a'}, {'b', 'c'}}, {{'a', 'b'}, {'c'}}] """ - for sp in set_partition_iterator_blocks(sorted(self._set), self._k): + try: + s = sorted(self._set) + except TypeError: + s = sorted(self._set, key=str) + for sp in set_partition_iterator_blocks(s, self._k): yield self.element_class(self, sp, check=False) def __contains__(self, x): diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 8d911087b24..92a068e4c8c 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -6747,7 +6747,7 @@ def _nonnegative_coefficients(x): sage: _nonnegative_coefficients(x^2-4) False """ - if isinstance(x, Polynomial) or isinstance(x, MPolynomial): + if isinstance(x, (Polynomial, MPolynomial)): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index aace1ba5a2c..cb912e67409 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5841,7 +5841,7 @@ class SemistandardTableaux(Tableaux): OUTPUT: - The appropriate class, after checking basic consistency tests. (For - example, specifying ``eval`` implies a value for `max_entry`). + example, specifying ``eval`` implies a value for ``max_entry``). A semistandard tableau is a tableau whose entries are positive integers, which are weakly increasing in rows and strictly increasing down columns. diff --git a/src/sage/combinat/triangles_FHM.py b/src/sage/combinat/triangles_FHM.py index c8248bdc5f2..9bd07daa5fe 100644 --- a/src/sage/combinat/triangles_FHM.py +++ b/src/sage/combinat/triangles_FHM.py @@ -427,7 +427,8 @@ def h(self): """ x, y = self._vars n = self._n - step = self._poly(x=y / (y - 1), y=(y - 1) * x / (1 + (y - 1) * x)) + step = self._poly.subs({x: y / (y - 1), + y: (y - 1) * x / (1 + (y - 1) * x)}) step *= (1 + (y - 1) * x)**n polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -503,7 +504,8 @@ def m(self): """ x, y = self._vars n = self._n - step = self._poly(x=(x - 1) * y / (1 - y), y=x / (x - 1)) * (1 - y)**n + step = self._poly.subs({x: (x - 1) * y / (1 - y), + y: x / (x - 1)}) * (1 - y)**n polym = step.numerator() return M_triangle(polym, variables=(x, y)) @@ -536,8 +538,8 @@ def f(self): """ x, y = self._vars n = self._n - step1 = self._poly(x=x / (1 + x), y=y) * (x + 1)**n - step2 = step1(x=x, y=y / x) + step1 = self._poly.subs({x: x / (1 + x), y: y}) * (x + 1)**n + step2 = step1.subs({x: x, y: y / x}) polyf = step2.numerator() return F_triangle(polyf, variables=(x, y)) @@ -585,8 +587,9 @@ def vector(self): sage: H_triangle(ht).vector() x^2 + 3*x + 1 """ - anneau = PolynomialRing(ZZ, 'x') - return anneau(self._poly(y=1)) + x, y = self._vars + anneau = PolynomialRing(ZZ, "x") + return anneau(self._poly.subs({y: 1})) class F_triangle(Triangle): @@ -617,7 +620,8 @@ def h(self): """ x, y = self._vars n = self._n - step = (1 - x)**n * self._poly(x=x / (1 - x), y=x * y / (1 - x)) + step = (1 - x)**n * self._poly.subs({x: x / (1 - x), + y: x * y / (1 - x)}) polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -662,11 +666,39 @@ def m(self): """ x, y = self._vars n = self._n - step = self._poly(x=y * (x - 1) / (1 - x * y), y=x * y / (1 - x * y)) + step = self._poly.subs({x: y * (x - 1) / (1 - x * y), + y: x * y / (1 - x * y)}) step *= (1 - x * y)**n polym = step.numerator() return M_triangle(polym, variables=(x, y)) + def parabolic(self): + """ + Return a parabolic version of the F-triangle. + + This is obtained by replacing the variable `y` by `y-1`. + + EXAMPLES:: + + sage: from sage.combinat.triangles_FHM import H_triangle + sage: x, y = polygens(ZZ,'x,y') + sage: H_triangle(1+x*y).f() + F: x + y + 1 + sage: _.parabolic() + F: x + y + + TESTS:: + + sage: a, b = polygens(ZZ,'a,b') + sage: H_triangle(1+a*b).f() + F: a + b + 1 + sage: _.parabolic() + F: a + b + """ + x, y = self._vars + polyf = self._poly.subs({y: y - 1}) + return F_triangle(polyf, variables=(x, y)) + def vector(self): """ Return the f-vector as a polynomial in one variable. @@ -681,9 +713,10 @@ def vector(self): sage: F_triangle(ft).vector() 5*x^2 + 5*x + 1 """ - anneau = PolynomialRing(ZZ, 'x') - x = anneau.gen() - return anneau(self._poly(y=x)) + x, y = self._vars + anneau = PolynomialRing(ZZ, "x") + nx = anneau.gen() + return anneau(self._poly.subs({x: nx, y: nx})) class Gamma_triangle(Triangle): diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index e940582f83c..403b28f2049 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -90,10 +90,10 @@ def Words(alphabet=None, length=None, finite=True, infinite=True): sage: Words('natural numbers') Finite and infinite words over Non negative integers """ - if isinstance(alphabet, FiniteWords) or \ - isinstance(alphabet, InfiniteWords) or \ - isinstance(alphabet, FiniteOrInfiniteWords) or \ - isinstance(alphabet, Words_n): + if isinstance(alphabet, (FiniteWords, + InfiniteWords, + FiniteOrInfiniteWords, + Words_n)): return alphabet if length is None: diff --git a/src/sage/crypto/key_exchange/diffie_hellman.py b/src/sage/crypto/key_exchange/diffie_hellman.py index 47b6bd392a8..8dee1010a19 100644 --- a/src/sage/crypto/key_exchange/diffie_hellman.py +++ b/src/sage/crypto/key_exchange/diffie_hellman.py @@ -254,7 +254,7 @@ def subgroup_size(self) -> Integer: def __len__(self) -> int: """ Calculates the size of the subgroup of `\\GF{p}` generated by - ``self.generator()``. This is a wrapper around `subgroup_size`. + ``self.generator()``. This is a wrapper around ``subgroup_size``. TESTS:: diff --git a/src/sage/data_structures/bitset.pxd b/src/sage/data_structures/bitset.pxd index db627b294cd..a93e26c2ef9 100644 --- a/src/sage/data_structures/bitset.pxd +++ b/src/sage/data_structures/bitset.pxd @@ -37,4 +37,3 @@ cdef class Bitset(FrozenBitset): cpdef discard(self, unsigned long n) cpdef pop(self) cpdef clear(self) - diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 668af9abacc..bc5b9ba9bdd 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -729,7 +729,7 @@ def __init__(self, num_strands): def _warn_incompatibility(self, fname): """ - Warn the user that he has an incomaptible file cache under `Sage_DOT` + Warn the user that he has an incomaptible file cache under ``Sage_DOT`` and move it away to another file (marked with timestamp). EXAMPLES:: diff --git a/src/sage/databases/sloane.py b/src/sage/databases/sloane.py index 78fc268b486..aac252d84a8 100644 --- a/src/sage/databases/sloane.py +++ b/src/sage/databases/sloane.py @@ -12,7 +12,7 @@ :: sage: SloaneEncyclopedia[60843] # optional - sloane_database - [1, 6, 21, 107] + [1, 6, 21, 107, 47176870] To get the name of a sequence, type @@ -149,6 +149,17 @@ def __len__(self): self.load() return len(self.__data__) + def is_installed(self): + """ + Check if a local copy of the encyclopedia is installed. + + EXAMPLES:: + + sage: SloaneEncyclopedia.is_installed() # optional - sloane_database + True + """ + return os.path.exists(self.__file__) and os.path.exists(self.__file_names__) + def find(self, seq, maxresults=30): """ Return a list of all sequences which have seq as a subsequence, up @@ -274,7 +285,7 @@ def load(self): for L in file_seq: if len(L) == 0: continue - m = entry.search(L) + m = entry.search(L.decode('utf-8')) if m: seqnum = int(m.group('num')) msg = m.group('body').strip() @@ -287,10 +298,13 @@ def load(self): for L in file_names: if not L: continue - m = entry.search(L) + m = entry.search(L.decode('utf-8')) if m: seqnum = int(m.group('num')) - self.__data__[seqnum][3] = m.group('body').strip() + if seqnum in self.__data__: + self.__data__[seqnum][3] = m.group('body').strip() + else: + self.__data__[seqnum] = [seqnum, None, 'unknown', m.group('body').strip()] file_names.close() self.__loaded_names__ = True except KeyError: diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index fff35be8307..05dde014fec 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -59,6 +59,7 @@ auto_optional_tags = set() + class DocTestDefaults(SageObject): """ This class is used for doctesting the Sage doctest module. diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index bf0309d3131..45b3987de05 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -45,6 +45,7 @@ # software xxx is available to Sage. prefix = 'has_' + def has_internet(): """ Test if Internet is available. @@ -61,6 +62,7 @@ def has_internet(): from sage.features.internet import Internet return Internet().is_present() + def has_latex(): """ Test if Latex is available. @@ -74,6 +76,7 @@ def has_latex(): from sage.features.latex import latex return latex().is_present() + def has_xelatex(): """ Test if xelatex is available. @@ -87,6 +90,7 @@ def has_xelatex(): from sage.features.latex import xelatex return xelatex().is_present() + def has_pdflatex(): """ Test if pdflatex is available. @@ -100,6 +104,7 @@ def has_pdflatex(): from sage.features.latex import pdflatex return pdflatex().is_present() + def has_lualatex(): """ Test if lualatex is available. @@ -113,6 +118,7 @@ def has_lualatex(): from sage.features.latex import lualatex return lualatex().is_present() + def has_magma(): """ Test if Magma is available. @@ -126,6 +132,7 @@ def has_magma(): from sage.features.interfaces import Magma return Magma().is_present() + def has_matlab(): """ Test if Matlab is available. @@ -139,6 +146,7 @@ def has_matlab(): from sage.features.interfaces import Matlab return Matlab().is_present() + def has_mathematica(): """ Test if Mathematica is available. @@ -152,6 +160,7 @@ def has_mathematica(): from sage.features.interfaces import Mathematica return Mathematica().is_present() + def has_maple(): """ Test if Maple is available. @@ -165,6 +174,7 @@ def has_maple(): from sage.features.interfaces import Maple return Maple().is_present() + def has_macaulay2(): """ Test if Macaulay2 is available. @@ -178,6 +188,7 @@ def has_macaulay2(): from sage.features.interfaces import Macaulay2 return Macaulay2().is_present() + def has_octave(): """ Test if Octave is available. @@ -191,6 +202,7 @@ def has_octave(): from sage.features.interfaces import Octave return Octave().is_present() + def has_pandoc(): """ Test if pandoc is available. @@ -204,6 +216,7 @@ def has_pandoc(): from sage.features.pandoc import Pandoc return Pandoc().is_present() + def has_scilab(): """ Test if Scilab is available. @@ -221,6 +234,7 @@ def has_scilab(): except Exception: return False + def has_cplex(): """ Test if CPLEX is available. @@ -234,6 +248,7 @@ def has_cplex(): from sage.features.mip_backends import CPLEX return CPLEX().is_present() + def has_gurobi(): """ Test if Gurobi is available. @@ -247,6 +262,7 @@ def has_gurobi(): from sage.features.mip_backends import Gurobi return Gurobi().is_present() + def has_graphviz(): """ Test if graphviz (dot, twopi, neato) are available. @@ -260,6 +276,7 @@ def has_graphviz(): from sage.features.graphviz import Graphviz return Graphviz().is_present() + def has_ffmpeg(): """ Test if ffmpeg is available. @@ -273,6 +290,7 @@ def has_ffmpeg(): from sage.features.ffmpeg import FFmpeg return FFmpeg().is_present() + def has_imagemagick(): """ Test if ImageMagick (command magick or convert) is available. @@ -286,6 +304,7 @@ def has_imagemagick(): from sage.features.imagemagick import ImageMagick return ImageMagick().is_present() + def has_dvipng(): """ Test if dvipng is available. @@ -299,6 +318,7 @@ def has_dvipng(): from sage.features.dvipng import dvipng return dvipng().is_present() + def has_pdf2svg(): """ Test if pdf2svg is available. @@ -312,6 +332,7 @@ def has_pdf2svg(): from sage.features.pdf2svg import pdf2svg return pdf2svg().is_present() + def has_rubiks(): """ Test if the rubiks package (``cu2``, ``cubex``, ``dikcube``, @@ -326,6 +347,7 @@ def has_rubiks(): from sage.features.rubiks import Rubiks return Rubiks().is_present() + def has_4ti2(): """ Test if the 4ti2 package is available. @@ -339,6 +361,7 @@ def has_4ti2(): from sage.features.four_ti_2 import FourTi2 return FourTi2().is_present() + def external_features(): r""" Generate the features that are only to be tested if ``--optional=external`` is used. @@ -363,6 +386,7 @@ def external_features(): yield CPLEX() yield Gurobi() + def external_software() -> list[str]: """ Return the alphabetical list of external software supported by this module. diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 20f6eb6ce69..79a92835b26 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -58,7 +58,7 @@ special_optional_regex = ( "py2|long time|not implemented|not tested|optional|needs|known bug" ) -tag_with_explanation_regex = r"((?:\w|[.])*)\s*(?:\((?P.*?)\))?" +tag_with_explanation_regex = r"((?:!?\w|[.])*)\s*(?:\((?P.*?)\))?" optional_regex = re.compile( rf"[^ a-z]\s*(?P{special_optional_regex})(?:\s|[:-])*(?P(?:(?:{tag_with_explanation_regex})\s*)*)", re.IGNORECASE, @@ -1124,14 +1124,14 @@ def check_and_clear_tag_counts(): continue if self.optional_tags is not True: - extra = { - tag - for tag in optional_tags - if ( - tag not in self.optional_tags - and tag not in available_software - ) - } + extra = set() + for tag in optional_tags: + if tag not in self.optional_tags: + if tag.startswith('!'): + if tag[1:] in available_software: + extra.add(tag) + elif tag not in available_software: + extra.add(tag) if extra and any(tag in ["bug"] for tag in extra): # Bug only occurs on a specific platform? bug_platform = optional_tags_with_values.get("bug") diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index e6bfd52bf33..54742cd6c1e 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -50,6 +50,7 @@ from sage.doctest.sources import DictAsObject from .external import available_software + def signal_name(sig): """ Return a string describing a signal number. @@ -91,6 +92,7 @@ def signal_name(sig): return "bus error" return "signal %s" % sig + class DocTestReporter(SageObject): """ This class reports to the users on the results of doctests. diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index ed831598e65..e17df277c1f 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -26,6 +26,7 @@ from time import time as walltime from os import sysconf, times + def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False): """ EXAMPLES:: @@ -614,6 +615,7 @@ def make_recording_dict(D, st, gt): ans.got = gt return ans + class NestedName: """ Class used to construct fully qualified names based on indentation level. diff --git a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py index f16d99cbb11..67ca0c97e8d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py @@ -165,7 +165,8 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): if isinstance(morphism_or_polys, SchemeMorphism_polynomial): domain = morphism_or_polys.domain() if domain is not None: - if isinstance(domain, AffineSpace_generic) or isinstance(domain, AlgebraicScheme_subscheme_affine): + if isinstance(domain, (AffineSpace_generic, + AlgebraicScheme_subscheme_affine)): from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine return DynamicalSystem_affine(morphism_or_polys, domain) if isinstance(domain, Berkovich_Cp): diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 2fab95104f1..f395214b516 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -385,7 +385,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): polys = list(morphism_or_polys) if len(polys) == 1: raise ValueError("list/tuple must have at least 2 polynomials") - test = lambda x: isinstance(x, PolynomialRing_general) or isinstance(x, MPolynomialRing_base) + test = lambda x: isinstance(x, (PolynomialRing_general, MPolynomialRing_base)) if not all(test(poly.parent()) for poly in polys): try: polys = [poly.lift() for poly in polys] @@ -450,7 +450,8 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): msg = 'polys (={}) must be of the same degree' raise ValueError(msg.format(polys)) - if not isinstance(domain, ProjectiveSpace_ring) and not isinstance(domain, AlgebraicScheme_subscheme_projective): + if not isinstance(domain, (ProjectiveSpace_ring, + AlgebraicScheme_subscheme_projective)): raise ValueError('"domain" must be a projective scheme') if R not in Fields(): return typecall(cls, polys, domain) @@ -2042,7 +2043,7 @@ def green_function(self, P, v, **kwds): sage: f.green_function(P([2, 1]), K.ideal(7), N=7) 0.48647753726382832627633818586 sage: f.green_function(P([w, 1]), K.ideal(17), error_bound=0.001) - -0.70813041039490996737374178059 + -0.70821687320448199545278619351 :: @@ -2073,7 +2074,7 @@ def green_function(self, P, v, **kwds): K = BR elif is_prime(v): K = Qp(v, prec) - elif v == 0: + elif v == 0 and BR == QQ: K = R v = BR.places(prec=prec)[0] else: @@ -2095,6 +2096,7 @@ def green_function(self, P, v, **kwds): # compute upper bound if isinstance(v, RingHomomorphism_im_gens): #archimedean vindex = BR.places(prec=prec).index(v) + emb = BR.places(prec=prec)[vindex] U = GBR.local_height_arch(vindex, prec=prec) + R(binomial(dim + d, d)).log() else: #non-archimedean U = GBR.local_height(v, prec=prec) @@ -2103,30 +2105,31 @@ def green_function(self, P, v, **kwds): CR = GBR.codomain().ambient_space().coordinate_ring() #.lift() only works over fields I = CR.ideal(GBR.defining_polynomials()) maxh = 0 - Res = 1 for k in range(dim + 1): CoeffPolys = (CR.gen(k) ** D).lift(I) h = 1 - for poly in CoeffPolys: - if poly != 0: - for c in poly.coefficients(): - Res = lcm(Res, c.denominator()) for poly in CoeffPolys: if poly != 0: if isinstance(v, RingHomomorphism_im_gens): #archimedean if BR == QQ: - h = max([(Res*c).local_height_arch(prec=prec) for c in poly.coefficients()]) + h = max([R(K(c).abs()) for c in poly.coefficients()]) else: - h = max([(Res*c).local_height_arch(vindex, prec=prec) for c in poly.coefficients()]) + h = max([R(emb(c).abs()) for c in poly.coefficients()]) else: #non-archimedean - h = max([c.local_height(v, prec=prec) for c in poly.coefficients()]) + if BR == QQ: + h = max([R(v)**(-R(c.valuation(v))) for c in poly.coefficients()]) + else: + h = max([R(c.abs_non_arch(v, prec=prec)) for c in poly.coefficients()]) maxh = max(h, maxh) if maxh == 0: maxh = 1 #avoid division by 0 if isinstance(v, RingHomomorphism_im_gens): #archimedean - L = R(Res / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs() + L = R(1 / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs() else: #non-archimedean - L = R(Res / maxh).log().abs() + if BR == QQ: + L = ((-self.resultant().valuation(v))*R(v).log()).abs() + else: + L = (self.resultant().abs_non_arch(v, prec=prec)).log().abs() C = max([U, L]) if C != 0: N = R(C / (err*(d-1))).log(d).abs().ceil() @@ -2252,7 +2255,7 @@ def canonical_height(self, P, **kwds): sage: f = DynamicalSystem_projective([1000*x^2 - 29*y^2, 1000*y^2]) sage: Q = P(-1/4, 1) sage: f.canonical_height(Q, error_bound=0.01) # needs sage.libs.pari - 3.7996079979254623065837411853 + 3.7979215342343045582800170705 :: @@ -3530,7 +3533,9 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): if hyperplane_found: break else: - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base) or isinstance(R, FractionField_generic): + if isinstance(R, (PolynomialRing_general, + MPolynomialRing_base, + FractionField_generic)): # for polynomial rings, we can get an infinite family of hyperplanes # by increasing the degree var = R.gen() @@ -4592,7 +4597,8 @@ def preperiodic_points(self, m, n, **kwds): for k in ZZ(n).divisors(): if ZZ(n/k).is_prime(): Sn.append(k) - if (isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_general, + MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) @@ -4946,9 +4952,10 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari elif minimal: Sn = [] for k in ZZ(n).divisors(): - if ZZ(n/k).is_prime(): + if ZZ(n//k).is_prime(): Sn.append(k) - if (isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_general, + MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) @@ -5239,7 +5246,8 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur # if we are already using an algebraic closure, we move the # map into a finite extension and set use_algebraic_closure to True # in order to get a scheme defined over a finite extension - if isinstance(K, sage.rings.abc.AlgebraicField) or isinstance(K, AlgebraicClosureFiniteField_generic): + if isinstance(K, (sage.rings.abc.AlgebraicField, + AlgebraicClosureFiniteField_generic)): f = self.reduce_base_field() K = f.base_ring() use_algebraic_closure = True @@ -5780,7 +5788,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', else: F = base_ring if isinstance(base_ring, FractionField_generic): - if isinstance(base_ring.ring(), MPolynomialRing_base) or isinstance(base_ring.ring(), PolynomialRing_general): + if isinstance(base_ring.ring(), (MPolynomialRing_base, + PolynomialRing_general)): f.normalize_coordinates() f_ring = f.change_ring(base_ring.ring()) X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) @@ -5883,7 +5892,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', base_ring = dom.base_ring() if isinstance(base_ring, FractionField_generic): base_ring = base_ring.ring() - if (isinstance(base_ring, PolynomialRing_general) or isinstance(base_ring, MPolynomialRing_base)): + if isinstance(base_ring, (PolynomialRing_general, + MPolynomialRing_base)): base_ring = base_ring.base_ring() elif base_ring in FunctionFields(): base_ring = base_ring.constant_base_field() @@ -6837,10 +6847,10 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): INPUT: - `return_conjugation`` -- (default: ``False``) if ``True``, then + ``return_conjugation`` -- (default: ``False``) if ``True``, then return the conjugation that moves self to a map that comes from a Short Weierstrass Model Elliptic curve - `check_lattes``.-.(default:.``False``) if ``True``, then will ValueError if not Lattes + ``check_lattes``.-.(default:.``False``) if ``True``, then will ValueError if not Lattes OUTPUT: a Short Weierstrass Model Elliptic curve which is isogenous to the Elliptic curve of 'self', diff --git a/src/sage/env.py b/src/sage/env.py index 0cfe6dfe8c4..060eb2209a9 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -2,16 +2,21 @@ r""" Sage Runtime Environment -Verify that importing ``sage.all`` works in Sage's Python without any ``SAGE_`` -environment variables, and has the same ``SAGE_ROOT`` and ``SAGE_LOCAL`` -(see also :issue:`29446`):: +Verify that importing ``sage.all`` works in Sage's Python without any +``SAGE_`` environment variables, and has the same ``SAGE_ROOT`` and +``SAGE_LOCAL`` (see also :issue:`29446`). If ``SAGE_ROOT`` is a path, +we normalize it, but keep in mind that ``SAGE_ROOT`` may also be +``None``:: sage: env = {k:v for (k,v) in os.environ.items() if not k.startswith("SAGE_")} sage: from subprocess import check_output sage: module_name = "sage.all" # hide .all import from the linter sage: cmd = f"from {module_name} import SAGE_ROOT, SAGE_LOCAL;" sage: cmd += "from os.path import samefile;" - sage: cmd += f"s1 = samefile(SAGE_ROOT, '{SAGE_ROOT}') if SAGE_ROOT else True;" + sage: if SAGE_ROOT is None: + ....: cmd += "s1 = SAGE_ROOT is None;" + ....: else: + ....: cmd += f"s1 = samefile(SAGE_ROOT, '{SAGE_ROOT}');" sage: cmd += f"s2 = samefile(SAGE_LOCAL, '{SAGE_LOCAL}');" sage: cmd += "print(s1 and s2);" sage: out = check_output([sys.executable, "-c", cmd], env=env).decode().strip() # long time diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index e02015a5710..ac4a0bcd97f 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -418,6 +418,7 @@ def is_hidden(self): return True return False + class FeatureNotPresentError(RuntimeError): r""" A missing feature error. diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 9d070d932ed..2394d4d6c05 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -25,7 +25,7 @@ def sage_data_path(data_name): r""" - Search path for database `data_name`. + Search path for database ``data_name``. EXAMPLES:: diff --git a/src/sage/features/dot2tex.py b/src/sage/features/dot2tex.py new file mode 100644 index 00000000000..e9f97b6e704 --- /dev/null +++ b/src/sage/features/dot2tex.py @@ -0,0 +1,42 @@ +# sage_setup: distribution = sagemath-environment +r""" +Check for ``dot2tex`` +""" + +# ***************************************************************************** +# Copyright (C) 2024 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from . import PythonModule + + +class dot2tex(PythonModule): + r""" + A :class:`sage.features.Feature` describing the presence of :ref:`dot2tex `. + + dot2tex is provided by an optional package in the Sage distribution. + + EXAMPLES:: + + sage: from sage.features.dot2tex import dot2tex + sage: dot2tex().is_present() # optional - dot2tex + FeatureTestResult('dot2tex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.dot2tex import dot2tex + sage: isinstance(dot2tex(), dot2tex) + True + """ + PythonModule.__init__(self, 'dot2tex', spkg='dot2tex') + + +def all_features(): + return [dot2tex()] diff --git a/src/sage/features/dvipng.py b/src/sage/features/dvipng.py index 68bcdcb5a04..4ae0c7a01cf 100644 --- a/src/sage/features/dvipng.py +++ b/src/sage/features/dvipng.py @@ -14,6 +14,7 @@ from . import Executable + class dvipng(Executable): r""" A :class:`~sage.features.Feature` describing the presence of ``dvipng``. diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index 0d3ff8e4232..8214e4d6ff3 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -14,6 +14,7 @@ from . import Executable, FeatureTestResult + class FFmpeg(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`ffmpeg `. diff --git a/src/sage/features/fricas.py b/src/sage/features/fricas.py index 539b3b027dd..15c346248ae 100644 --- a/src/sage/features/fricas.py +++ b/src/sage/features/fricas.py @@ -16,6 +16,7 @@ import subprocess from . import Executable, FeatureTestResult + class FriCAS(Executable): r""" A :class:`~sage.features.Feature` which checks for the :ref:`fricas ` binary. @@ -62,5 +63,6 @@ def is_functional(self): return FeatureTestResult(self, True) + def all_features(): return [FriCAS()] diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 609cb37c263..6a6f20b30a8 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -16,6 +16,7 @@ from .join_feature import JoinFeature from .sagemath import sage__libs__gap + class GapPackage(Feature): r""" A :class:`~sage.features.Feature` describing the presence of a GAP package. diff --git a/src/sage/features/giac.py b/src/sage/features/giac.py index 6f9fe2ccfba..67403a332be 100644 --- a/src/sage/features/giac.py +++ b/src/sage/features/giac.py @@ -5,6 +5,7 @@ from . import Executable, FeatureTestResult + class Giac(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`giac `. @@ -26,5 +27,6 @@ def __init__(self): Executable.__init__(self, 'giac', executable='giac', spkg='giac', type='standard') + def all_features(): return [Giac()] diff --git a/src/sage/features/igraph.py b/src/sage/features/igraph.py index 9bb61c28454..bd349ec730d 100644 --- a/src/sage/features/igraph.py +++ b/src/sage/features/igraph.py @@ -40,5 +40,6 @@ def __init__(self): [PythonModule('igraph', spkg='python_igraph', url='http://igraph.org')]) + def all_features(): return [python_igraph()] diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 866d0aed95e..fa63616b596 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -21,6 +21,7 @@ from . import Executable, FeatureTestResult from .join_feature import JoinFeature + class Magick(Executable): r""" A :class:`~sage.features.Feature` describing the presence of ``magick`` or the deprecated ``convert``. @@ -134,5 +135,6 @@ def __init__(self): spkg='imagemagick', url='https://www.imagemagick.org/') + def all_features(): return [ImageMagick()] diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index b5d83b06972..3d2efaf50d6 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -18,6 +18,7 @@ from . import Feature, FeatureTestResult + class Kenzo(Feature): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`Kenzo `. diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 271800beece..46173f7484b 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -208,6 +208,7 @@ def __init__(self): Executable.__init__(self, 'dvips', executable='dvips', url='https://tug.org/texinfohtml/dvips.html') + class TeXFile(StaticFile): r""" A :class:`sage.features.Feature` describing the presence of a TeX file. diff --git a/src/sage/features/msolve.py b/src/sage/features/msolve.py index bc66da45044..24215a7c57c 100644 --- a/src/sage/features/msolve.py +++ b/src/sage/features/msolve.py @@ -22,6 +22,7 @@ from . import Executable from . import FeatureTestResult + class msolve(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`msolve `. @@ -64,5 +65,6 @@ def is_functional(self): reason="output of msolve -h not recognized") return FeatureTestResult(self, True) + def all_features(): return [msolve()] diff --git a/src/sage/features/palp.py b/src/sage/features/palp.py index 9e3324c495b..b20f44104d6 100644 --- a/src/sage/features/palp.py +++ b/src/sage/features/palp.py @@ -43,6 +43,7 @@ def __init__(self, palpprog, suff=None): executable=f"{palpprog}.x", spkg='palp', type='standard') + class Palp(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`PALP `. @@ -61,5 +62,6 @@ def __init__(self): for suff in (None, 4, 5, 6, 11)], description='PALP') + def all_features(): return [Palp()] diff --git a/src/sage/features/pdf2svg.py b/src/sage/features/pdf2svg.py index 41014eb8e5c..92d9f563b5b 100644 --- a/src/sage/features/pdf2svg.py +++ b/src/sage/features/pdf2svg.py @@ -14,6 +14,7 @@ from . import Executable + class pdf2svg(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`pdf2svg `. diff --git a/src/sage/features/poppler.py b/src/sage/features/poppler.py index a6da8343f53..436506e0b36 100644 --- a/src/sage/features/poppler.py +++ b/src/sage/features/poppler.py @@ -32,6 +32,7 @@ from . import Executable + class pdftocairo(Executable): r""" A :class:`sage.features.Feature` describing the presence of @@ -54,5 +55,6 @@ def __init__(self): Executable.__init__(self, "pdftocairo", executable='pdftocairo', url='https://poppler.freedesktop.org/') + def all_features(): return [pdftocairo()] diff --git a/src/sage/features/sloane_database.py b/src/sage/features/sloane_database.py new file mode 100644 index 00000000000..84aad5ce67a --- /dev/null +++ b/src/sage/features/sloane_database.py @@ -0,0 +1,59 @@ +# sage_setup: distribution = sagemath-environment +r""" +Feature for testing the presence of Sloane Online Encyclopedia of Integer Sequences +""" + +# **************************************************************************** +# Copyright (C) 2024 Kwankyu Lee +# +# 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 . import Feature + + +class SloaneOEIS(Feature): + r""" + A :class:`~sage.features.Feature` which describes the presence of + the Sloane Online Encyclopedia of Integer Sequences. + + EXAMPLES:: + + sage: from sage.features.sloane_database import SloaneOEIS + sage: bool(SloaneOEIS().is_present()) # optional - sloane_database + True + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sloane_database import SloaneOEIS + sage: isinstance(SloaneOEIS(), SloaneOEIS) + True + """ + Feature.__init__(self, name='sloane_database', + description='Sloane Online Encyclopedia of Integer Sequences') + + def _is_present(self): + r""" + Return whether the database is available. + + EXAMPLES:: + + sage: from sage.features.sloane_database import SloaneOEIS + sage: bool(SloaneOEIS().is_present()) # optional - !sloane_database + False + """ + try: + from sage.databases.sloane import SloaneEncyclopedia + except ImportError: + return False + return SloaneEncyclopedia.is_installed() + + +def all_features(): + return [SloaneOEIS()] diff --git a/src/sage/features/symengine_py.py b/src/sage/features/symengine_py.py index 96a64ca60b3..e822e252eda 100644 --- a/src/sage/features/symengine_py.py +++ b/src/sage/features/symengine_py.py @@ -40,5 +40,6 @@ def __init__(self): [PythonModule('symengine', spkg='symengine_py', url='https://pypi.org/project/symengine')]) + def all_features(): return [symengine_py()] diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index fc69057ef6f..2986e47960d 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -836,6 +836,7 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False, Check that the algorithm keyword can be used:: + sage: # needs sage.libs.giac sage: ex = piecewise([([0, 1], 1), ((1, oo), 1/x**2)]) sage: integral(ex, x, 0, 100, algorithm='sympy') 199/100 diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index e46e96c2b32..39622aaf3ef 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -1989,7 +1989,7 @@ def _solve_enumeration(self, maximization=True): sage: c._solve_enumeration() [[(0, 1), (1, 0)]] - Testing against an error in `_is_NE`. Note that 1 equilibrium is + Testing against an error in ``_is_NE``. Note that 1 equilibrium is missing: ``[(2/3, 1/3), (0, 1)]``, however this equilibrium has supports of different sizes. This only occurs in degenerate games and is not supported in the `enumeration` algorithm:: diff --git a/src/sage/games/quantumino.py b/src/sage/games/quantumino.py index 555f6901f4a..587e279e042 100644 --- a/src/sage/games/quantumino.py +++ b/src/sage/games/quantumino.py @@ -205,6 +205,7 @@ pentaminos.append(Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,2,0), (1,2,1)], color='purple')) pentaminos.append(Polyomino([(0,1,0), (1,0,0), (1,1,0), (1,1,1), (1,2,0)], color='gray')) + def show_pentaminos(box=(5, 8, 2)): r""" Show the 17 3-D pentaminos included in the game and the `5 \times 8 @@ -245,6 +246,8 @@ def show_pentaminos(box=(5, 8, 2)): ############################## # Class QuantuminoState ############################## + + class QuantuminoState(SageObject): r""" A state of the Quantumino puzzle. @@ -386,6 +389,8 @@ def show3d(self, size=0.85): ############################## # Class QuantuminoSolver ############################## + + class QuantuminoSolver(SageObject): r""" Return the Quantumino solver for the given box where one of the diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index ef912a5e501..c1d0ab39190 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -28,7 +28,7 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): r""" - Like `number_field_elements_from_algebraics`, but for a list of lists of lists. + Like ``number_field_elements_from_algebraics``, but for a list of lists of lists. EXAMPLES:: diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1402e0b1e77..9929ae7ca60 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -290,7 +290,7 @@ def plot(self, cell_colors=None, **kwds): cell_colors = rainbow(self._n) shuffle(cell_colors) else: - if not (isinstance(cell_colors, list) or (isinstance(cell_colors, dict))): + if not isinstance(cell_colors, (list, dict)): raise AssertionError("'cell_colors' must be a list or a dictionary") for i, p in enumerate(self._P): col = cell_colors[i] diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 1aa7b32d691..00a535c3335 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -2824,7 +2824,7 @@ cdef class CGraphBackend(GenericGraphBackend): # WARNING # If you modify this, you must keep in mind the documentation in the - # corresponding method in `generic_graph.py` in the method `edge_iterator`. + # corresponding method in ``generic_graph.py`` in the method ``edge_iterator``. # E.g. code assumes that you can use an iterator to relabel or delete arcs. u_int = cg._next_neighbor_unsafe(v_int, -1, out, &l_int) diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index a02541436ac..d82ba543669 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1569,7 +1569,7 @@ cdef class SparseGraphBackend(CGraphBackend): # WARNING # If you modify this, you must keep in mind the documentation in the - # corresponding method in `generic_graph.py` in the method `edge_iterator`. + # corresponding method in ``generic_graph.py`` in the method ``edge_iterator``. # E.g. code assumes that you can use an iterator to relabel or delete arcs. r = self._cg._neighbors_BTNode_unsafe(v_int, out, neighbors, maxdegree) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index e249046ae70..6a68eab6684 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -131,7 +131,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, bint normalize=True): - ``G`` -- a graph - ``_`` -- this variable is ignored, only its type matters. If it is of type - `mpq_t` then computations are made on `Q`, if it is ``double`` the + ``mpq_t`` then computations are made on `Q`, if it is ``double`` the computations are made on ``double``. - ``normalize`` -- boolean (default: ``True``); whether to renormalize the diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index 37c0ca5fb51..1803e91bb2c 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -475,6 +475,7 @@ def neighbors_iter(x): # Prevent finding twice a solution p.add_constraint(p.sum(b[u] for u in dom) <= best - 1) + def dominating_set(g, k=1, independent=False, total=False, connected=False, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -587,6 +588,7 @@ def dominating_set(g, k=1, independent=False, total=False, connected=False, valu # Enumeration of minimal dominating set as described in [BDHPR2019]_ # ============================================================================== + def _parent(G, dom, V_prev): r""" Return a subset of dom that is irredundant in ``V_prev``. diff --git a/src/sage/graphs/graph_decompositions/meson.build b/src/sage/graphs/graph_decompositions/meson.build index 0d9778ae2ba..1fc8bc1d765 100644 --- a/src/sage/graphs/graph_decompositions/meson.build +++ b/src/sage/graphs/graph_decompositions/meson.build @@ -1,4 +1,9 @@ -tdlib = cc.find_library('tdlib', required: false, disabler: true) +# tdlib is a header-only library +if cc.has_header('treedec/combinations.hpp') + tdlib = declare_dependency() +else + tdlib = disabler() +endif # Cannot be found via pkg-config rw = cc.find_library('rw') diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 8ed9ee9d224..da385943bd1 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -75,7 +75,7 @@ The treewidth of a clique is `n-1` and its treelength is 1:: :meth:`treewidth` | Compute the treewidth of `G` (and provide a decomposition). :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). - :meth:`make_nice_tree_decomposition` | Return a *nice* tree decomposition (TD) of the TD `tree_decomp`. + :meth:`make_nice_tree_decomposition` | Return a *nice* tree decomposition (TD) of the TD ``tree_decomp``. :meth:`label_nice_tree_decomposition` | Return a nice tree decomposition with nodes labelled accordingly. :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. :meth:`reduced_tree_decomposition` | Return a reduced tree-decomposition of `T`. @@ -830,7 +830,7 @@ def make_nice_tree_decomposition(graph, tree_decomp): .. WARNING:: - This method assumes that the vertices of the input tree `tree_decomp` + This method assumes that the vertices of the input tree ``tree_decomp`` are hashable and have attribute ``issuperset``, e.g., ``frozenset`` or :class:`~sage.sets.set.Set_object_enumerated_with_category`. diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index f0fb9329002..f50758496c4 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1566,7 +1566,7 @@ def tkz_picture(self): For a complicated vertex, a TeX box is used. :: sage: B = crystals.Tableaux(['B', 2], shape=[1]) - sage: latex(B) + sage: latex(B) # optional - !dot2tex \begin{tikzpicture} ... \newsavebox{\vertex} diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 2a9b8916c90..9e06d4ebfca 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -57,7 +57,6 @@ ``delete_multiedge()`` | Delete all edges from ``u`` to ``v``. ``disjoint_union()`` | Return the disjoint union of ``self`` and ``other``. ``disjunctive_product()`` | Return the disjunctive product of ``self`` and ``other``. - ``has_loops()`` | Return whether there are loops in the matching covered graph. ``is_biconnected()`` | Check if the matching covered graph is biconnected. ``is_block_graph()`` | Check whether the matching covered graph is a block graph. ``is_cograph()`` | Check whether the matching covered graph is cograph. @@ -69,12 +68,8 @@ ``join()`` | Return the join of ``self`` and ``other``. ``lexicographic_product()`` | Return the lexicographic product of ``self`` and ``other``. ``load_afile()`` | Load the matching covered graph specified in the given file into the current object. - ``loop_edges()`` | Return a list of all loops in the matching covered graph. - ``loop_vertices()`` | Return a list of vertices with loops. ``merge_vertices()`` | Merge vertices. - ``number_of_loops()`` | Return the number of edges that are loops. ``random_subgraph()`` | Return a random matching covered subgraph containing each vertex with probability ``p``. - ``remove_loops()`` | Remove loops on vertices in ``vertices``. ``save_afile()`` | Save the graph to file in alist format. ``strong_product()`` | Return the strong product of ``self`` and ``other``. ``subdivide_edge()`` | Subdivide an edge `k` times. @@ -89,16 +84,6 @@ ``transitive_reduction()`` | Return a transitive reduction of the matching covered graph. ``union()`` | Return the union of ``self`` and ``other``. - **Barriers and canonical partition** - - .. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - ``canonical_partition()`` | Return the canonical partition of the (matching covered) graph. - ``maximal_barrier()`` | Return the (unique) maximal barrier of the (matching covered) graph containing the (provided) vertex. - **Bricks, braces and tight cut decomposition** .. csv-table:: @@ -165,6 +150,7 @@ from sage.graphs.graph import Graph from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index + class MatchingCoveredGraph(Graph): r""" Matching covered graph @@ -1627,6 +1613,16 @@ def allow_loops(self, new, check=True): Traceback (most recent call last): ... ValueError: loops are not allowed in matching covered graphs + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ if new: raise ValueError('loops are not allowed in ' @@ -1658,9 +1654,97 @@ def allows_loops(self): sage: G = MatchingCoveredGraph(P) sage: G.allows_loops() False + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return False + @doc_index('Barriers and canonical partition') + def canonical_partition(self): + r""" + Return the canonical partition of the (matching covered) graph. + + For a matching covered graph `G`, a subset `B` of the vertex set `V` is + a barrier if `|B| = o(G - B)`, where `|B|` denotes the cardinality of + the set `B` and `o(G - B)` denotes the number of odd components in the + graph `G - B`. And a barrier `B` is a maximal barrier if `C` is not a + barrier for each `C` such that `B \subset C \subseteq V`. + + Note that in a matching covered graph, each vertex belongs to a unique + maximal barrier. The maximal barriers of a matching covered graph + partitions its vertex set and the partition of the vertex set of a + matching covered graph into its maximal barriers is called as its + *canonical* *partition*. + + OUTPUT: + + - A list of sets that constitute a (canonical) partition of the vertex + set, wherein each set is a (unique) maximal barrier of the (matching + covered) graph. + + EXAMPLES: + + Show the maximal barrier of the graph `K_4 \odot K_{3, 3}`:: + + sage: G = Graph([ + ....: (0, 2), (0, 3), (0, 4), (1, 2), + ....: (1, 3), (1, 4), (2, 5), (3, 6), + ....: (4, 7), (5, 6), (5, 7), (6, 7) + ....: ]) + sage: H = MatchingCoveredGraph(G) + sage: H.canonical_partition() + [{0}, {1}, {2, 3, 4}, {5}, {6}, {7}] + + For a bicritical graph (for instance, the Petersen graph), the + canonical parition constitutes of only singleton sets each containing + an individual vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.canonical_partition() + [{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}] + + For a bipartite matching covered graph (for instance, the Hexahedral + graph), the canonical partition consists of two sets each of which + corresponds to the individual color class:: + + sage: H = graphs.HexahedralGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.canonical_partition() + [{0, 2, 5, 7}, {1, 3, 4, 6}] + sage: B = BipartiteGraph(H) + sage: list(B.bipartition()) == G.canonical_partition() + True + + REFERENCES: + + - [LM2024]_ + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.graph.Graph.is_matching_covered` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.maximal_barrier` + """ + visited = set() + + maximal_barriers = [] + for v in self: + if v not in visited: + B = self.maximal_barrier(v) + visited.update(B) + maximal_barriers.append(B) + + return maximal_barriers + @doc_index('Overwritten methods') def delete_vertex(self, vertex, in_order=False): r""" @@ -1918,6 +2002,265 @@ def get_matching(self): """ return self._matching + @doc_index('Barriers and canonical partition') + def maximal_barrier(self, vertex): + r""" + Return the (unique) maximal barrier containing the vertex. + + For a matching covered graph `G`, a subset `B` of the vertex set `V` is + a barrier if `|B| = o(G - B)`, where `|B|` denotes the cardinality of + the set `B` and `o(G - B)` denotes the number of odd components in the + graph `G - B`. And a barrier `B` is a maximal barrier if `C` is not a + barrier for each `C` such that `B \subset C \subseteq V`. + + In a matching covered graph, each vertex belongs to a unique maximal + barrier, which is a consequence of the following theorem. + + .. RUBRIC:: Theorem [LM2024]_: + + Let `u` and `v` be any two vertices in a matchable graph `G`. Then the + graph `G - u - v` is matchable if and only if there is no barrier of + `G` which contains both `u` and `v`. + + And in order to find the vertices that do not lie in the maximal + barrier containing the provided vertex in linear time we take + inspiration of the `M` alternating tree seach method [LR2004]_. + + INPUT: + + - ``vertex`` -- a vertex of the graph + + OUTPUT: + + - A :exc:`~ValueError` is returned if ``vertex`` is not a vertex of the + graph, otherwise a set of vertices that constitute the (unique) + maximal barrier containing the vertex is returned. + + EXAMPLES: + + The graph `K_4 \odot K_{3, 3}` is matching covered. Show the set of + vertices in the (unique) maximal barrier containing the vertex `2`:: + + sage: G = Graph([ + ....: (0, 2), (0, 3), (0, 4), (1, 2), + ....: (1, 3), (1, 4), (2, 5), (3, 6), + ....: (4, 7), (5, 6), (5, 7), (6, 7) + ....: ]) + sage: H = MatchingCoveredGraph(G) + sage: B = H.maximal_barrier(2) + sage: B + {2, 3, 4} + + Let `B` be a maximal barrier of a matching covered graph `G` (which is, + of course, a matchable graph). The graph, `J := G - B` has no even + component:: + + sage: J = G.copy() + sage: J.delete_vertices(B) + sage: all(len(K)%2 != 0 for K in J.connected_components()) + ... + True + + Let `B` be a maximal barrier in a matching covered graph `G` and let + `M` be a perfect matching of `G`. If `K` is an odd component of + `J := G - B`, then `M \cap \partial_G(K)` has precisely one edge and if + `v` is the end of that edge in `V(K)`, then `M \cap E(K)` is a perfect + matching of `K - v`:: + + sage: K = J.subgraph(vertices=(J.connected_components())[0]) + sage: # Let F := \partial_G(K) and T := M \cap F + sage: F = [edge for edge in G.edge_iterator() + ....: if (edge[0] in K and edge[1] not in K) + ....: or (edge[0] not in K and edge[1] in K) + ....: ] + sage: M = H.get_matching() + sage: T = [edge for edge in F if edge in M] + sage: len(T) == 1 + True + sage: v = T[0][0] if T[0][0] in K else T[0][1] + sage: # Let N := M \cap E(K) and L := K - v + sage: N = Graph([edge for edge in K.edge_iterator() if edge in M]) + sage: L = K.copy() + sage: L.delete_vertex(v) + sage: # Check if N is a perfect matching of L + sage: L.order() == 2*N.size() + True + + Let `B` be a maximal barrier of a matching covered graph `G` (which is, + of course, a matchable graph). The graph induced by each component of + `G - B` is factor critical:: + + sage: all((K.subgraph(vertices=connected_component)).is_factor_critical() + ....: for connected_component in K.connected_components() + ....: ) + True + + For a bicritical graph (for instance, the Petersen graph), for each + vertex the maximal barrier is a singleton set containing only that + vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: u = 0 + sage: set([u]) == G.maximal_barrier(u) + True + + In a bipartite matching covered graph (for instance, the Hexahedral + graph), for a vertex, the maximal barrier is the set of vertices of + the color class that the particular vertex belongs to. In other words, + there are precisely two maximal barriers in a bipartite matching + covered graph, that is, the vertex sets of the individual color class:: + + sage: G = graphs.HexahedralGraph() + sage: H = MatchingCoveredGraph(G) + sage: A, _ = H.bipartite_sets() + sage: # needs random + sage: import random + sage: a = random.choice(list(A)) + sage: A == H.maximal_barrier(a) + True + + Maximal barriers of matching covered graph constitute a partition of + its vertex set:: + + sage: S = set() + sage: for v in H: + ....: B = tuple(sorted(list(H.maximal_barrier(v)))) + ....: S.add(B) + sage: S = list(S) + sage: # Check that S is a partition of the vertex set of H + sage: # Part 1: Check if S spans the vertex set of H + sage: sorted([u for B in S for u in B]) == sorted(list(H)) + True + sage: # Part 2: Check if each maximal barrier in S is disjoint + sage: is_disjoint = True + sage: for i in range(len(S)): + ....: for j in range(i+1, len(S)): + ....: c = [v for v in S[i] if v in S[j]] + ....: is_disjoint = (len(c) == 0) + sage: is_disjoint + True + + TESTS: + + Providing with a nonexistent vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.maximal_barrier('') + Traceback (most recent call last): + ... + ValueError: vertex not in the graph + sage: G.maximal_barrier(100) + Traceback (most recent call last): + ... + ValueError: vertex 100 not in the graph + + REFERENCES: + + - [LZ2004]_ + - [LM2024]_ + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.graph.Graph.is_matching_covered` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.canonical_partition` + """ + if vertex not in self: + raise ValueError('vertex {} not in the graph'.format(vertex)) + + # u: The M neighbor of vertex + matching = self.get_matching() + u = next((a if b == vertex else b) for a, b, *_ in matching if vertex in [a, b]) + + # Goal: Find the vertices w such that G - w - vertex is matchable. + # In other words, there exists an odd length M-alternating vertex-w + # path in G, starting and ending with edges in M. Alternatively, there + # exists an even length M-alternating u-w path in the graph G - vertex + # starting with an edge not in M and ending with and edge in M. + + # even: The set of all such vertex w + from sage.graphs.matching import M_alternating_even_mark + even = M_alternating_even_mark(G=self, matching=matching, + vertex=u) + + B = set([vertex]) + B.update(v for v in self if v not in even) + + return B + + @doc_index('Overwritten methods') + def has_loops(self): + r""" + Check whether there are loops in the (matching covered) graph. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.has_loops` method in + order to return ``False`` as matching covered graphs are always + free of looped edges. + + OUTPUT: + + - A boolean ``False`` is returned since matching covered graphs, by + definition, are free of self-loops. + + EXAMPLES: + + A matching covered graph, for instance the Petersen graph, is always free + of loops:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G + Matching covered petersen graph: graph on 10 vertices + sage: G.has_loops() + False + sage: G.allows_loops() + False + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: K = graphs.CompleteGraph(2) + sage: G = MatchingCoveredGraph(K) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered complete graph: multi-graph on 2 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.allows_loops() + False + sage: G.has_loops() + False + sage: G.allow_loops(True) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return False + @doc_index('Overwritten methods') def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -2003,6 +2346,323 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, raise ValueError('algorithm must be set to \'Edmonds\', ' '\'LP_matching\' or \'LP\'') + @doc_index('Overwritten methods') + def loop_edges(self, labels=True): + r""" + Return a list of all loops in the (matching covered) graph. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.loop_edges` method + in order to return an empty list as matching covered graphs are + free of looped edges. + + INPUT: + + - ``labels`` -- boolean (default: ``True``); whether returned edges + have labels (``(u,v,l)``) or not (``(u,v)``). + + OUTPUT: + + - A list capturing the edges that are loops in the matching covered + graph; note that, the list is empty since matching covered graphs do + not contain any looped edges. + + EXAMPLES: + + A matching covered graph, for instance the Heawood graph, by + definition, is always free of loops:: + + sage: H = graphs.HeawoodGraph() + sage: G = MatchingCoveredGraph(H) + sage: G + Matching covered heawood graph: graph on 14 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loops() + [] + sage: G.loop_edges() + [] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: C = graphs.CycleGraph(4) + sage: G = MatchingCoveredGraph(C) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered cycle graph: multi-graph on 4 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 3, None), (1, 2, None), (2, 3, None)] + sage: G.loops() + [] + sage: G.loop_edges() + [] + + One may set the ``label`` to either ``True`` or ``False``:: + + sage: G.loop_edges(labels=False) + [] + sage: G.loops(labels=True) + [] + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return [] + + @doc_index('Overwritten methods') + def loop_vertices(self): + r""" + Return a list of vertices with loops. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.loop_vertices` + method in order to return an empty list as matching covered graphs + are free of vertices that have looped edges. + + OUTPUT: + + - A list capturing the vertices that have loops in the matching covered + graph; note that, the list is empty since matching covered graphs do + not contain any looped edges. + + EXAMPLES: + + A matching covered graph, for instance the Möbius graph of order 8, by + definition, is always free of loops:: + + sage: M = graphs.MoebiusLadderGraph(4) + sage: G = MatchingCoveredGraph(M) + sage: G + Matching covered moebius ladder graph: graph on 8 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loop_vertices() + [] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: S = graphs.StaircaseGraph(4) + sage: G = MatchingCoveredGraph(S) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered staircase graph: multi-graph on 8 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 3, None), (0, 6, None), + (1, 2, None), (1, 4, None), (2, 5, None), (2, 7, None), + (3, 4, None), (3, 6, None), (4, 5, None), (5, 7, None), + (6, 7, None)] + sage: G.loop_vertices() + [] + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return [] + + loops = loop_edges + + @doc_index('Overwritten methods') + def number_of_loops(self): + r""" + Return the number of edges that are loops. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.number_of_loops` + method in order to return 0 as matching covered graphs are free + of looped edges. + + OUTPUT: + + - An integer, 0 is returned, since matching covered graphs do not + contain zero loops. + + EXAMPLES: + + A matching covered graph, for instance the Truncated biwheel graph, + by definition, is always free of loops:: + + sage: T = graphs.TruncatedBiwheelGraph(5) + sage: G = MatchingCoveredGraph(T) + sage: G + Matching covered truncated biwheel graph: graph on 10 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loop_vertices() + [] + sage: G.number_of_loops() + 0 + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: B = graphs.BiwheelGraph(4) + sage: G = MatchingCoveredGraph(B) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered biwheel graph: multi-graph on 8 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 5, None), (0, 7, None), + (1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), + (3, 4, None), (3, 6, None), (4, 5, None), (4, 7, None), + (5, 6, None)] + sage: G.loop_vertices() + [] + sage: G.number_of_loops() + 0 + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return 0 + + @doc_index('Overwritten methods') + def remove_loops(self, vertices=None): + r""" + Remove loops on vertices in ``vertices``. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.remove_loops` method + in order to return without any alteration as matching covered + graphs are free of looped edges. + + INPUT: + + - ``vertices`` -- (default: ``None``) iterator container of vertex + labels correponding to which the looped edges are to be removed. If + ``vertices`` is ``None``, remove all loops. + + OUTPUT: + + - Nothing is returned, as a matching covered graph is already devoid of + any loops. + + EXAMPLES: + + A matching covered graph, for instance the Wheel graph of order six, is + always free of loops:: + + sage: W = graphs.WheelGraph(6) + sage: G = MatchingCoveredGraph(W) + sage: G + Matching covered wheel graph: graph on 6 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.remove_loops() + sage: G.edges(sort=True) + [(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), + (0, 5, None), (1, 2, None), (1, 5, None), (2, 3, None), + (3, 4, None), (4, 5, None)] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: K = graphs.CompleteGraph(2) + sage: G = MatchingCoveredGraph(K) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered complete graph: multi-graph on 2 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=[0, 1]) + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=[0..100]) + + Note that the parameter ``vertices`` must be either ``None`` or an + iterable:: + + sage: G.remove_loops(vertices='') + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=None) + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=0) + Traceback (most recent call last): + ... + TypeError: 'Integer' object is not iterable + sage: G.remove_loops(vertices=False) + Traceback (most recent call last): + ... + TypeError: 'bool' object is not iterable + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + """ + from collections.abc import Iterable + + if vertices is not None and not isinstance(vertices, Iterable): + raise TypeError(f'\'{vertices.__class__.__name__}\' ' + 'object is not iterable') + + return + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" diff --git a/src/sage/graphs/meson.build b/src/sage/graphs/meson.build index d88f1942daf..28fbcaf24ef 100644 --- a/src/sage/graphs/meson.build +++ b/src/sage/graphs/meson.build @@ -1,5 +1,10 @@ bliss = cc.find_library('bliss', required: false, disabler: true) -mcqd = cc.find_library('mcqd', required: false, disabler: true) +# mcqd is a header-only library +if cc.has_header('mcqd.h') + mcqd = declare_dependency() +else + mcqd = disabler() +endif cliquer = cc.find_library('cliquer') # Cannot be found via pkg-config diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index ec5bc722d64..67a861555cb 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -365,6 +365,13 @@ def _normalize(n, gens_orders=None, names='f'): Traceback (most recent call last): ... TypeError: unable to convert 's' to an integer + + Verify that :issue:`38967` is fixed:: + + sage: AbelianGroup([-4]) + Traceback (most recent call last): + ... + ValueError: orders of generators cannot be negative but they are (-4,) """ if gens_orders is None: if isinstance(n, (list, tuple)): @@ -376,6 +383,8 @@ def _normalize(n, gens_orders=None, names='f'): if len(gens_orders) < n: gens_orders = [0] * (n - len(gens_orders)) + list(gens_orders) gens_orders = tuple(ZZ(i) for i in gens_orders) + if any(i < 0 for i in gens_orders): + raise ValueError(f'orders of generators cannot be negative but they are {gens_orders}') if len(gens_orders) > n: raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')') if isinstance(names, list): diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index b1e3cd1e0cb..190a0180d1b 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -30,15 +30,17 @@ - Volker Braun """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Volker Braun # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from copy import copy from sage.structure.element import Matrix from sage.misc.cachefunc import cached_method @@ -119,15 +121,17 @@ def __init__(self, parent, A, b=0, convert=True, check=True): A = A.matrix() except AttributeError: pass - if isinstance(A, Matrix) and A.nrows() == A.ncols() == parent.degree()+1: + if isinstance(A, Matrix) and A.nrows() == A.ncols() == parent.degree() + 1: g = A d = parent.degree() A = g.submatrix(0, 0, d, d) - b = [ g[i,d] for i in range(d) ] + b = [g[i,d] for i in range(d)] convert = True if convert: A = parent.matrix_space()(A) b = parent.vector_space()(b) + A.set_immutable() + b.set_immutable() if check: # Note: the coercion framework expects that we raise TypeError for invalid input if not isinstance(A, Matrix): @@ -138,6 +142,12 @@ def __init__(self, parent, A, b=0, convert=True, check=True): raise TypeError('b must be an element of ' + str(parent.vector_space())) parent._element_constructor_check(A, b) super().__init__(parent) + if not A.is_immutable(): + A = copy(A) + A.set_immutable() + if not b.is_immutable(): + b = copy(b) + b.set_immutable() self._A = A self._b = b @@ -151,10 +161,12 @@ def A(self): sage: G = AffineGroup(3, QQ) sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) - sage: g.A() + sage: A = g.A(); A [1 2 3] [4 5 6] [7 8 0] + sage: A.is_immutable() + True """ return self._A @@ -168,8 +180,10 @@ def b(self): sage: G = AffineGroup(3, QQ) sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) - sage: g.b() + sage: b = g.b(); b (10, 11, 12) + sage: b.is_immutable() + True """ return self._b @@ -345,7 +359,9 @@ def _mul_(self, other): parent = self.parent() A = self._A * other._A b = self._b + self._A * other._b - return parent.element_class(parent, A, b, check=False) + A.set_immutable() + b.set_immutable() + return parent.element_class(parent, A, b, convert=False, check=False) def __call__(self, v): """ @@ -439,13 +455,14 @@ def _act_on_(self, x, self_on_left): x |-> [0 1] x + [0] sage: v = vector(GF(3), [1,-1]); v (1, 2) - sage: g*v + sage: g * v (1, 2) - sage: g*v == g.A() * v + g.b() + sage: g * v == g.A() * v + g.b() True """ if self_on_left: return self(x) + return None def __invert__(self): """ @@ -472,7 +489,9 @@ def __invert__(self): parent = self.parent() A = parent.matrix_space()(~self._A) b = -A * self.b() - return parent.element_class(parent, A, b, check=False) + A.set_immutable() + b.set_immutable() + return parent.element_class(parent, A, b, convert=False, check=False) def _richcmp_(self, other, op): """ @@ -497,6 +516,27 @@ def _richcmp_(self, other, op): return richcmp(self._b, other._b, op) + def __hash__(self): + """ + Return the hash of ``self``. + + OUTPUT: int + + EXAMPLES:: + + sage: F = AffineGroup(3, QQ) + sage: g = F([1,2,3,4,5,6,7,8,0], [10,11,12]) + sage: h = F([1,2,3,4,5,6,7,8,0], [10,11,0]) + sage: hash(g) == hash(h) + False + sage: hash(g) == hash(copy(g)) + True + sage: f = g * h + sage: hash(f) == hash(~f) + False + """ + return hash((self._A, self._b)) + def list(self): """ Return list representation of ``self``. diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 8945175cf7a..ce0375b121f 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -67,36 +67,39 @@ ############################################################################## from itertools import combinations + +from sage.algebras.free_algebra import FreeAlgebra from sage.categories.action import Action from sage.categories.groups import Groups -from sage.combinat.permutation import Permutation -from sage.combinat.permutation import Permutations +from sage.combinat.permutation import Permutation, Permutations from sage.combinat.subset import Subsets from sage.features.sagemath import sage__libs__braiding +from sage.functions.generalized import sign from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement -from sage.groups.finitely_presented import FinitelyPresentedGroup -from sage.groups.finitely_presented import GroupMorphismWithGensImages +from sage.groups.finitely_presented import ( + FinitelyPresentedGroup, + GroupMorphismWithGensImages, +) from sage.groups.free_group import FreeGroup, is_FreeGroup -from sage.functions.generalized import sign -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.groups.perm_gps.permgroup_named import SymmetricGroupElement +from sage.groups.perm_gps.permgroup_named import SymmetricGroup, SymmetricGroupElement from sage.libs.gap.libgap import libgap from sage.matrix.constructor import identity_matrix, matrix +from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import -from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod from sage.rings.integer import Integer -from sage.rings.integer_ring import IntegerRing +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.sets.set import Set from sage.structure.element import Expression -from sage.structure.richcmp import richcmp, rich_to_bool +from sage.structure.richcmp import rich_to_bool, richcmp lazy_import('sage.libs.braiding', ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', - 'thurston_type', 'rigidity', 'sliding_circuits'], + 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', + 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings' ], feature=sage__libs__braiding()) lazy_import('sage.knots.knot', 'Knot') @@ -267,7 +270,7 @@ def burau_matrix(self, var='t', reduced=False): - :wikipedia:`Burau_representation` - [Squ1984]_ """ - R = LaurentPolynomialRing(IntegerRing(), var) + R = LaurentPolynomialRing(ZZ, var) t = R.gen() n = self.strands() if not reduced: @@ -418,7 +421,7 @@ def alexander_polynomial(self, var='t', normalized=True): """ n = self.strands() p = (self.burau_matrix(reduced=True) - identity_matrix(n - 1)).det() - K, t = LaurentPolynomialRing(IntegerRing(), var).objgen() + K, t = LaurentPolynomialRing(ZZ, var).objgen() if p == 0: return K.zero() qn = sum(t**i for i in range(n)) @@ -524,8 +527,8 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio Graphics object consisting of 12 graphics primitives """ from sage.plot.bezier_path import bezier_path - from sage.plot.plot import Graphics, line from sage.plot.colors import rainbow + from sage.plot.plot import Graphics, line if orientation == 'top-bottom': orx = 0 ory = -1 @@ -621,8 +624,8 @@ def plot3d(self, color='rainbow'): sage: b.plot3d(color=["red", "blue", "red", "blue"]) # needs sage.plot sage.symbolic Graphics3d Object """ - from sage.plot.plot3d.shapes2 import bezier3d from sage.plot.colors import rainbow + from sage.plot.plot3d.shapes2 import bezier3d b = [] n = self.strands() if isinstance(color, (list, tuple)): @@ -776,7 +779,7 @@ def TL_matrix(self, drain_size, variab=None, sparse=True): - [Jon2005]_ """ if variab is None: - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') else: R = variab.parent() rep = self.parent().TL_representation(drain_size, variab) @@ -857,7 +860,6 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): - [MW2012]_ """ - from sage.rings.integer_ring import ZZ if varnames is not None: poly = self.links_gould_polynomial(use_symbolics=use_symbolics) R = LaurentPolynomialRing(ZZ, varnames) @@ -935,7 +937,7 @@ def tropical_coordinates(self): coord[k+2] = x2 + sign*(min(y2, 0) + min(min(y1, 0) + sign*z, 0)) from sage.rings.semirings.tropical_semiring import TropicalSemiring - T = TropicalSemiring(IntegerRing()) + T = TropicalSemiring(ZZ) return [T(_) for _ in coord] def markov_trace(self, variab=None, normalized=True): @@ -980,9 +982,9 @@ def markov_trace(self, variab=None, normalized=True): Univariate Laurent Polynomial Ring in A over Integer Ring """ if variab is None: - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') A = R.gens()[0] - one = IntegerRing().one() + one = ZZ.one() quantum_integer = lambda d: R({i: one for i in range(-2*d, 2*d+1, 4)}) else: A = variab @@ -1125,7 +1127,6 @@ def jones_polynomial(self, variab=None, skein_normalization=False): else: return self._jones_polynomial(variab) else: - from sage.rings.integer_ring import ZZ if variab is None: variab = 't' if not isinstance(variab, Expression): @@ -1189,8 +1190,8 @@ def _enhanced_states(self): ((6, 0), [(2, [((1, 1), [], [([(0, 0), (1, 2)], 0), ([(0, 2), (1, 0)], 0)])])])] """ - from sage.graphs.graph import Graph from sage.functions.generalized import sgn + from sage.graphs.graph import Graph crossinglist = self.Tietze() ncross = len(crossinglist) writhe = 0 @@ -1326,7 +1327,7 @@ def _annular_khovanov_complex_cached(self, qagrad, ring=None): """ from sage.homology.chain_complex import ChainComplex if ring is None: - ring = IntegerRing() + ring = ZZ states = self._enhanced_states() if qagrad in states: bases = states[qagrad] @@ -1402,13 +1403,13 @@ def annular_khovanov_complex(self, qagrad=None, ring=None): 0: []} """ if ring is None: - ring = IntegerRing() + ring = ZZ if qagrad is None: return {qa: self._annular_khovanov_complex_cached(qa, ring) for qa in self._enhanced_states()} return self._annular_khovanov_complex_cached(qagrad, ring) - def annular_khovanov_homology(self, qagrad=None, ring=IntegerRing()): + def annular_khovanov_homology(self, qagrad=None, ring=ZZ): r""" Return the annular Khovanov homology of a closure of a braid. @@ -1743,7 +1744,7 @@ def conjugating_braid(self, other): cb[0][0] %= 2 return B._element_from_libbraiding(cb) - def is_conjugated(self, other): + def is_conjugated(self, other) -> bool: """ Check if the two braids are conjugated. @@ -1908,7 +1909,7 @@ def thurston_type(self): """ return thurston_type(self) - def is_reducible(self): + def is_reducible(self) -> bool: """ Check whether the braid is reducible. @@ -1924,7 +1925,7 @@ def is_reducible(self): """ return self.thurston_type() == 'reducible' - def is_periodic(self): + def is_periodic(self) -> bool: """ Check whether the braid is periodic. @@ -1940,9 +1941,9 @@ def is_periodic(self): """ return self.thurston_type() == 'periodic' - def is_pseudoanosov(self): + def is_pseudoanosov(self) -> bool: """ - Check if the braid is pseudo-anosov. + Check if the braid is pseudo-Anosov. EXAMPLES:: @@ -2093,24 +2094,24 @@ def deformed_burau_matrix(self, variab='q'): sage: burau.subs({t:q}).change_ring(db_base) == db_simp True """ - R = LaurentPolynomialRing(IntegerRing(), variab) + R = LaurentPolynomialRing(ZZ, variab) + n = self.strands() tz = self.Tietze() - m = len(tz) - from sage.algebras.free_algebra import FreeAlgebra - alg = FreeAlgebra(R, m*3, - [f'{s}p_{i}' for i in range(m) if tz[i] > 0 - for s in 'bca'] - + [f'{s}m_{i}' for i in range(m) if tz[i] < 0 - for s in 'bca']) - gen_indices = ([i for i in range(m) if tz[i] > 0] - + [i for i in range(m) if tz[i] < 0]) - - M = identity_matrix(alg, n) + m3 = len(tz) * 3 + plus = [i for i, tzi in enumerate(tz) if tzi > 0] + minus = [i for i, tzi in enumerate(tz) if tzi < 0] + gens_str = [f'{s}p_{i}' for i in plus for s in 'bca'] + gens_str += [f'{s}m_{i}' for i in minus for s in 'bca'] + alg_ZZ = FreeAlgebra(ZZ, m3, gens_str) + gen_indices = {k: i for i, k in enumerate(plus + minus)} + gens = [alg_ZZ.gens()[k:k + 3] for k in range(0, m3, 3)] + + M = identity_matrix(alg_ZZ, n) for k, i in enumerate(tz): - A = identity_matrix(alg, n) - gen_index = gen_indices.index(k) - b, c, a = alg.gens()[3*gen_index:3*gen_index+3] + A = identity_matrix(alg_ZZ, n) + b, c, a = gens[gen_indices[k]] + # faster using row operations instead ? if i > 0: A[i-1, i-1] = a A[i, i] = 0 @@ -2122,7 +2123,9 @@ def deformed_burau_matrix(self, variab='q'): A[-1-i, -i] = c A[-i, -1-i] = b M = M * A - return M + + alg_R = FreeAlgebra(R, m3, gens_str) + return M.change_ring(alg_R) def _colored_jones_sum(self, N, qword): r""" @@ -2147,23 +2150,19 @@ def _colored_jones_sum(self, N, qword): """ rqword = RightQuantumWord(qword).reduced_word() alg = qword.parent() - R = alg.base_ring() - result = R.one() + result = alg.base_ring().one() current_word = alg.one() - i = 1 - continue_summing = True # This seemingly infinite sum is always finite if the qword comes # from a sum of quantum determinants; because at some point # the break condition will become true. - while continue_summing: + while True: current_word *= rqword - new_rqw = RightQuantumWord(alg(current_word)) + new_rqw = RightQuantumWord(current_word) current_word = new_rqw.reduced_word() new_eps = new_rqw.eps(N) - result += new_eps if not new_eps: - continue_summing = False - i += 1 + break + result += new_eps return result def colored_jones_polynomial(self, N, variab=None, try_inverse=True): @@ -2213,7 +2212,7 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): if variab is None: return cj if isinstance(variab, str): - variab = LaurentPolynomialRing(IntegerRing(), variab).gen() + variab = LaurentPolynomialRing(ZZ, variab).gen() return cj.subs(q=variab) db = self.deformed_burau_matrix('q')[1:, 1:] @@ -2239,6 +2238,90 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): self._cj_with_q[N] = cj.subs({q: 1/q}) if use_inverse else cj return self.colored_jones_polynomial(N, variab, try_inverse) + def super_summit_set_element(self): + r""" + Return an element of the braid's super summit set and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, 1, 3]) + sage: b.super_summit_set_element() + (s0*s2*s0*s1*s2*s1*s0, s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s1*s0*s2*s1*s0) + """ + to_sss = send_to_sss(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_sss]) + + def ultra_summit_set_element(self): + r""" + Return an element of the braid's ultra summit set and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.ultra_summit_set_element() + (s0*s1*s0*s2*s1, s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s1*s2*s1^2*s0) + """ + to_uss = send_to_uss(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_uss]) + + def sliding_circuits_element(self): + r""" + Return an element of the braid's sliding circuits, and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.sliding_circuits_element() + (s0*s1*s0*s2*s1, s0^2*s1*s2) + """ + to_sc = send_to_sc(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_sc]) + + def trajectory(self): + r""" + Return the braid's trajectory. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.trajectory() + [s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s2*s0*s1*s2*s1*s0^2*s1*s2^2, + s0*s1*s2^3, + s0*s1*s2*s1^2, + s0*s1*s0*s2*s1] + """ + traj = trajectory(self) + B = self.parent() + return [B._element_from_libbraiding(b) for b in traj] + + def cyclic_slidings(self): + r""" + Return the braid's cyclic slidings. + + OUTPUT: The braid's cyclic slidings. Each cyclic sliding is a list of braids. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, 1]) + sage: b.cyclic_slidings() + [[s0*s2*s1*s0*s1*s2, s0*s1*s2*s1*s0^2, s1*s0*s2^2*s1*s0], + [s0*s1*s2*s1^2*s0, s0*s1*s2*s1*s0*s2, s1*s0*s2*s0*s1*s2]] + """ + cs = cyclic_slidings(self) + B = self.parent() + return [[B._element_from_libbraiding(b) for b in t] for t in cs] + class RightQuantumWord: """ @@ -2286,12 +2369,15 @@ def __init__(self, words): """ self._algebra = words.parent() self.q = self._algebra.base_ring().gen() + self.iq = ~self.q self.R = self._algebra.base_ring() self._unreduced_words = words self._gens = self._algebra._indices.gens() - self._gens_index = {g: i for i, g in enumerate(self._gens)} self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), - default=len(self._gens)) + default=len(self._gens)) // 3 + split = ((g, str(g), i) for i, g in enumerate(self._gens)) + self._recognize = {g: (s[0], s[1] == 'm', 3 * (i // 3)) + for g, s, i in split} @lazy_attribute def tuples(self): @@ -2327,24 +2413,25 @@ def tuples(self): """ from collections import defaultdict ret = defaultdict(self.R) + convert = self._recognize + q = self.q + iq = self.iq for unreduced_monom, q_power in list(self._unreduced_words): - q = self.q ret_tuple = [0] * len(self._gens) for gen, exp in unreduced_monom: - gen_index = self._gens_index[gen] - is_minus = bool(gen_index >= self._minus_begin) - index = gen_index // 3 + letter, is_minus, index = convert[gen] # This uses the relations in equations (4.1) and (4.2) # of [HL2018]_. - i, j, k = ret_tuple[3*index: 3*index + 3] - if not (gen_index + 1) % 3: # is_a - ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] - if not gen_index % 3: # is_b - ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] - q_power *= q**(2*(k*exp + j*exp)) if is_minus else q**(-2*j*exp) - if not (gen_index + 2) % 3: # is_c - ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] - q_power *= q**(-k*exp) if is_minus else q**(k*exp) + if letter == 'a': # is_a + ret_tuple[index + 2] += exp + elif letter == 'b': # is_b + j, k = ret_tuple[index + 1:index + 3] + ret_tuple[index] += exp + q_power *= q**(2*(k*exp + j*exp)) if is_minus else iq**(2*j*exp) + else: # is_c + k = ret_tuple[index + 2] + ret_tuple[index + 1] += exp + q_power *= iq**(k*exp) if is_minus else q**(k*exp) ret[tuple(ret_tuple)] += q_power return ret @@ -2414,7 +2501,7 @@ def eps(self, N): sage: from sage.groups.braid import RightQuantumWord sage: B = BraidGroup(3) sage: b = B([1,-2,1,2]) - sage: db = b.deformed_burau_matrix()[:, :] + sage: db = b.deformed_burau_matrix() sage: q = db.parent().base_ring().base_ring().gen() sage: (bp_0, cp_0, ap_0, ....: bp_2, cp_2, ap_2, @@ -2443,16 +2530,16 @@ def eps_monom(q_tuple): """ q = self.q ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] - for i in range(self._minus_begin//3)) + for i in range(self._minus_begin)) ret_q *= q**sum((N - 1)*(-q_tuple[rj]) - for rj in range(self._minus_begin + 1, + for rj in range(self._minus_begin * 3 + 1, len(q_tuple), 3)) ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) for h in range(q_tuple[3*i + 2])) - for i in range(self._minus_begin//3)) + for i in range(self._minus_begin)) ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + k + 1 - N) for k in range(q_tuple[3*j + 2])) - for j in range(self._minus_begin//3, + for j in range(self._minus_begin, len(q_tuple)//3)) return ret_q @@ -2756,17 +2843,15 @@ def _links_gould_representation(self, symbolics=False): d = 4 # dimension of the natural module from sage.matrix.special import diagonal_matrix if symbolics: - from sage.symbolic.ring import SR as BR - from sage.calculus.var import var from sage.misc.functional import sqrt - t0, t1 = var('t0, t1') + from sage.symbolic.ring import SR as BR + t0, t1 = BR.var('t0, t1') s0 = sqrt(t0) s1 = sqrt(t1) Y = sqrt(-(t0 - 1)*(t1 - 1)) sparse = False else: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.rings.integer_ring import ZZ LR = LaurentPolynomialRing(ZZ, 's0r, s1r') PR = PolynomialRing(LR, 'Yr') s0r, s1r, Yr = PR.gens_dict_recursive().values() @@ -2865,7 +2950,7 @@ def _LKB_matrix_(self, braid, variab): A = A*self._LKB_matrix_((i,), variab) return A n2 = [set(X) for X in combinations(range(n), 2)] - R = LaurentPolynomialRing(IntegerRing(), variab) + R = LaurentPolynomialRing(ZZ, variab) q = R.gens()[0] t = R.gens()[1] if not braid: @@ -3215,7 +3300,7 @@ def TL_representation(self, drain_size, variab=None): if variab is None: if drain_size in self._TL_representation_dict: return self._TL_representation_dict[drain_size] - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') A = R.gens()[0] else: R = variab.parent() diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index e407b9d1326..94bdf4c12e5 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -371,7 +371,7 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, - ``root_bur`` -- six (resp. twelfth) root of unity in some field (default: root of unity over `\QQ`) - ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp. - the domain of `root_bur` if given) base ring for the Burau matrix + the domain of ``root_bur`` if given) base ring for the Burau matrix - ``characteristic`` -- integer giving the characteristic of the domain (default: 0 or the characteristic of ``domain`` if given) - ``var`` -- string used for the indeterminate name in case ``root_bur`` @@ -640,7 +640,6 @@ class CubicBraidGroup(UniqueRepresentation, FinitelyPresentedGroup): sage: C3.gens() (t0, t1) sage: U3.is_isomorphic(C3) - #I Forcing finiteness test True sage: U3.as_classical_group() Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), @@ -1604,7 +1603,6 @@ def as_permutation_group(self, use_classical=True): sage: C3 = CubicBraidGroup(3) sage: PC3 = C3.as_permutation_group() sage: assert C3.is_isomorphic(PC3) # random (with respect to the occurrence of the info message) - #I Forcing finiteness test sage: PC3.degree() 8 sage: c = C3([2,1-2]) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 9b5f7e422d6..b65566ebeb4 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1080,7 +1080,6 @@ def direct_product(self, H, reduced=False, new_names=True): sage: C7 = G / [G.0**7]; C6 = G / [G.0**6] sage: C14 = G / [G.0**14]; C3 = G / [G.0**3] sage: C7.direct_product(C6).is_isomorphic(C14.direct_product(C3)) - #I Forcing finiteness test True sage: F = FreeGroup(2); D = F / [F([1,1,1,1,1]),F([2,2]),F([1,2])**2] sage: D.direct_product(D).as_permutation_group().is_isomorphic( @@ -1174,7 +1173,6 @@ def semidirect_product(self, H, hom, check=True, reduced=False): sage: alpha = (Q.gens(), [a,b]) sage: S2 = C2.semidirect_product(Q, ([C2.0],[alpha])) sage: S1.is_isomorphic(S2) - #I Forcing finiteness test True Dihedral groups can be constructed as semidirect products @@ -1233,8 +1231,6 @@ def semidirect_product(self, H, hom, check=True, reduced=False): sage: Se2 = D.semidirect_product(C ,id2) sage: Dp1 = C.direct_product(D) sage: Dp1.is_isomorphic(Se1), Dp1.is_isomorphic(Se2) - #I Forcing finiteness test - #I Forcing finiteness test (True, True) Most checks for validity of input are left to GAP to handle:: diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index 940d761ef49..20d847be0dd 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -451,7 +451,6 @@ def QuaternionPresentation(): sage: Q.order(), Q.is_abelian() (8, False) sage: Q.is_isomorphic(groups.presentation.DiCyclic(2)) - #I Forcing finiteness test True """ F = FreeGroup(['a','b']) @@ -554,12 +553,6 @@ def BinaryDihedralPresentation(n): ....: P = groups.presentation.BinaryDihedral(n) ....: M = groups.matrix.BinaryDihedral(n) ....: assert P.is_isomorphic(M) - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test """ F = FreeGroup('x,y,z') x,y,z = F.gens() diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 69acc7c654d..5b207f423c6 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -1502,12 +1502,18 @@ def has_order(P, n, operation='+'): sage: has_order(x, -8) False + Check for :issue:`38708`:: + + sage: has_order(Mod(2,3), int(2), operation='*') + True + .. NOTE:: In some cases, order *testing* can be much faster than *computing* the order using :func:`order_from_multiple`. """ - if isinstance(n, sage.rings.integer.Integer): + if not isinstance(n, sage.structure.factorization.Factorization): + n = integer_ring.ZZ(n) if n <= 0: return False n = n.factor() diff --git a/src/sage/groups/group.pxd b/src/sage/groups/group.pxd index 8a38ba4b583..462099d77fd 100644 --- a/src/sage/groups/group.pxd +++ b/src/sage/groups/group.pxd @@ -11,4 +11,3 @@ cdef class FiniteGroup(Group): cdef class AlgebraicGroup(Group): pass - diff --git a/src/sage/groups/libgap_mixin.py b/src/sage/groups/libgap_mixin.py index 3491c9f9db0..b14b050bd3b 100644 --- a/src/sage/groups/libgap_mixin.py +++ b/src/sage/groups/libgap_mixin.py @@ -946,4 +946,16 @@ def is_isomorphic(self, H): sage: F == G, G == H, F == H (False, False, False) """ - return self.gap().IsomorphismGroups(H.gap()) != libgap.fail + # If GAP doesn't know that the groups are finite, it will + # check. This emits an informational warning, and then + # annotates the groups as being finite (assuming they were) so + # that future isomorphism checks are silent. This can lead to + # apparent non-determinism in the output as statements are + # rearranged. There's nothing the user can do about this + # anyway, and it happens in trivial cases like the alternating + # group on one element, so we prefer to hide the warning. + old_warnlevel = libgap.InfoLevel(libgap.InfoWarning) + libgap.SetInfoLevel(libgap.InfoWarning, 0) + result = self.gap().IsomorphismGroups(H.gap()) != libgap.fail + libgap.SetInfoLevel(libgap.InfoWarning, old_warnlevel) + return result diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 43c2ef98770..61c1151452b 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -1461,9 +1461,22 @@ def __pow__(self, exponent): 1 sage: S(-1)^3 # indirect doctest -1 + + Check that the results may live in other parents too:: + + sage: x = SR.var('x') + sage: elem = S(-1)^x; elem # indirect doctest + (-1)^x + sage: elem.parent() + Symbolic Ring + """ + result = self._element_ ** exponent P = self.parent() - return P.element_class(P, self._element_ ** exponent) + try: + return P.element_class(P, result) + except (ValueError, TypeError): + return result def __invert__(self): r""" diff --git a/src/sage/groups/old.pxd b/src/sage/groups/old.pxd index 3409c5b1764..b141cd6d1a3 100644 --- a/src/sage/groups/old.pxd +++ b/src/sage/groups/old.pxd @@ -11,4 +11,3 @@ cdef class FiniteGroup(Group): cdef class AlgebraicGroup(Group): pass - diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 7603da471f9..a9a24f2b26c 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -1422,7 +1422,7 @@ def __richcmp__(self, other, op): return NotImplemented return richcmp(self._state, other._state, op) - def solve(self, algorithm='hybrid', timeout=15): + def solve(self, algorithm='default', timeout=15): r""" Solve the Rubik's cube. @@ -1430,17 +1430,14 @@ def solve(self, algorithm='hybrid', timeout=15): - ``algorithm`` -- must be one of the following: - - ``hybrid`` -- try ``kociemba`` for timeout seconds, then ``dietz`` - - ``kociemba`` -- use Dik T. Winter's program - (reasonable speed, few moves) - - ``dietz`` -- use Eric Dietz's cubex program - (fast but lots of moves) - - ``optimal`` -- use Michael Reid's optimal program - (may take a long time) + - ``hybrid`` -- (default) try ``kociemba`` for timeout seconds, then ``dietz`` + - ``kociemba`` -- use Dik T. Winter's program (reasonable speed, few moves) + - ``dietz`` -- use Eric Dietz's cubex program (fast but lots of moves) + - ``optimal`` -- use Michael Reid's optimal program (may take a long time) - ``gap`` -- use GAP word solution (can be slow) - Any choice other than ``gap`` requires the optional package - ``rubiks``. Otherwise, the ``gap`` algorithm is used. + Any choice other than ``gap`` requires the optional package ``rubiks``. + If the package is not installed, the ``gap`` algorithm is used by default. EXAMPLES:: @@ -1452,7 +1449,10 @@ def solve(self, algorithm='hybrid', timeout=15): solutions:: sage: s = C.solve('dietz'); s # optional - rubiks - "U' L' L' U L U' L U D L L D' L' D L' D' L D L' U' L D' L' U L' B' U' L' U B L D L D' U' L' U L B L B' L' U L U' L' F' L' F L' F L F' L' D' L' D D L D' B L B' L B' L B F' L F F B' L F' B D' D' L D B' B' L' D' B U' U' L' B' D' F' F' L D F'" + "U' L' L' U L U' L U D L L D' L' D L' D' L D L' U' L D' L' U L' B' + U' L' U B L D L D' U' L' U L B L B' L' U L U' L' F' L' F L' F L F' + L' D' L' D D L D' B L B' L B' L B F' L F F B' L F' B D' D' L D B' + B' L' D' B U' U' L' B' D' F' F' L D F'" sage: C2 = RubiksCube(s) # optional - rubiks sage: C == C2 # optional - rubiks True @@ -1460,11 +1460,11 @@ def solve(self, algorithm='hybrid', timeout=15): from sage.features.rubiks import Rubiks if Rubiks().is_present(): import sage.interfaces.rubik # here to avoid circular referencing + if algorithm == 'default': + algorithm = "hybrid" else: - algorithm = 'gap' - - if algorithm == "default": - algorithm = "hybrid" + if algorithm == 'default': + algorithm = 'gap' if algorithm == "hybrid": try: diff --git a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd index 8996dcaf509..fde91d1d0f6 100644 --- a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +++ b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd @@ -82,4 +82,3 @@ cdef iterator *setup_canonical_generator(int degree, iterator *cangen_prealloc) except NULL cdef iterator *start_canonical_generator(StabilizerChain *, void *, int, iterator *) except NULL - diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd index 2cf087e9915..6ef14648081 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +++ b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd @@ -28,4 +28,3 @@ cdef class MatrixStruct: cdef int refine_matrix(PartitionStack *, void *, int *, int) noexcept cdef int compare_matrices(int *, int *, void *, void *, int) noexcept cdef bint all_matrix_children_are_equivalent(PartitionStack *, void *) noexcept - diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 60f2ccc77f2..ee30f144282 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -1434,6 +1434,7 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): return [[i_k] + l for i_k in range(S_k, i_k_plus_one) for l in sum_indices(k-1, i_k, S_k)] + def is_GF2(R): r""" Return ``True`` iff ``R`` is isomorphic to the field `\GF{2}`. diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 7aa5ac779d9..a41ba32b393 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -496,6 +496,7 @@ def quadratic_equation(A, B, C): r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" html(calc % (B, dis1, A, B, dis2, (2*A), sol)) + @library_interact( a0=lambda: slider(0, 360, 1, 30, label='A'), a1=lambda: slider(0, 360, 1, 180, label='B'), diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 7d1ac74b7c1..74d51dbb51e 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -57,6 +57,7 @@ from sage.env import SAGE_ECMBIN + class ECM(SageObject): def __init__(self, B1=10, B2=None, **kwds): diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 6f2fb118968..bd1095e8c70 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -880,7 +880,7 @@ def _reduce(self): Special care has to be taken with strings. Since for example `r("abc")` will be interpreted as the R-command abc (not a string in R), we have to reduce to - `"'abc'"` instead. That is dependant on the Elements `is_string` function to + `"'abc'"` instead. That is dependant on the Elements ``is_string`` function to be implemented correctly. This has gone wrong in the past and remained uncaught by the doctests because the original identifier was reused. This test makes sure that does not happen again:: diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 39c3aff9dc2..488a1fb1af5 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -454,7 +454,7 @@ def clean_output(s): def _un_camel(name): """ - Convert `CamelCase` to `camel_case`. + Convert ``CamelCase`` to ``camel_case``. EXAMPLES:: diff --git a/src/sage/interfaces/mathics.py b/src/sage/interfaces/mathics.py index a6d39ad3c14..58a376b9c72 100644 --- a/src/sage/interfaces/mathics.py +++ b/src/sage/interfaces/mathics.py @@ -402,7 +402,7 @@ def _mathics_sympysage_symbol(self): This function replaces ``_sympysage_symbol`` to take care of the special names used in Mathics. - It is set to the method `_sage_` of the Sympy class + It is set to the method ``_sage_`` of the Sympy class :class:`sympy.core.symbol.Sympol`. EXAMPLES:: diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 1b1e97f3578..a8ba86ae3d0 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -35,7 +35,7 @@ classical Maxima Pexpect interface in case no new implementation has been made. This interface is the one used for calculus by Sage -and is accessible as `maxima_calculus`:: +and is accessible as ``maxima_calculus``:: sage: maxima_calculus Maxima_lib @@ -80,8 +80,8 @@ TESTS: Check our workaround for a race in ecl works, see :issue:`26968`. -We use a temporary `MAXIMA_USERDIR` so it's empty; we place it -in `DOT_SAGE` since we expect it to have more latency than `/tmp`. +We use a temporary ``MAXIMA_USERDIR`` so it's empty; we place it +in ``DOT_SAGE`` since we expect it to have more latency than ``/tmp``. sage: import tempfile, subprocess sage: tmpdir = tempfile.TemporaryDirectory(dir=DOT_SAGE) diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index aaa01cdade9..607c73085aa 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -30,6 +30,8 @@ from sage.categories.monoids import Monoids # We need Link to be first in the MRO in order to use its equality, hash, etc. + + class Knot(Link, Element, metaclass=InheritComparisonClasscallMetaclass): r""" A knot. diff --git a/src/sage/libs/braiding.pyx b/src/sage/libs/braiding.pyx index fb856c918c9..6bfdea11dc4 100644 --- a/src/sage/libs/braiding.pyx +++ b/src/sage/libs/braiding.pyx @@ -41,6 +41,11 @@ cdef extern from "braiding.h" namespace "Braiding": int thurstontype(int n, list[int] word) int Rigidity_ext(int n, list[int] word) list[list[list[list[int]]]] SlidingCircuits(int n, list[int] word) + list[list[list[int]]] SendToSSS(int n, list[int] word) + list[list[list[int]]] SendToUSS(int n, list[int] word) + list[list[list[int]]] SendToSC(int n, list[int] word) + list[list[list[int]]] Trajectory(int n, list[int] word) + list[list[list[list[int]]]] CyclicSlidings(int n, list[int] word) def conjugatingbraid(braid1, braid2): @@ -383,3 +388,161 @@ def sliding_circuits(braid): cdef list[list[list[list[int]]]] rop = SlidingCircuits(nstrands, l) sig_off() return rop + + +def send_to_sss(braid): + r""" + Return an element of the braid's super summit set and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` super summit + set, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_sss + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2,- 3]) + sage: send_to_sss(d) + [[[0], [1, 2, 1, 3]], [[-1], [1, 2, 3, 2]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToSSS(nstrands, l) + sig_off() + return rop + + +def send_to_uss(braid): + r""" + Return an element of the braid's ultra summit set and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` ultra summit + set, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_uss + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2,- 1]) + sage: send_to_uss(d) + [[[0], [1, 2, 3, 2]], [[0], [1]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToUSS(nstrands, l) + sig_off() + return rop + + +def send_to_sc(braid): + r""" + Return an element of the braid's sliding circuits and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` sliding + circuits, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_sc + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: send_to_sc(d) + [[[0], [1, 2, 3, 2], [2, 1]], [[0], [1]]] + + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToSC(nstrands, l) + sig_off() + return rop + + +def trajectory(braid): + r""" + Return the braid's trajectory. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list of braids, formed by the ``braid```trajectory. + + EXAMPLES:: + + sage: from sage.libs.braiding import trajectory + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: trajectory(d) + [[[0], [1, 3], [1, 2, 3, 2]], + [[0], [1, 2, 3, 2, 1], [3]], + [[0], [1, 2, 3, 2], [2, 1]], + [[0], [2, 1, 3], [1, 2, 3]]] + + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = Trajectory(nstrands, l) + sig_off() + return rop + + +def cyclic_slidings(braid): + r""" + Return the cyclic slidings of the braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list of lists of braids, given by the input's cyclic slidings. + + EXAMPLES:: + + sage: from sage.libs.braiding import cyclic_slidings + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: cyclic_slidings(d) + [[[[0], [1, 2, 3, 2], [2, 1]], + [[0], [1, 2, 3, 2, 1], [3]], + [[0], [2, 1, 3], [1, 2, 3]]], + [[[0], [1, 3, 2, 1], [2, 3]], + [[0], [1, 2, 3, 2, 1], [1]], + [[0], [2, 1, 3], [3, 2, 1]]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[list[int]]]] rop = CyclicSlidings(nstrands, l) + sig_off() + return rop diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 845feb2fd38..858a0f24d6e 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -279,7 +279,7 @@ def m(self, i, j): """ from sage.misc.superseded import deprecation deprecation(30237, "the .m(i, j) method has been deprecated; use .coxeter_matrix()[i,j] instead.") - return self.coxeter_matrix()[i,j] + return self.coxeter_matrix()[i, j] def kazhdan_lusztig_polynomial(self, u, v, constant_term_one=True): r""" @@ -354,8 +354,9 @@ def kazhdan_lusztig_polynomial(self, u, v, constant_term_one=True): return p ZZq = PolynomialRing(ZZ, 'q', sparse=True) # This is the same as q**len_diff * p(q**(-2)) - len_diff = v.length()-u.length() - d = {-2*deg+len_diff: coeff for deg,coeff in enumerate(p) if coeff != 0} + len_diff = v.length() - u.length() + d = {-2 * deg + len_diff: coeff for deg, coeff in enumerate(p) + if coeff != 0} return ZZq(d) def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): @@ -414,11 +415,11 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): WOI = self.weak_order_ideal(lambda x: J_set.issuperset(x.descents())) if constant_term_one: P = PolynomialRing(ZZ, 'q') - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v) - for z in WOI if (u*z).bruhat_le(v)) + return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v) + for z in WOI if (u * z).bruhat_le(v)) P = PolynomialRing(ZZ, 'q', sparse=True) - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v, constant_term_one=False).shift(z.length()) - for z in WOI if (u*z).bruhat_le(v)) + return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v, constant_term_one=False).shift(z.length()) + for z in WOI if (u * z).bruhat_le(v)) class Element(ElementWrapper): wrapped_class = CoxGroupElement @@ -701,7 +702,7 @@ def action_on_rational_function(self, f): for exponent in exponents: # Construct something in the root lattice from the exponent vector - exponent = sum(e*b for e, b in zip(exponent, basis_elements)) + exponent = sum(e * b for e, b in zip(exponent, basis_elements)) exponent = self.action(exponent) monomial = 1 diff --git a/src/sage/libs/eclib/constructor.py b/src/sage/libs/eclib/constructor.py index 79d28b90c1c..37df4eb935b 100644 --- a/src/sage/libs/eclib/constructor.py +++ b/src/sage/libs/eclib/constructor.py @@ -1,5 +1,6 @@ "Cremona modular symbols" + def CremonaModularSymbols(level, sign=0, cuspidal=False, verbose=0): """ Return the space of Cremona modular symbols with given level, sign, etc. diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py index a5e65a37d4d..1cdaebc93e4 100644 --- a/src/sage/libs/eclib/interface.py +++ b/src/sage/libs/eclib/interface.py @@ -31,6 +31,7 @@ from .mwrank import _Curvedata, _two_descent, _mw, parse_point_list + class mwrank_EllipticCurve(SageObject): r""" The :class:`mwrank_EllipticCurve` class represents an elliptic @@ -246,8 +247,11 @@ def __repr__(self): """ a1, a2, a3, a4, a6 = self.__ainvs # we do not assume a1, a2, a3 are reduced to {0,1}, {-1,0,1}, {0,1} - coeff = lambda a: ''.join([" +" if a > 0 else " -", - " " + str(abs(a)) if abs(a) > 1 else ""]) + + def coeff(a): + return ''.join([" +" if a > 0 else " -", + " " + str(abs(a)) if abs(a) > 1 else ""]) + return ''.join(['y^2', ' '.join([coeff(a1), 'xy']) if a1 else '', ' '.join([coeff(a3), 'y']) if a3 else '', @@ -267,21 +271,28 @@ def two_descent(self, verbose=True, selmer_only=False, first_limit=20, - ``selmer_only`` -- boolean (default: ``False``); ``selmer_only`` switch - - ``first_limit`` -- integer (default: 20); bound on `|x|+|z|` in - quartic point search - - - ``second_limit`` -- integer (default: 8); bound on - `\log \max(|x|,|z|)`, i.e. logarithmic - - - ``n_aux`` -- integer (default: -1); (only relevant for general - 2-descent when 2-torsion trivial) number of primes used for - quartic search. ``n_aux=-1`` causes default (8) to be used. - Increase for curves of higher rank. - - - ``second_descent`` -- boolean (default: ``True``); (only relevant - for curves with 2-torsion, where mwrank uses descent via - 2-isogeny) flag determining whether or not to do second - descent. *Default strongly recommended.* + - ``first_limit`` -- integer (default: 20); naive height bound on + first point search on quartic homogeneous spaces (before + testing local solubility; very simple search with no + overheads). + + - ``second_limit`` -- integer (default: 8); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search) + + - ``n_aux`` -- integer (default: -1); if positive, the number of + auxiliary primes used in sieve-assisted search for quartics. + If -1 (the default) use a default value (set in the eclib + code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). + Only relevant for curves with no 2-torsion, where full + 2-descent is carried out. Worth increasing for curves + expected to be of rank > 6 to one or two more than the + expected rank. + + - ``second_descent`` -- boolean (default: ``True``); flag specifying + whether or not a second descent will be carried out. Only relevant + for curves with 2-torsion. Recommended left as the default except for + experts interested in details of Selmer groups. OUTPUT: nothing @@ -606,12 +617,14 @@ def certain(self): """ return bool(self.__two_descent_data().getcertain()) - #def fullmw(self): - # return self.__two_descent_data().getfullmw() + # def fullmw(self): + # return self.__two_descent_data().getfullmw() def CPS_height_bound(self): r""" - Return the Cremona-Prickett-Siksek height bound. This is a + Return the Cremona-Prickett-Siksek height bound. + + This is a floating point number `B` such that if `P` is a point on the curve, then the naive logarithmic height `h(P)` is less than `B+\hat{h}(P)`, where `\hat{h}(P)` is the canonical height of @@ -1282,9 +1295,9 @@ def search(self, height_limit=18, verbose=False): """ height_limit = float(height_limit) int_bits = sys.maxsize.bit_length() - max_height_limit = int_bits * 0.693147 # log(2.0) = 0.693147 approx + max_height_limit = int_bits * 0.693147 # log(2.0) = 0.693147 approx if height_limit >= max_height_limit: - raise ValueError("The height limit must be < {} = {}log(2) on a {}-bit machine.".format(max_height_limit, int_bits, int_bits+1)) + raise ValueError("The height limit must be < {} = {}log(2) on a {}-bit machine.".format(max_height_limit, int_bits, int_bits + 1)) moduli_option = 0 # Use Stoll's sieving program... see strategies in ratpoints-1.4.c diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 5bc54a04cdc..4a2ca04e55f 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -992,29 +992,11 @@ cdef class _two_descent: points. Useful as a faster way of getting an upper bound on the rank. - - ``firstlim`` -- integer (default: 20); naive height bound on - first point search on quartic homogeneous spaces (before - testing local solubility; very simple search with no - overheads). - - - ``secondlim`` -- integer (default: 8); naive height bound on - second point search on quartic homogeneous spaces (after - testing local solubility; sieve-assisted search) - - - ``n_aux`` -- integer (default: -1); if positive, the number of - auxiliary primes used in sieve-assisted search for quartics. - If -1 (the default) use a default value (set in the eclib - code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). - Only relevant for curves with no 2-torsion, where full - 2-descent is carried out. Worth increasing for curves - expected to be of rank > 6 to one or two more than the - expected rank. - - - ``second_descent`` -- integer (default: 1); flag specifying - whether or not a second descent will be carried out (yes if - 1, the default; no if 0). Only relevant for curves with - 2-torsion. Recommended left as the default except for - experts interested in details of Selmer groups. + - ``firstlim``, ``secondlim``, ``n_aux``, ``second_descent`` -- + see ``first_limit``, ``second_limit``, ``n_aux``, ``second_descent`` + respectively in :meth:`~sage.libs.eclib.interface.mwrank_EllipticCurve.two_descent` + (although ``second_descent`` here is ``1`` or ``0`` instead of ``True`` or ``False`` + respectively) OUTPUT: none diff --git a/src/sage/libs/gap/gap_globals.py b/src/sage/libs/gap/gap_globals.py index 4c3e6eb3aae..f8061a173a2 100644 --- a/src/sage/libs/gap/gap_globals.py +++ b/src/sage/libs/gap/gap_globals.py @@ -15,34 +15,34 @@ # selected gap globals to use in tab completion -common_gap_globals = set([ - 'Assert', - 'Cyclotomics', - 'GaussianIntegers', - 'GaussianRationals', - 'GlobalMersenneTwister', - 'GlobalRandomSource', - 'InfoAlgebra', - 'InfoAttributes', - 'InfoBckt', - 'InfoCharacterTable', - 'InfoCoh', - 'InfoComplement', - 'InfoCoset', - 'InfoFpGroup', - 'InfoGroebner', - 'InfoGroup', - 'InfoLattice', - 'InfoMatrix', - 'InfoMonomial', - 'InfoNumtheor', - 'InfoOptions', - 'InfoPackageLoading', - 'InfoPcSubgroup', - 'InfoWarning', - 'Integers', - 'NiceBasisFiltersInfo', - 'Primes', - 'Rationals', - 'TableOfMarksComponents' -]) | common_gap_functions +common_gap_globals = { + 'Assert', + 'Cyclotomics', + 'GaussianIntegers', + 'GaussianRationals', + 'GlobalMersenneTwister', + 'GlobalRandomSource', + 'InfoAlgebra', + 'InfoAttributes', + 'InfoBckt', + 'InfoCharacterTable', + 'InfoCoh', + 'InfoComplement', + 'InfoCoset', + 'InfoFpGroup', + 'InfoGroebner', + 'InfoGroup', + 'InfoLattice', + 'InfoMatrix', + 'InfoMonomial', + 'InfoNumtheor', + 'InfoOptions', + 'InfoPackageLoading', + 'InfoPcSubgroup', + 'InfoWarning', + 'Integers', + 'NiceBasisFiltersInfo', + 'Primes', + 'Rationals', + 'TableOfMarksComponents' +} | common_gap_functions diff --git a/src/sage/libs/gap/test_long.py b/src/sage/libs/gap/test_long.py index c92ff9d5223..262f3b00e28 100644 --- a/src/sage/libs/gap/test_long.py +++ b/src/sage/libs/gap/test_long.py @@ -28,7 +28,7 @@ def test_loop_2(): G = libgap.FreeGroup(2) a, b = G.GeneratorsOfGroup() for i in range(100): - rel = libgap([a**2, b**2, a*b*a*b]) + rel = libgap([a**2, b**2, a * b * a * b]) H = G / rel H1 = H.GeneratorsOfGroup()[0] n = H1.Order() diff --git a/src/sage/libs/giac/__init__.py b/src/sage/libs/giac/__init__.py index ba0be068152..49bbe254947 100644 --- a/src/sage/libs/giac/__init__.py +++ b/src/sage/libs/giac/__init__.py @@ -287,7 +287,7 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, return PolynomialSequence([P(0)], P, immutable=True) # check for name confusions - blackgiacconstants = ['i', 'e'] # NB e^k is expanded to exp(k) + blackgiacconstants = ['i', 'e'] # NB e^k is expanded to exp(k) blacklist = blackgiacconstants + [str(j) for j in libgiac.VARS()] problematicnames = sorted(set(P.gens_dict()).intersection(blacklist)) @@ -336,8 +336,8 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, var_names = var_names[:len(blocks[0])] else: raise NotImplementedError( - "%s is not a supported term order in " - "Giac Groebner bases." % P.term_order()) + "%s is not a supported term order in " + "Giac Groebner bases." % P.term_order()) # compute de groebner basis with giac gb_giac = F.gbasis(list(var_names), giac_order) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 91c42f3132c..65279b16504 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -102,6 +102,13 @@ TESTS:: sage: libgiac(-11^1000) -2469932918005826334124088385085221477709733385238396234869182951830739390375433175367866116456946191973803561189036523363533798726571008961243792655536655282201820357872673322901148243453211756020067624545609411212063417307681204817377763465511222635167942816318177424600927358163388910854695041070577642045540560963004207926938348086979035423732739933235077042750354729095729602516751896320598857608367865475244863114521391548985943858154775884418927768284663678512441565517194156946312753546771163991252528017732162399536497445066348868438762510366191040118080751580689254476068034620047646422315123643119627205531371694188794408120267120500325775293645416335230014278578281272863450085145349124727476223298887655183167465713337723258182649072572861625150703747030550736347589416285606367521524529665763903537989935510874657420361426804068643262800901916285076966174176854351055183740078763891951775452021781225066361670593917001215032839838911476044840388663443684517735022039957481918726697789827894303408292584258328090724141496484460001 +Ensure that signed infinities get converted correctly:: + + sage: libgiac(+Infinity) + +infinity + sage: libgiac(-Infinity) + -infinity + .. SEEALSO:: ``libgiac``, ``giacsettings``, ``Pygen``,``loadgiacgen`` @@ -159,6 +166,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer cimport Integer +from sage.rings.infinity import AnInfinity from sage.rings.rational cimport Rational from sage.structure.element cimport Matrix @@ -860,6 +868,8 @@ cdef class Pygen(GiacMethods_base): s = s._giac_init_() except AttributeError: s = SRexpressiontoGiac(s) + elif isinstance(s, AnInfinity): + s = s._giac_init_() if not isinstance(s, str): s = s.__str__() sig_on() diff --git a/src/sage/libs/gmp/mpq.pxd b/src/sage/libs/gmp/mpq.pxd index 068988ffbc4..19d94b32808 100644 --- a/src/sage/libs/gmp/mpq.pxd +++ b/src/sage/libs/gmp/mpq.pxd @@ -55,4 +55,3 @@ cdef extern from "gmp.h": # Input and Output Functions # size_t mpq_out_str (file *stream, int base, mpq_t op) # size_t mpq_inp_str (mpq_t rop, file *stream, int base) - diff --git a/src/sage/libs/m4ri.pxd b/src/sage/libs/m4ri.pxd index 7fbdd35b856..1306b72a74c 100644 --- a/src/sage/libs/m4ri.pxd +++ b/src/sage/libs/m4ri.pxd @@ -179,6 +179,9 @@ cdef extern from "m4ri/m4ri.h": # reduced row echelon form using PLUQ factorization cdef mzd_t *mzd_kernel_left_pluq(mzd_t *A, int cutoff) + # system solving + cdef int mzd_solve_left(mzd_t *A, mzd_t *B, int cutoff, int inconsistency_check) + ######################## # Bit operations ######################## @@ -192,4 +195,3 @@ cdef extern from "m4ri/m4ri.h": ################################## cdef void mzd_clear_bits(mzd_t *m, int x, int y, int n) - diff --git a/src/sage/libs/meson.build b/src/sage/libs/meson.build index 61b36da51f5..2e28ef8ff79 100644 --- a/src/sage/libs/meson.build +++ b/src/sage/libs/meson.build @@ -36,7 +36,7 @@ foreach name, pyx : extension_data if name == 'sirocco' deps += [sirocco] elif name == 'meataxe' - deps += [mtx, meataxe] + deps += [mtx] endif py.extension_module( diff --git a/src/sage/libs/ntl/ZZ_pX.pxd b/src/sage/libs/ntl/ZZ_pX.pxd index 8c9f609f1cd..4c6895581dd 100644 --- a/src/sage/libs/ntl/ZZ_pX.pxd +++ b/src/sage/libs/ntl/ZZ_pX.pxd @@ -119,4 +119,3 @@ cdef extern from "ntlwrap_impl.h": void ZZ_pX_right_pshift(ZZ_pX_c x, ZZ_pX_c a, ZZ_c pn, ZZ_pContext_c c) void ZZ_pX_InvMod_newton_unram(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F, ZZ_pContext_c cpn, ZZ_pContext_c cp) void ZZ_pX_InvMod_newton_ram(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F, ZZ_pContext_c cpn) - diff --git a/src/sage/libs/ntl/ntl_GF2E.pxd b/src/sage/libs/ntl/ntl_GF2E.pxd index c36292c8748..f12777b16c9 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pxd +++ b/src/sage/libs/ntl/ntl_GF2E.pxd @@ -5,4 +5,3 @@ cdef class ntl_GF2E(): cdef GF2E_c x cdef ntl_GF2EContext_class c cdef ntl_GF2E _new(self) - diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index ccb18792918..b5bc281db4d 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -173,6 +173,7 @@ 3.60546360143265208591582056420772677481026899659802474544 # 32-bit """ + def _get_pari_instance(): """ TESTS:: @@ -181,8 +182,8 @@ def _get_pari_instance(): Interface to the PARI C library """ from cypari2 import Pari - stack_initial = 1024*1024 - stack_max = 1024*stack_initial + stack_initial = 1024 * 1024 + stack_max = 1024 * stack_initial P = Pari(stack_initial, stack_max) # pari_init_opts() overrides MPIR's memory allocation functions, diff --git a/src/sage/libs/singular/standard_options.py b/src/sage/libs/singular/standard_options.py index 476961b2f09..cdd81edf74c 100644 --- a/src/sage/libs/singular/standard_options.py +++ b/src/sage/libs/singular/standard_options.py @@ -6,6 +6,7 @@ - Martin Albrecht """ + class LibSingularGBDefaultContext: def __init__(self): """ @@ -95,7 +96,8 @@ def __exit__(self, typ, value, tb): b - 3*d^6 + 2*d^4 + d^3 + 2*d^2 - 3*d, a - 2*d^6 + d^5 - 2*d^4 + 3*d^3 + 3*d^2 - 2*d - 1] """ - self.libsingular_option_context.__exit__(typ,value,tb) + self.libsingular_option_context.__exit__(typ, value, tb) + def libsingular_gb_standard_options(func): r""" diff --git a/src/sage/manifolds/all.py b/src/sage/manifolds/all.py index e219a98dc32..425199da31a 100644 --- a/src/sage/manifolds/all.py +++ b/src/sage/manifolds/all.py @@ -1,4 +1,5 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.manifolds.manifold', 'Manifold') lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') lazy_import('sage.manifolds', 'catalog', 'manifolds') diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index a4888559c0f..f7193b12c16 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -19,13 +19,15 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** +from sage.manifolds.utilities import ( + simplify_chain_generic, + simplify_chain_generic_sympy, + simplify_chain_real, + simplify_chain_real_sympy, +) +from sage.misc.latex import latex from sage.structure.sage_object import SageObject from sage.symbolic.ring import SR -from sage.manifolds.utilities import (simplify_chain_real, - simplify_chain_generic, - simplify_chain_real_sympy, - simplify_chain_generic_sympy,) -from sage.misc.latex import latex try: import sympy diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index c3c40c42b9a..fb6ba5634f2 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -34,6 +34,7 @@ # Lazy import from examples folders: from sage.misc.lazy_import import lazy_import as _lazy_import + _lazy_import('sage.manifolds.differentiable.examples.real_line', 'OpenInterval') _lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine') _lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') @@ -172,9 +173,9 @@ def Kerr(m=1, a=0, coordinates='BL', names=None): sage: K.default_chart().coord_range() t: (-oo, +oo); r: (0, +oo); th: (0, pi); ph: [-pi, pi] (periodic) """ - from sage.misc.functional import sqrt from sage.functions.trig import cos, sin from sage.manifolds.manifold import Manifold + from sage.misc.functional import sqrt M = Manifold(4, 'M', structure='Lorentzian') if coordinates == "Kerr": if names is None: @@ -252,8 +253,8 @@ def Torus(R=2, r=1, names=None): gamma = dtheta⊗dtheta + (cos(theta)^2 + 6*cos(theta) + 9) dphi⊗dphi """ from sage.functions.trig import cos, sin - from sage.manifolds.manifold import Manifold from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace + from sage.manifolds.manifold import Manifold E = EuclideanSpace(3, symbols='X Y Z') M = Manifold(2, 'T', ambient=E, structure='Riemannian') if names is None: diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py index d0d3148be7e..f20a0e2bab4 100644 --- a/src/sage/manifolds/chart.py +++ b/src/sage/manifolds/chart.py @@ -36,16 +36,16 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.ext.fast_callable import fast_callable +from sage.manifolds.calculus_method import CalculusMethod +from sage.manifolds.chart_func import ChartFunctionRing +from sage.misc.decorators import options +from sage.misc.latex import latex +from sage.rings.infinity import Infinity from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.ring import SR -from sage.rings.infinity import Infinity -from sage.misc.latex import latex -from sage.misc.decorators import options -from sage.manifolds.chart_func import ChartFunctionRing -from sage.manifolds.calculus_method import CalculusMethod from sage.symbolic.expression import Expression -from sage.ext.fast_callable import fast_callable +from sage.symbolic.ring import SR class Chart(UniqueRepresentation, SageObject): @@ -1216,7 +1216,7 @@ def preimage(self, codomain_subset, name=None, latex_name=None): sage: R((-2,)) in McZ True """ - from .subsets.pullback import ManifoldSubsetPullback + from sage.manifolds.subsets.pullback import ManifoldSubsetPullback return ManifoldSubsetPullback(self, codomain_subset, name=name, latex_name=latex_name) @@ -2053,9 +2053,9 @@ def codomain(self): sage: c_spher1.codomain() The Cartesian product of ((0, +oo), (0, pi), [0, 2*pi)) """ - from sage.sets.real_set import RealSet - from sage.modules.free_module import VectorSpace from sage.categories.cartesian_product import cartesian_product + from sage.modules.free_module import VectorSpace + from sage.sets.real_set import RealSet intervals = tuple(RealSet.interval(xmin, xmax, lower_closed=(min_included == 'periodic' or min_included), upper_closed=(max_included != 'periodic' and max_included)) @@ -2554,7 +2554,7 @@ def valid_coordinates_numerical(self, *coordinates): return self._fast_valid_coordinates(*coordinates) # case fast callable has to be computed - from operator import lt, gt + from operator import gt, lt if not isinstance(self._restrictions, (list, set, frozenset)): if isinstance(self._restrictions, tuple): @@ -3003,11 +3003,11 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, sage: X.plot.reset() """ + from sage.manifolds.continuous_map import ContinuousMap + from sage.manifolds.utilities import set_axes_labels from sage.misc.functional import numerical_approx from sage.plot.graphics import Graphics from sage.plot.line import line - from sage.manifolds.continuous_map import ContinuousMap - from sage.manifolds.utilities import set_axes_labels # Extract the kwds options max_range = kwds['max_range'] diff --git a/src/sage/manifolds/chart_func.py b/src/sage/manifolds/chart_func.py index aae7a2b1fff..77006d5459a 100644 --- a/src/sage/manifolds/chart_func.py +++ b/src/sage/manifolds/chart_func.py @@ -32,16 +32,16 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import AlgebraElement, ModuleElementWithMutability -from sage.structure.parent import Parent -from sage.structure.sage_object import SageObject -from sage.structure.unique_representation import UniqueRepresentation from sage.categories.commutative_algebras import CommutativeAlgebras from sage.manifolds.utilities import ExpressionNice from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import -from sage.symbolic.ring import SR +from sage.structure.element import AlgebraElement, ModuleElementWithMutability from sage.structure.mutability import Mutability +from sage.structure.parent import Parent +from sage.structure.sage_object import SageObject +from sage.structure.unique_representation import UniqueRepresentation +from sage.symbolic.ring import SR try: import sympy @@ -671,8 +671,8 @@ def display(self): sage: X.zero_function().display() (x, y) ↦ 0 """ - from sage.typeset.unicode_characters import unicode_mapsto from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import unicode_mapsto curr = self._calc_method._current expr = self.expr(curr) if (curr == 'SR' and diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index 2c30b796aab..d8158deb1ce 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -843,7 +843,7 @@ def image(self, subset=None, inverse=None): sage: Phi_S.is_subset(M) True """ - from .continuous_map_image import ImageManifoldSubset + from sage.manifolds.continuous_map_image import ImageManifoldSubset if self._is_identity: if subset is None: return self.domain() @@ -1166,8 +1166,8 @@ def display(self, chart1=None, chart2=None): \end{array} """ from sage.misc.latex import latex - from sage.typeset.unicode_characters import unicode_to, unicode_mapsto from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import unicode_mapsto, unicode_to def _display_expression(self, chart1, chart2, result): r""" @@ -2045,8 +2045,8 @@ def __invert__(self): sage: si == s True """ - from sage.symbolic.ring import SR from sage.symbolic.relation import solve + from sage.symbolic.ring import SR if self._inverse is not None: return self._inverse if not self._is_isomorphism: diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 73b6e5d42cd..a52c82ee1cc 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -28,12 +28,12 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.rings.integer import Integer -from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.misc.cachefunc import cached_method from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism +from sage.rings.integer import Integer +from sage.structure.sage_object import SageObject class AffineConnection(SageObject): @@ -603,8 +603,8 @@ def _new_coef(self, frame): sage: nab._new_coef(X.frame()) 3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y)) """ - from sage.tensor.modules.comp import Components from sage.manifolds.differentiable.scalarfield import DiffScalarField + from sage.tensor.modules.comp import Components return Components(frame._domain.scalar_field_algebra(), frame, 3, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) @@ -1306,8 +1306,8 @@ def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, Gam^ph_ph,r = 1/r Gam^ph_ph,th = cos(th)/sin(th) """ - from sage.misc.latex import latex from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.misc.latex import latex if frame is None: frame = self._domain.default_frame() if chart is None: @@ -1503,8 +1503,7 @@ def __call__(self, tensor): :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` for more examples. """ - from sage.manifolds.differentiable.tensorfield_paral import \ - TensorFieldParal + from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.tensor.modules.format_utilities import format_unop_latex dom_resu = self._domain.intersection(tensor._domain) tensor_r = tensor.restrict(dom_resu) diff --git a/src/sage/manifolds/differentiable/automorphismfield.py b/src/sage/manifolds/differentiable/automorphismfield.py index 3556fc56e95..c8f2143beb2 100644 --- a/src/sage/manifolds/differentiable/automorphismfield.py +++ b/src/sage/manifolds/differentiable/automorphismfield.py @@ -24,9 +24,9 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism class AutomorphismField(TensorField): @@ -1168,9 +1168,9 @@ def __invert__(self): sage: b is ~a True """ + from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.matrix.constructor import matrix from sage.tensor.modules.comp import Components - from sage.manifolds.differentiable.vectorframe import CoordFrame if self._is_identity: return self if self._inverse is None: diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index c6315670c9e..45a2fad087a 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -38,15 +38,19 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.groups import Groups +from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, + AutomorphismFieldParal, +) +from sage.manifolds.differentiable.vectorfield_module import ( + VectorFieldFreeModule, + VectorFieldModule, +) from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.free_module_linear_group import FreeModuleLinearGroup -from sage.manifolds.differentiable.vectorfield_module import (VectorFieldModule, - VectorFieldFreeModule) -from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) class AutomorphismFieldGroup(UniqueRepresentation, Parent): diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 184e9641eeb..35d70c2e847 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -38,11 +38,10 @@ # https://www.gnu.org/licenses/ # ****************************************************************************** -from sage.structure.sage_object import SageObject -from sage.structure.mutability import Mutability +from sage.manifolds.differentiable.vector_bundle import DifferentiableVectorBundle from sage.rings.integer import Integer -from sage.manifolds.differentiable.vector_bundle import \ - DifferentiableVectorBundle +from sage.structure.mutability import Mutability +from sage.structure.sage_object import SageObject class BundleConnection(SageObject, Mutability): diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 51f32ffb4b8..63d0384e149 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -282,16 +282,16 @@ from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement -from sage.misc.fast_methods import Singleton -from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method +from sage.manifolds.differentiable.affine_connection import AffineConnection +from sage.manifolds.differentiable.bundle_connection import BundleConnection +from sage.manifolds.differentiable.levi_civita_connection import LeviCivitaConnection from sage.misc.abstract_method import abstract_method -from .affine_connection import AffineConnection -from .bundle_connection import BundleConnection -from .levi_civita_connection import LeviCivitaConnection -from sage.symbolic.expression import Expression +from sage.misc.cachefunc import cached_method +from sage.misc.fast_methods import Singleton from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.sage_object import SageObject +from sage.symbolic.expression import Expression class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): @@ -795,7 +795,7 @@ def _element_constructor_(self, x, **kwargs): Characteristic cohomology class pontr(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M """ - if isinstance(x, (str, Expression)) or isinstance(x, Polynomial): + if isinstance(x, (str, Expression, Polynomial)): return self._build_element(x, **kwargs) R = self.base_ring() @@ -894,7 +894,7 @@ def _build_element(self, *args, **kwargs): # predefined classes accessible via class names if isinstance(val, str): - from sage.arith.misc import factorial, bernoulli + from sage.arith.misc import bernoulli, factorial P = PolynomialRing(base_ring, 'x') x = P.gen() @@ -1085,8 +1085,8 @@ def multiplicative_sequence(q, n=None): e[] + e[1] - e[1, 1] + 3*e[2] - e[2, 1] + e[2, 2] + 4*e[3] - 3*e[3, 1] + e[3, 2] + 7*e[4] - 4*e[4, 1] + 11*e[5] """ - from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.misc_c import prod if n is None: @@ -1140,8 +1140,8 @@ def additive_sequence(q, k, n=None): sage: sym_1 = additive_sequence(f, 2, 1); sym_1 2*e[] + e[1] """ - from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + from sage.combinat.sf.sf import SymmetricFunctions if n is None: n = q.degree() @@ -1427,7 +1427,7 @@ def get_local(self, cmat): sage: algorithm.get_local(cmat) [2-form on the 2-dimensional Lorentzian manifold M] """ - from sage.symbolic.constants import pi, I + from sage.symbolic.constants import I, pi dom = cmat[0][0]._domain rk = len(cmat) diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py index bcfa37dc237..c944a9d7815 100644 --- a/src/sage/manifolds/differentiable/chart.py +++ b/src/sage/manifolds/differentiable/chart.py @@ -31,9 +31,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.manifolds.chart import Chart, RealChart, CoordChange +from sage.manifolds.chart import Chart, CoordChange, RealChart from sage.manifolds.differentiable.vectorframe import CoordFrame +from sage.misc.cachefunc import cached_method class DiffChart(Chart): diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index e28e44b8adb..8a1cfc2e77e 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -32,10 +32,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.latex import latex -from sage.misc.decorators import options -from sage.manifolds.point import ManifoldPoint from sage.manifolds.differentiable.diff_map import DiffMap +from sage.manifolds.point import ManifoldPoint +from sage.misc.decorators import options +from sage.misc.latex import latex class DifferentiableCurve(DiffMap): @@ -871,9 +871,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) sphinx_plot(g) """ - from sage.rings.infinity import Infinity - from sage.misc.functional import numerical_approx from sage.manifolds.chart import RealChart + from sage.misc.functional import numerical_approx + from sage.rings.infinity import Infinity # # Get the @options from kwds @@ -995,9 +995,9 @@ def _graphics(self, plot_curve, ambient_coords, thickness=1, sage: graph._extra_kwds['axes_labels'] == l True """ + from sage.manifolds.utilities import set_axes_labels from sage.plot.graphics import Graphics from sage.plot.line import line - from sage.manifolds.utilities import set_axes_labels # # The plot diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index 9bc766f5a78..729ed375afa 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -45,13 +45,15 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.algebras import Algebras +from sage.manifolds.differentiable.characteristic_cohomology_class import ( + CharacteristicCohomologyClassRing, + CharacteristicCohomologyClassRingElement, +) from sage.misc.cachefunc import cached_method -from sage.structure.parent import Parent from sage.structure.element import AlgebraElement -from sage.categories.algebras import Algebras -from .characteristic_cohomology_class import (CharacteristicCohomologyClassRing, - CharacteristicCohomologyClassRingElement) +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class DeRhamCohomologyClass(AlgebraElement): diff --git a/src/sage/manifolds/differentiable/degenerate.py b/src/sage/manifolds/differentiable/degenerate.py index b34fefc3a89..80da669f083 100644 --- a/src/sage/manifolds/differentiable/degenerate.py +++ b/src/sage/manifolds/differentiable/degenerate.py @@ -11,11 +11,12 @@ # ***************************************************************************** from __future__ import annotations + from typing import TYPE_CHECKING -from sage.rings.infinity import infinity -from sage.manifolds.structure import DegenerateStructure from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import DegenerateStructure +from sage.rings.infinity import infinity if TYPE_CHECKING: from sage.manifolds.differentiable.metric import DegenerateMetric @@ -368,8 +369,8 @@ def open_subset(self, name, latex_name=None, coord_def={}): #******************************************************************************************* -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal class TangentTensor(TensorFieldParal): diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index a119fb57802..fcb843a8abe 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -156,17 +156,17 @@ # ***************************************************************************** from __future__ import annotations + from typing import TYPE_CHECKING -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold -from sage.manifolds.differentiable.degenerate import (DegenerateManifold, - TangentTensor) -from sage.manifolds.differentiable.differentiable_submanifold import \ - DifferentiableSubmanifold +from sage.manifolds.differentiable.degenerate import DegenerateManifold, TangentTensor +from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, +) +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.rings.infinity import infinity from sage.matrix.constructor import matrix +from sage.rings.infinity import infinity from sage.symbolic.expression import Expression if TYPE_CHECKING: diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index fb58189796e..0457b815d8a 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -44,16 +44,18 @@ # ***************************************************************************** from __future__ import annotations -from typing import Optional, Union, TYPE_CHECKING -from sage.misc.cachefunc import cached_method -from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm + +from typing import TYPE_CHECKING, Optional, Union + from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.misc.cachefunc import cached_method +from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm if TYPE_CHECKING: - from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule from sage.manifolds.differentiable.metric import PseudoRiemannianMetric from sage.manifolds.differentiable.symplectic_form import SymplecticForm + from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule class DiffForm(TensorField): @@ -442,8 +444,8 @@ def exterior_derivative(self) -> DiffForm: True """ from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) vmodule = self._vmodule # shortcut @@ -525,8 +527,8 @@ def wedge(self, other: DiffForm) -> DiffForm: """ if other._tensor_rank == 0: return self * other - from sage.typeset.unicode_characters import unicode_wedge from sage.tensor.modules.format_utilities import is_atomic + from sage.typeset.unicode_characters import unicode_wedge if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior product") @@ -762,8 +764,8 @@ def hodge_dual( """ from sage.functions.other import factorial from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) if nondegenerate_tensor is None: @@ -1438,10 +1440,12 @@ def exterior_derivative(self) -> DiffFormParal: sage: a.lie_der(v) == v.contract(diff(a)) + diff(a(v)) # long time True """ - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) - from sage.tensor.modules.comp import CompFullyAntiSym from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.tensor.modules.comp import CompFullyAntiSym + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index ee0dd856697..d79686fb7b6 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -38,14 +38,14 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.modules import Modules -from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule from sage.tensor.modules.reflexive_module import ReflexiveModule_abstract @@ -863,7 +863,9 @@ def _coerce_map_from_(self, other): and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain)) - from sage.manifolds.differentiable.tensorfield_module import TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldFreeModule, + ) if isinstance(other, TensorFieldFreeModule): # coercion of a type-(0,1) tensor to a linear form return (self._fmodule is other._fmodule and self._degree == 1 diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index ec0f30be82c..433993d36ad 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -408,14 +408,13 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.functions.trig import cos, sin, atan2 +from sage.categories.manifolds import Manifolds +from sage.categories.metric_spaces import MetricSpaces +from sage.functions.trig import atan2, cos, sin +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold from sage.misc.functional import sqrt from sage.misc.latex import latex from sage.rings.real_mpfr import RR -from sage.categories.manifolds import Manifolds -from sage.categories.metric_spaces import MetricSpaces -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold ############################################################################### @@ -696,8 +695,9 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, symbols = ' '.join(names) # Technical bit for UniqueRepresentation - from sage.misc.prandom import getrandbits from time import time + + from sage.misc.prandom import getrandbits if unique_tag is None: unique_tag = getrandbits(128) * time() @@ -1035,7 +1035,7 @@ def sphere(self, radius=1, center=None, name=None, latex_name=None, n = self._dim if n == 1: raise ValueError('Euclidean space must have dimension of at least 2') - from .sphere import Sphere + from sage.manifolds.differentiable.examples.sphere import Sphere return Sphere(n-1, radius=radius, ambient_space=self, center=center, name=name, latex_name=latex_name, coordinates=coordinates, names=names) diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index 52b3dfad182..ef71608529e 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -24,14 +24,14 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.categories.manifolds import Manifolds +from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import RealDifferentialStructure from sage.misc.latex import latex from sage.rings.infinity import infinity, minus_infinity -from sage.symbolic.ring import SR from sage.rings.real_mpfr import RR +from sage.symbolic.ring import SR from sage.typeset.unicode_characters import unicode_mathbbR -from sage.manifolds.differentiable.manifold import DifferentiableManifold -from sage.manifolds.structure import RealDifferentialStructure -from sage.categories.manifolds import Manifolds class OpenInterval(DifferentiableManifold): diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 43956a3ba1a..f1add71e110 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -165,13 +165,14 @@ eps_g = -dchi """ -from sage.manifolds.differentiable.pseudo_riemannian_submanifold import \ - PseudoRiemannianSubmanifold -from sage.categories.metric_spaces import MetricSpaces from sage.categories.manifolds import Manifolds +from sage.categories.metric_spaces import MetricSpaces from sage.categories.topological_spaces import TopologicalSpaces -from sage.rings.real_mpfr import RR from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace +from sage.manifolds.differentiable.pseudo_riemannian_submanifold import ( + PseudoRiemannianSubmanifold, +) +from sage.rings.real_mpfr import RR class Sphere(PseudoRiemannianSubmanifold): @@ -315,8 +316,9 @@ def __classcall_private__(cls, n=None, radius=1, ambient_space=None, n = len(names) # Technical bit for UniqueRepresentation - from sage.misc.prandom import getrandbits from time import time + + from sage.misc.prandom import getrandbits if unique_tag is None: unique_tag = getrandbits(128) * time() @@ -609,8 +611,8 @@ def _init_spherical(self, names=None): A.set_default_frame(spher.frame()) # manage embedding... - from sage.misc.misc_c import prod from sage.functions.trig import cos, sin + from sage.misc.misc_c import prod R = self._radius diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space.py b/src/sage/manifolds/differentiable/examples/symplectic_space.py index 5a78277d567..41d7defe25a 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space.py @@ -20,8 +20,10 @@ from sage.categories.manifolds import Manifolds from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace -from sage.manifolds.differentiable.symplectic_form import (SymplecticForm, - SymplecticFormParal) +from sage.manifolds.differentiable.symplectic_form import ( + SymplecticForm, + SymplecticFormParal, +) from sage.rings.real_mpfr import RR diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space_test.py b/src/sage/manifolds/differentiable/examples/symplectic_space_test.py index 9cfdf6da123..ca3dbcc5f41 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space_test.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space_test.py @@ -1,9 +1,10 @@ +import pytest + import sage.all -from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.examples.symplectic_space import ( StandardSymplecticSpace, ) -import pytest +from sage.manifolds.differentiable.symplectic_form import SymplecticForm class TestR2VectorSpace: diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 17784f555e1..77d6a419325 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -106,21 +106,21 @@ # https://www.gnu.org/licenses/ # ********************************************************************** -from sage.symbolic.expression import Expression -from sage.rings.infinity import Infinity -from sage.calculus.desolvers import desolve_system_rk4 -from sage.calculus.desolvers import desolve_odeint +from random import shuffle + +from sage.arith.srange import srange +from sage.calculus.desolvers import desolve_odeint, desolve_system_rk4 +from sage.calculus.interpolation import Spline +from sage.ext.fast_callable import fast_callable from sage.manifolds.chart import Chart from sage.manifolds.differentiable.curve import DifferentiableCurve from sage.manifolds.differentiable.tangent_vector import TangentVector -from sage.calculus.interpolation import Spline from sage.misc.decorators import options from sage.misc.functional import numerical_approx from sage.misc.lazy_import import lazy_import -from sage.arith.srange import srange -from sage.ext.fast_callable import fast_callable +from sage.rings.infinity import Infinity +from sage.symbolic.expression import Expression from sage.symbolic.ring import SR -from random import shuffle lazy_import('scipy.integrate', 'ode') @@ -857,9 +857,9 @@ def solve_analytical(self, verbose=False): Dx3_0*t + x3_0) """ - from sage.calculus.var import function - from sage.calculus.functional import diff from sage.calculus.desolvers import desolve_system + from sage.calculus.functional import diff + from sage.calculus.var import function from sage.symbolic.assumptions import assume, forget from sage.symbolic.ring import var @@ -2559,8 +2559,8 @@ def plot_integrated(self, chart=None, ambient_coords=None, t += dt if display_tangent: - from sage.plot.graphics import Graphics from sage.plot.arrow import arrow2d + from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d scale = kwds.pop('scale') @@ -2746,8 +2746,8 @@ def plot_integrated(self, chart=None, ambient_coords=None, t += dt if display_tangent: - from sage.plot.graphics import Graphics from sage.plot.arrow import arrow2d + from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d scale = kwds.pop('scale') diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 215756f00d3..7768efbad23 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -29,10 +29,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.parallel.decorate import parallel -from sage.parallel.parallelism import Parallelism from sage.manifolds.differentiable.affine_connection import AffineConnection from sage.manifolds.differentiable.vectorframe import CoordFrame +from sage.parallel.decorate import parallel +from sage.parallel.parallelism import Parallelism class LeviCivitaConnection(AffineConnection): @@ -364,9 +364,9 @@ def _new_coef(self, frame): sage: nab._new_coef(e) 3-indices components w.r.t. Vector frame (M, (e_0,e_1)) """ - from sage.tensor.modules.comp import Components, CompWithSym from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.tensor.modules.comp import Components, CompWithSym if isinstance(frame, CoordFrame): # the Christoffel symbols are symmetric: return CompWithSym(frame._domain.scalar_field_algebra(), frame, 3, diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 285a160e7ff..1ad2543827a 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -451,8 +451,8 @@ from sage.rings.real_mpfr import RR if TYPE_CHECKING: - from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.diff_form import DiffForm + from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.metric import PseudoRiemannianMetric from sage.manifolds.differentiable.vectorfield_module import ( VectorFieldFreeModule, @@ -1097,8 +1097,9 @@ class as the manifold. Differentiable real vector bundle E -> M of rank 2 over the base space 2-dimensional differentiable manifold M """ - from sage.manifolds.differentiable.vector_bundle \ - import DifferentiableVectorBundle + from sage.manifolds.differentiable.vector_bundle import ( + DifferentiableVectorBundle, + ) return DifferentiableVectorBundle(rank, name, self, field=field, latex_name=latex_name) @@ -1366,8 +1367,10 @@ def vector_field_module( sage: M.is_manifestly_parallelizable() True """ - from sage.manifolds.differentiable.vectorfield_module import \ - VectorFieldModule, VectorFieldFreeModule + from sage.manifolds.differentiable.vectorfield_module import ( + VectorFieldFreeModule, + VectorFieldModule, + ) if dest_map is None: dest_map = self.identity_map() codomain = dest_map._codomain @@ -2695,7 +2698,7 @@ def set_orientation(self, orientation): [Coordinate frame (U, (∂/∂x,∂/∂y)), Coordinate frame (V, (∂/∂u,∂/∂v))] """ - from .vectorframe import VectorFrame + from sage.manifolds.differentiable.vectorframe import VectorFrame chart_type = self._structure.chart if isinstance(orientation, chart_type): orientation = [orientation.frame()] @@ -2985,7 +2988,9 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [1 2] [0 3] """ - from sage.manifolds.differentiable.automorphismfield import AutomorphismFieldParal + from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismFieldParal, + ) fmodule = frame1._fmodule if frame2._fmodule != fmodule: raise ValueError("the two frames are not defined on the same " + @@ -3394,8 +3399,8 @@ def tangent_space(self, point, base_ring=None): :class:`~sage.manifolds.differentiable.tangent_space.TangentSpace` for more examples. """ - from sage.manifolds.point import ManifoldPoint from sage.manifolds.differentiable.tangent_space import TangentSpace + from sage.manifolds.point import ManifoldPoint if not isinstance(point, ManifoldPoint): raise TypeError("{} is not a manifold point".format(point)) if point not in self: @@ -3725,7 +3730,9 @@ def integrated_autoparallel_curve(self, affine_connection, """ from sage.manifolds.differentiable.examples.real_line import RealLine - from sage.manifolds.differentiable.manifold_homset import IntegratedAutoparallelCurveSet + from sage.manifolds.differentiable.manifold_homset import ( + IntegratedAutoparallelCurveSet, + ) if len(curve_param) != 3: raise ValueError("the argument 'curve_param' must be " + @@ -3893,8 +3900,7 @@ def affine_connection(self, name, latex_name=None): :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` for more examples. """ - from sage.manifolds.differentiable.affine_connection import \ - AffineConnection + from sage.manifolds.differentiable.affine_connection import AffineConnection return AffineConnection(self, name, latex_name) def metric(self, name: str, signature: Optional[int] = None, diff --git a/src/sage/manifolds/differentiable/manifold_homset.py b/src/sage/manifolds/differentiable/manifold_homset.py index d26e1cfea91..98fdf8998f5 100644 --- a/src/sage/manifolds/differentiable/manifold_homset.py +++ b/src/sage/manifolds/differentiable/manifold_homset.py @@ -42,12 +42,14 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.manifolds.manifold_homset import TopologicalManifoldHomset -from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.curve import DifferentiableCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedAutoparallelCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedGeodesic +from sage.manifolds.differentiable.diff_map import DiffMap +from sage.manifolds.differentiable.integrated_curve import ( + IntegratedAutoparallelCurve, + IntegratedCurve, + IntegratedGeodesic, +) +from sage.manifolds.manifold_homset import TopologicalManifoldHomset class DifferentiableManifoldHomset(TopologicalManifoldHomset): @@ -180,8 +182,7 @@ def __init__(self, domain, codomain, name=None, latex_name=None): manifolds over Real Field with 53 bits of precision sage: TestSuite(E).run() """ - from sage.manifolds.differentiable.manifold import \ - DifferentiableManifold + from sage.manifolds.differentiable.manifold import DifferentiableManifold if not isinstance(domain, DifferentiableManifold): raise TypeError("domain = {} is not an ".format(domain) + "instance of DifferentiableManifold") @@ -1305,11 +1306,11 @@ def _an_element_(self): (1.0565635217644918,) """ + from sage.categories.homset import Hom + from sage.functions.log import exp from sage.rings.infinity import Infinity from sage.rings.rational_field import QQ - from sage.categories.homset import Hom from sage.symbolic.ring import var - from sage.functions.log import exp dom = self.domain() t = dom.canonical_coordinate() @@ -1754,8 +1755,8 @@ def _an_element_(self): """ from sage.categories.homset import Hom - from sage.symbolic.ring import var from sage.functions.log import exp + from sage.symbolic.ring import var dom = self.domain() t = dom.canonical_coordinate() diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 4a783db3478..8512ad2b70d 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -784,8 +784,9 @@ def connection(self, name=None, latex_name=None, init_coef=True): sage: Dig == 0 True """ - from sage.manifolds.differentiable.levi_civita_connection import \ - LeviCivitaConnection + from sage.manifolds.differentiable.levi_civita_connection import ( + LeviCivitaConnection, + ) if self._connection is None: if latex_name is None: if name is None: diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 65e2a25891e..c9b04bd2a12 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -23,8 +23,8 @@ # ***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.structure.element import AlgebraElement, ModuleElementWithMutability from sage.rings.integer import Integer +from sage.structure.element import AlgebraElement, ModuleElementWithMutability class MixedForm(AlgebraElement, ModuleElementWithMutability): @@ -413,9 +413,8 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): F = x dx + (2*x^2 - 2*y^2) dx∧dy """ from sage.misc.latex import latex + from sage.tensor.modules.format_utilities import FormattedExpansion, is_atomic from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (is_atomic, - FormattedExpansion) # In case, no frame is given: if frame is None: frame = self._domain._def_frame @@ -711,7 +710,7 @@ def _richcmp_(self, other, op): sage: F.parent().zero() == 0 True """ - from sage.structure.richcmp import op_NE, op_EQ + from sage.structure.richcmp import op_EQ, op_NE if op == op_NE: return not self == other elif op == op_EQ: @@ -979,9 +978,11 @@ def wedge(self, other): resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1)) for j in self.irange()] # Compose name: + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) resu._name = format_mul_txt(self._name, unicode_wedge, other._name) resu._latex_name = format_mul_latex(self._latex_name, r'\wedge ', other._latex_name) @@ -1032,9 +1033,11 @@ def _lmul_(self, other): resu._comp = [other * form for form in self] # Compose name: from sage.misc.latex import latex + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) resu._name = format_mul_txt(repr(other), unicode_wedge, self._name) resu._latex_name = format_mul_latex(latex(other), r'\wedge ', self._latex_name) @@ -1100,8 +1103,10 @@ def exterior_derivative(self): resu[1:] = [self[j].exterior_derivative() for j in range(self._max_deg)] # Compose name: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('d', self._name) resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name) return resu diff --git a/src/sage/manifolds/differentiable/mixed_form_algebra.py b/src/sage/manifolds/differentiable/mixed_form_algebra.py index 26339c0d6ad..c6af6f4164d 100644 --- a/src/sage/manifolds/differentiable/mixed_form_algebra.py +++ b/src/sage/manifolds/differentiable/mixed_form_algebra.py @@ -28,14 +28,14 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.structure.parent import Parent -from sage.categories.graded_algebras import GradedAlgebras from sage.categories.chain_complexes import ChainComplexes +from sage.categories.graded_algebras import GradedAlgebras from sage.categories.morphism import SetMorphism +from sage.manifolds.differentiable.mixed_form import MixedForm +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.symbolic.ring import SR -from sage.manifolds.differentiable.mixed_form import MixedForm class MixedFormAlgebra(Parent, UniqueRepresentation): @@ -494,7 +494,9 @@ def cohomology(self, *args, **kwargs): De Rham cohomology ring on the 3-dimensional differentiable manifold M """ - from .de_rham_cohomology import DeRhamCohomologyRing + from sage.manifolds.differentiable.de_rham_cohomology import ( + DeRhamCohomologyRing, + ) return DeRhamCohomologyRing(self) homology = cohomology diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index fa2d5fce099..35f56f2935e 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -32,13 +32,15 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, + MultivectorFieldParal, +) from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule -from sage.manifolds.differentiable.multivectorfield import ( - MultivectorField, MultivectorFieldParal) class MultivectorModule(UniqueRepresentation, Parent): diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 1e739dfdd17..2efe5c133f2 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -36,9 +36,9 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor class MultivectorField(TensorField): @@ -300,8 +300,8 @@ def wedge(self, other): sage: c.display(e_uv) a∧b = (-v^2 + u) ∂/∂u∧∂/∂v """ - from sage.typeset.unicode_characters import unicode_wedge from sage.tensor.modules.format_utilities import is_atomic + from sage.typeset.unicode_characters import unicode_wedge if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior " + @@ -1401,10 +1401,10 @@ def bracket(self, other): True """ from itertools import combinations + from sage.combinat.permutation import Permutation - from sage.tensor.modules.comp import (Components, CompWithSym, - CompFullyAntiSym) from sage.manifolds.differentiable.scalarfield import DiffScalarField + from sage.tensor.modules.comp import CompFullyAntiSym, Components, CompWithSym pp = self._tensor_rank mp1 = (-1)**(pp+1) if isinstance(other, DiffScalarField): diff --git a/src/sage/manifolds/differentiable/poisson_tensor.py b/src/sage/manifolds/differentiable/poisson_tensor.py index 51da2de5f90..63fcab8d588 100644 --- a/src/sage/manifolds/differentiable/poisson_tensor.py +++ b/src/sage/manifolds/differentiable/poisson_tensor.py @@ -16,16 +16,17 @@ # ***************************************************************************** +from typing import Optional, Union + +from sage.manifolds.differentiable.diff_form import DiffForm +from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.multivectorfield import ( MultivectorField, MultivectorFieldParal, ) -from sage.manifolds.differentiable.diff_form import DiffForm -from sage.manifolds.differentiable.vectorfield import VectorField from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.vectorfield import VectorField from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.manifolds.differentiable.manifold import DifferentiableManifold -from typing import Optional, Union class PoissonTensorField(MultivectorField): diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian.py b/src/sage/manifolds/differentiable/pseudo_riemannian.py index 505900ad0df..c44d063bdc3 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian.py @@ -267,10 +267,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.infinity import infinity -from sage.manifolds.structure import (PseudoRiemannianStructure, - RiemannianStructure, LorentzianStructure) from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import ( + LorentzianStructure, + PseudoRiemannianStructure, + RiemannianStructure, +) +from sage.rings.infinity import infinity ############################################################################### diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index e791cef6781..57dc1c99862 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -190,19 +190,19 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold -from sage.manifolds.differentiable.degenerate import \ - DegenerateManifold -from sage.manifolds.differentiable.differentiable_submanifold import \ - DifferentiableSubmanifold -from sage.rings.infinity import infinity -from sage.matrix.constructor import matrix +from queue import Queue + from sage.functions.other import factorial -from sage.symbolic.ring import SR +from sage.manifolds.differentiable.degenerate import DegenerateManifold +from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, +) +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.rings.infinity import infinity from sage.rings.integer import Integer -from queue import Queue +from sage.symbolic.ring import SR class PseudoRiemannianSubmanifold(PseudoRiemannianManifold, diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index be1d6d3b97e..72d04db04f0 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -789,8 +789,10 @@ def differential(self) -> DiffForm: sage: ddg == 0 True """ - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) if self._differential is None: # A new computation is necessary: rname = format_unop_txt('d', self._name) @@ -936,8 +938,8 @@ def hodge_dual( True """ from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) result = self * nondegenerate_tensor.volume_form() diff --git a/src/sage/manifolds/differentiable/scalarfield_algebra.py b/src/sage/manifolds/differentiable/scalarfield_algebra.py index fc716f5fcc4..6a6091fe659 100644 --- a/src/sage/manifolds/differentiable/scalarfield_algebra.py +++ b/src/sage/manifolds/differentiable/scalarfield_algebra.py @@ -30,10 +30,10 @@ class `C^k` over a topological field `K` (in # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra from sage.rings.infinity import infinity from sage.symbolic.ring import SymbolicRing -from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra -from sage.manifolds.differentiable.scalarfield import DiffScalarField class DiffScalarFieldAlgebra(ScalarFieldAlgebra): diff --git a/src/sage/manifolds/differentiable/symplectic_form.py b/src/sage/manifolds/differentiable/symplectic_form.py index 52a076bfbe8..2c393d59cd7 100644 --- a/src/sage/manifolds/differentiable/symplectic_form.py +++ b/src/sage/manifolds/differentiable/symplectic_form.py @@ -22,18 +22,19 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** from __future__ import annotations -from typing import Union, Optional -from sage.symbolic.expression import Expression +from typing import Optional, Union + from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal from sage.manifolds.differentiable.diff_map import DiffMap -from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.vectorfield import VectorField -from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField +from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule +from sage.symbolic.expression import Expression class SymplecticForm(DiffForm): diff --git a/src/sage/manifolds/differentiable/symplectic_form_test.py b/src/sage/manifolds/differentiable/symplectic_form_test.py index 804c8956b6e..cb5133595fb 100644 --- a/src/sage/manifolds/differentiable/symplectic_form_test.py +++ b/src/sage/manifolds/differentiable/symplectic_form_test.py @@ -1,16 +1,16 @@ # pylint: disable=missing-function-docstring -from _pytest.fixtures import FixtureRequest import pytest +from _pytest.fixtures import FixtureRequest -from sage.manifolds.manifold import Manifold -from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.examples.sphere import Sphere -from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.examples.symplectic_space import ( StandardSymplecticSpace, ) -from sage.symbolic.function_factory import function +from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.symplectic_form import SymplecticForm +from sage.manifolds.manifold import Manifold +from sage.symbolic.function_factory import function class TestGenericSymplecticForm: diff --git a/src/sage/manifolds/differentiable/tangent_vector.py b/src/sage/manifolds/differentiable/tangent_vector.py index 1bd1dd5c647..81b89e29646 100644 --- a/src/sage/manifolds/differentiable/tangent_vector.py +++ b/src/sage/manifolds/differentiable/tangent_vector.py @@ -24,10 +24,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement -from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm -from .scalarfield import DiffScalarField +from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.misc.decorators import options +from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm +from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement class TangentVector(FiniteRankFreeModuleElement): @@ -448,13 +448,13 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) sphinx_plot(graph_v + graph_S2) """ + from sage.manifolds.differentiable.chart import DiffChart + from sage.misc.functional import numerical_approx from sage.plot.arrow import arrow2d - from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d from sage.plot.plot3d.shapes2 import text3d - from sage.misc.functional import numerical_approx - from sage.manifolds.differentiable.chart import DiffChart + from sage.plot.text import text scale = extra_options.pop("scale") diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 562c62cefc8..50ed9fe7a80 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -2228,7 +2228,7 @@ def __eq__(self, other): sage: t.parent().zero() == 0 True """ - from .mixed_form import MixedForm + from sage.manifolds.differentiable.mixed_form import MixedForm if other is self: return True @@ -2341,8 +2341,10 @@ def __pos__(self): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = + rst # Compose names: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('+', self._name) resu._latex_name = format_unop_latex(r'+', self._latex_name) return resu @@ -2385,8 +2387,10 @@ def __neg__(self): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = - rst # Compose names: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('-', self._name) resu._latex = format_unop_latex(r'-', self._latex_name) return resu @@ -2597,8 +2601,10 @@ def _rmul_(self, scalar): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst # Compose names: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) resu_name = format_mul_txt(scalar._name, '*', self._name) resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', self._latex_name) @@ -3826,8 +3832,8 @@ def up( raise ValueError("position out of range") from sage.manifolds.differentiable.metric import PseudoRiemannianMetric - from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField + from sage.manifolds.differentiable.symplectic_form import SymplecticForm if isinstance(non_degenerate_form, PseudoRiemannianMetric): return self.contract(pos, non_degenerate_form.inverse(), 1) diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 22d42050b89..089d4d178d8 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -38,20 +38,23 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, + AutomorphismFieldParal, +) +from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, + MultivectorFieldParal, +) +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.reflexive_module import ReflexiveModule_tensor from sage.tensor.modules.tensor_free_module import TensorFreeModule -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal -from sage.manifolds.differentiable.diff_form import (DiffForm, - DiffFormParal) -from sage.manifolds.differentiable.multivectorfield import (MultivectorField, - MultivectorFieldParal) -from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) class TensorFieldModule(UniqueRepresentation, ReflexiveModule_tensor): @@ -442,12 +445,11 @@ def _coerce_map_from_(self, other): sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormModule - from sage.manifolds.differentiable.multivector_module import \ - MultivectorModule - from sage.manifolds.differentiable.automorphismfield_group \ - import AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldGroup, + ) + from sage.manifolds.differentiable.diff_form_module import DiffFormModule + from sage.manifolds.differentiable.multivector_module import MultivectorModule if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -901,12 +903,13 @@ def _coerce_map_from_(self, other): sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormFreeModule - from sage.manifolds.differentiable.multivector_module import \ - MultivectorFreeModule - from sage.manifolds.differentiable.automorphismfield_group \ - import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldParalGroup, + ) + from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorFreeModule, + ) if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index cb0e1db14cd..3fa7166234c 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -1975,8 +1975,8 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True, t^10_0 = (u^2 - v^2)/(u^2 + 2*u*v + v^2 + 8) t^11_1 = -12/(u^2 + 2*u*v + v^2 + 8) """ - from sage.misc.latex import latex from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.misc.latex import latex if frame is None: if chart is not None: frame = chart.frame() diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 79e940a19e6..a6307cf274d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -30,12 +30,12 @@ #****************************************************************************** from sage.categories.vector_bundles import VectorBundles -from sage.rings.cc import CC -from sage.rings.real_mpfr import RR from sage.manifolds.vector_bundle import TopologicalVectorBundle -from sage.rings.infinity import infinity from sage.misc.superseded import deprecated_function_alias +from sage.rings.cc import CC +from sage.rings.infinity import infinity from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RR class DifferentiableVectorBundle(TopologicalVectorBundle): @@ -158,7 +158,7 @@ def bundle_connection(self, name, latex_name=None): Further examples can be found in :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection`. """ - from .bundle_connection import BundleConnection + from sage.manifolds.differentiable.bundle_connection import BundleConnection return BundleConnection(self, name, latex_name) def characteristic_cohomology_class_ring(self, base=QQ): @@ -186,7 +186,9 @@ def characteristic_cohomology_class_ring(self, base=QQ): Characteristic cohomology class (1 + p_1)(TM) of the Tangent bundle TM over the 4-dimensional differentiable manifold M """ - from .characteristic_cohomology_class import CharacteristicCohomologyClassRing + from sage.manifolds.differentiable.characteristic_cohomology_class import ( + CharacteristicCohomologyClassRing, + ) return CharacteristicCohomologyClassRing(base, self) diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index 44ae84089de..c038e8afab2 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -59,10 +59,12 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement from sage.manifolds.differentiable.multivectorfield import ( - MultivectorField, MultivectorFieldParal) + MultivectorField, + MultivectorFieldParal, +) from sage.misc.decorators import options +from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement class VectorField(MultivectorField): @@ -663,14 +665,14 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, sage: v.plot.reset() """ - from sage.rings.infinity import Infinity - from sage.misc.functional import numerical_approx - from sage.misc.latex import latex - from sage.plot.graphics import Graphics from sage.manifolds.chart import RealChart from sage.manifolds.utilities import set_axes_labels + from sage.misc.functional import numerical_approx + from sage.misc.latex import latex from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism + from sage.plot.graphics import Graphics + from sage.rings.infinity import Infinity # # 1/ Treatment of input parameters diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 67cd1abd614..edea1756278 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -57,9 +57,9 @@ if TYPE_CHECKING: from sage.manifolds.differentiable.diff_form import DiffForm - from sage.manifolds.scalarfield import ScalarField from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.manifold import DifferentiableManifold + from sage.manifolds.scalarfield import ScalarField class VectorFieldModule(UniqueRepresentation, ReflexiveModule_base): @@ -548,8 +548,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): try: return self._tensor_modules[(k,l)] except KeyError: - from sage.manifolds.differentiable.tensorfield_module import \ - TensorFieldModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldModule, + ) T = TensorFieldModule(self, (k,l)) self._tensor_modules[(k,l)] = T return T @@ -606,8 +607,9 @@ def exterior_power(self, p): if p == 0: L = self._ring else: - from sage.manifolds.differentiable.multivector_module import \ - MultivectorModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorModule, + ) L = MultivectorModule(self, p) self._exterior_powers[p] = L return L @@ -663,8 +665,9 @@ def dual_exterior_power(self, p): if p == 0: L = self._ring else: - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormModule + from sage.manifolds.differentiable.diff_form_module import ( + DiffFormModule, + ) L = DiffFormModule(self, p) self._dual_exterior_powers[p] = L return L @@ -713,8 +716,9 @@ def general_linear_group(self): for more examples and documentation. """ if self._general_linear_group is None: - from sage.manifolds.differentiable.automorphismfield_group import \ - AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldGroup, + ) self._general_linear_group = AutomorphismFieldGroup(self) return self._general_linear_group @@ -769,10 +773,11 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, :class:`~sage.manifolds.differentiable.tensorfield.TensorField` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield import \ - AutomorphismField - from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, - DegenerateMetric) + from sage.manifolds.differentiable.automorphismfield import AutomorphismField + from sage.manifolds.differentiable.metric import ( + DegenerateMetric, + PseudoRiemannianMetric, + ) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( tensor_type[0] + tensor_type[1], sym, antisym) @@ -1839,8 +1844,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): elif (k, l) == (0, 1): T = self.dual() else: - from sage.manifolds.differentiable.tensorfield_module import \ - TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldFreeModule, + ) T = TensorFieldFreeModule(self, (k,l)) self._tensor_modules[(k,l)] = T return T @@ -1900,8 +1906,9 @@ def exterior_power(self, p): elif p == 1: L = self else: - from sage.manifolds.differentiable.multivector_module import \ - MultivectorFreeModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorFreeModule, + ) L = MultivectorFreeModule(self, p) self._exterior_powers[p] = L return L @@ -1956,12 +1963,14 @@ def dual_exterior_power(self, p): if p == 0: L = self._ring elif p == 1: - from sage.manifolds.differentiable.diff_form_module import \ - VectorFieldDualFreeModule + from sage.manifolds.differentiable.diff_form_module import ( + VectorFieldDualFreeModule, + ) L = VectorFieldDualFreeModule(self) else: - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormFreeModule + from sage.manifolds.differentiable.diff_form_module import ( + DiffFormFreeModule, + ) L = DiffFormFreeModule(self, p) self._dual_exterior_powers[p] = L return L @@ -1996,8 +2005,9 @@ def general_linear_group(self): :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldParalGroup` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import \ - AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldParalGroup, + ) return AutomorphismFieldParalGroup(self) def basis(self, symbol=None, latex_symbol=None, from_frame=None, @@ -2138,9 +2148,13 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, for more examples and documentation. """ from sage.manifolds.differentiable.automorphismfield import ( - AutomorphismField, AutomorphismFieldParal) - from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, - DegenerateMetric) + AutomorphismField, + AutomorphismFieldParal, + ) + from sage.manifolds.differentiable.metric import ( + DegenerateMetric, + PseudoRiemannianMetric, + ) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( tensor_type[0] + tensor_type[1], sym, antisym) @@ -2227,7 +2241,7 @@ def tensor_from_comp(self, tensor_type, comp, name=None, sage: t.display() t = (x + 1) dx⊗dx - y dx⊗dy + x*y dy⊗dx + (-y^2 + 2) dy⊗dy """ - from sage.tensor.modules.comp import (CompWithSym, CompFullyAntiSym) + from sage.tensor.modules.comp import CompFullyAntiSym, CompWithSym # 0/ Compatibility checks: if comp._ring is not self._ring: diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 594d2e9a729..8cc75ab0f2d 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -216,10 +216,9 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_basis import (FreeModuleBasis, - FreeModuleCoBasis) -from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule from sage.misc.cachefunc import cached_method +from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule +from sage.tensor.modules.free_module_basis import FreeModuleBasis, FreeModuleCoBasis class CoFrame(FreeModuleCoBasis): @@ -1715,9 +1714,9 @@ def __init__(self, chart): Coordinate frame (M, (∂/∂x,∂/∂y)) sage: TestSuite(e).run() """ + from sage.manifolds.differentiable.chart import DiffChart from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_partial - from sage.manifolds.differentiable.chart import DiffChart if not isinstance(chart, DiffChart): raise TypeError("the first argument must be a chart") dom = chart.domain() diff --git a/src/sage/manifolds/family.py b/src/sage/manifolds/family.py index 565fa2401cc..e58faf0e885 100644 --- a/src/sage/manifolds/family.py +++ b/src/sage/manifolds/family.py @@ -26,6 +26,7 @@ #***************************************************************************** from functools import total_ordering + from sage.sets.family import FiniteFamily diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index 42e1579640d..3d13c977f9a 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -171,9 +171,8 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_basis import (FreeModuleBasis, - FreeModuleCoBasis) from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule +from sage.tensor.modules.free_module_basis import FreeModuleBasis, FreeModuleCoBasis class LocalCoFrame(FreeModuleCoBasis): @@ -1414,8 +1413,8 @@ def __init__(self, trivialization): sage: e = phi.frame() sage: TestSuite(e).run() """ + from sage.manifolds.trivialization import Trivialization from sage.misc.latex import latex - from .trivialization import Trivialization if not isinstance(trivialization, Trivialization): raise TypeError("the first argument must be a trivialization") ### diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index c27cd0b6434..e3d03ad602f 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -1321,7 +1321,7 @@ def set_default_chart(self, chart): sage: M.default_chart() Chart (M, (u, v)) """ - from .chart import Chart + from sage.manifolds.chart import Chart if not isinstance(chart, Chart): raise TypeError("{} is not a chart".format(chart)) if chart not in self._atlas: @@ -1692,7 +1692,7 @@ def orientation(self): r""" Get the preferred orientation of ``self`` if available. - An *orientation* of an `n`-dimensional topologial manifold is an + An *orientation* of an `n`-dimensional topological manifold is an atlas of charts whose transition maps are orientation preserving. A homeomorphism `f \colon U \to V` for open subsets `U, V \subset \RR^n` is called *orientation preserving* if for each `x \in U` the @@ -2950,14 +2950,20 @@ def Manifold( sage: isinstance(M, sage.misc.fast_methods.WithEqualityById) True """ - from sage.rings.infinity import infinity + from sage.manifolds.differentiable.degenerate import DegenerateManifold + from sage.manifolds.differentiable.degenerate_submanifold import ( + DegenerateSubmanifold, + ) + from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, + ) from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold - from sage.manifolds.differentiable.degenerate import DegenerateManifold + from sage.manifolds.differentiable.pseudo_riemannian_submanifold import ( + PseudoRiemannianSubmanifold, + ) from sage.manifolds.topological_submanifold import TopologicalSubmanifold - from sage.manifolds.differentiable.differentiable_submanifold import DifferentiableSubmanifold - from sage.manifolds.differentiable.pseudo_riemannian_submanifold import PseudoRiemannianSubmanifold - from sage.manifolds.differentiable.degenerate_submanifold import DegenerateSubmanifold + from sage.rings.infinity import infinity global _manifold_id diff --git a/src/sage/manifolds/manifold_homset.py b/src/sage/manifolds/manifold_homset.py index c390233ca55..2b3c8564622 100644 --- a/src/sage/manifolds/manifold_homset.py +++ b/src/sage/manifolds/manifold_homset.py @@ -28,10 +28,10 @@ #***************************************************************************** from sage.categories.homset import Homset -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation from sage.manifolds.continuous_map import ContinuousMap from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class TopologicalManifoldHomset(UniqueRepresentation, Homset): diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index b3647cc1447..ca10cb5c767 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -87,10 +87,10 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element import Element from sage.misc.decorators import options -from sage.symbolic.expression import Expression from sage.rings.integer_ring import ZZ +from sage.structure.element import Element +from sage.symbolic.expression import Expression class ManifoldPoint(Element): @@ -935,11 +935,11 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, gX = X.plot(X, ambient_coords=(y,z)) sphinx_plot(g+gX) """ - from sage.plot.point import point2d - from sage.plot.text import text + from sage.manifolds.chart import Chart from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d - from sage.manifolds.chart import Chart + from sage.plot.point import point2d + from sage.plot.text import text if self._manifold.base_field_type() != 'real': raise NotImplementedError('plot of points on manifolds over fields different' ' from the real field is not implemented') diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 62c728ff5bb..7b850a4b1a4 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -40,16 +40,20 @@ # ***************************************************************************** from __future__ import annotations -from typing import Optional, TYPE_CHECKING -from sage.structure.element import (CommutativeAlgebraElement, - ModuleElementWithMutability) -from sage.symbolic.expression import Expression + +from typing import TYPE_CHECKING, Optional + from sage.manifolds.chart_func import ChartFunction from sage.misc.cachefunc import cached_method +from sage.structure.element import ( + CommutativeAlgebraElement, + ModuleElementWithMutability, +) +from sage.symbolic.expression import Expression if TYPE_CHECKING: - from sage.tensor.modules.format_utilities import FormattedExpansion from sage.manifolds.chart import Chart + from sage.tensor.modules.format_utilities import FormattedExpansion class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability): @@ -2135,11 +2139,13 @@ def display(self, chart: Optional[Chart] = None) -> FormattedExpansion: \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array} """ from sage.misc.latex import latex - from sage.typeset.unicode_characters import (unicode_to, - unicode_mapsto, - unicode_mathbbR, - unicode_mathbbC) from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import ( + unicode_mapsto, + unicode_mathbbC, + unicode_mathbbR, + unicode_to, + ) def _display_expression(self, chart, result): r""" @@ -2764,8 +2770,10 @@ def _mul_(self, other): if other.is_trivial_one(): return self # Generic case: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) com_charts = self.common_charts(other) if com_charts is None: raise ValueError("no common chart for the multiplication") @@ -2809,8 +2817,10 @@ def _div_(self, other): ... ZeroDivisionError: division of a scalar field by zero """ - from sage.tensor.modules.format_utilities import format_mul_txt, \ - format_mul_latex + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) # Trivial cases: if other.is_trivial_zero(): raise ZeroDivisionError("division of a scalar field by zero") diff --git a/src/sage/manifolds/scalarfield_algebra.py b/src/sage/manifolds/scalarfield_algebra.py index 960b4514387..d4a01098eaf 100644 --- a/src/sage/manifolds/scalarfield_algebra.py +++ b/src/sage/manifolds/scalarfield_algebra.py @@ -30,13 +30,13 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.topological_spaces import TopologicalSpaces -from sage.symbolic.ring import SymbolicRing, SR from sage.manifolds.scalarfield import ScalarField +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.symbolic.ring import SR, SymbolicRing class ScalarFieldAlgebra(UniqueRepresentation, Parent): @@ -518,7 +518,7 @@ def _coerce_map_from_(self, other): sage: CU._coerce_map_from_(CM) True """ - from .chart_func import ChartFunctionRing + from sage.manifolds.chart_func import ChartFunctionRing if isinstance(other, SymbolicRing): return True # coercion from the base ring (multiplication by the # algebra unit, i.e. self.one()) diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index 75af42a57e5..77d8f881ee1 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -19,11 +19,11 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.structure.element import ModuleElementWithMutability from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement from sage.tensor.modules.tensor_with_indices import TensorWithIndices -from sage.rings.integer import Integer -from sage.rings.integer_ring import ZZ class Section(ModuleElementWithMutability): @@ -2213,8 +2213,10 @@ def _rmul_(self, scalar): return self.copy() ### # General case: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst diff --git a/src/sage/manifolds/section_module.py b/src/sage/manifolds/section_module.py index 6192045f45a..bace0b29866 100644 --- a/src/sage/manifolds/section_module.py +++ b/src/sage/manifolds/section_module.py @@ -26,13 +26,13 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.section import Section, TrivialSection +from sage.misc.cachefunc import cached_method from sage.rings.infinity import infinity -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.misc.cachefunc import cached_method -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.section import Section, TrivialSection class SectionModule(UniqueRepresentation, Parent): @@ -467,7 +467,7 @@ def set_default_frame(self, basis): sage: C0.default_frame().domain() Open subset U of the 3-dimensional topological manifold M """ - from .local_frame import LocalFrame + from sage.manifolds.local_frame import LocalFrame if not isinstance(basis, LocalFrame): raise ValueError("the argument is not a local frame") elif not basis._domain.is_subset(self._domain): @@ -587,7 +587,7 @@ def __init__(self, vbundle, domain): True sage: TestSuite(C0).run() """ - from .scalarfield import ScalarField + from sage.manifolds.scalarfield import ScalarField self._domain = domain name = "C^0({};{})".format(domain._name, vbundle._name) latex_name = r'C^0({};{})'.format(domain._latex_name, diff --git a/src/sage/manifolds/structure.py b/src/sage/manifolds/structure.py index ed166b6438a..6d0797c062d 100644 --- a/src/sage/manifolds/structure.py +++ b/src/sage/manifolds/structure.py @@ -23,15 +23,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.fast_methods import Singleton from sage.manifolds.chart import Chart, RealChart -from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra -from sage.manifolds.manifold_homset import TopologicalManifoldHomset from sage.manifolds.differentiable.chart import DiffChart, RealDiffChart -from sage.manifolds.differentiable.scalarfield_algebra import \ - DiffScalarFieldAlgebra -from sage.manifolds.differentiable.manifold_homset import \ - DifferentiableManifoldHomset +from sage.manifolds.differentiable.manifold_homset import DifferentiableManifoldHomset +from sage.manifolds.differentiable.scalarfield_algebra import DiffScalarFieldAlgebra +from sage.manifolds.manifold_homset import TopologicalManifoldHomset +from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra +from sage.misc.fast_methods import Singleton # This is a slight abuse by making this a Singleton, but there is no # need to have different copies of this object. diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py index 453fa02de2f..b0552238afa 100644 --- a/src/sage/manifolds/subset.py +++ b/src/sage/manifolds/subset.py @@ -65,15 +65,17 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import annotations -from typing import Optional -from collections import defaultdict + import itertools -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.superseded import deprecation +from collections import defaultdict +from typing import Optional + from sage.categories.sets_cat import Sets from sage.manifolds.family import ManifoldObjectFiniteFamily, ManifoldSubsetFiniteFamily from sage.manifolds.point import ManifoldPoint +from sage.misc.superseded import deprecation +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class ManifoldSubset(UniqueRepresentation, Parent): @@ -1891,7 +1893,7 @@ def declare_closed(self): if self.is_closed(): return self.complement(is_open=True) - from .subsets.closure import ManifoldSubsetClosure + from sage.manifolds.subsets.closure import ManifoldSubsetClosure for closure in self.manifold().subsets(): if isinstance(closure, ManifoldSubsetClosure): if closure._subset.is_subset(self): @@ -2755,7 +2757,7 @@ def closure(self, name=None, latex_name=None): """ if self.is_closed(): return self - from .subsets.closure import ManifoldSubsetClosure + from sage.manifolds.subsets.closure import ManifoldSubsetClosure return ManifoldSubsetClosure(self, name=name, latex_name=latex_name) #### End of construction of new sets from self diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index d62f9936368..2d499892e35 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -13,23 +13,23 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.sets_cat import Sets, EmptySetError +import sage.geometry.abc from sage.categories.metric_spaces import MetricSpaces +from sage.categories.sets_cat import EmptySetError, Sets +from sage.manifolds.chart import Chart +from sage.manifolds.scalarfield import ScalarField +from sage.manifolds.subset import ManifoldSubset from sage.misc.lazy_import import lazy_import from sage.modules.free_module import FreeModule_generic +from sage.modules.free_module_element import vector +from sage.rings.complex_double import CDF from sage.rings.infinity import infinity, minus_infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.complex_double import CDF from sage.rings.real_double import RDF from sage.rings.real_lazy import CLF, RLF -from sage.symbolic.ring import SR -from sage.modules.free_module_element import vector -from sage.manifolds.subset import ManifoldSubset -from sage.manifolds.chart import Chart -from sage.manifolds.scalarfield import ScalarField from sage.sets.real_set import RealSet -import sage.geometry.abc +from sage.symbolic.ring import SR lazy_import('sage.geometry.relative_interior', 'RelativeInterior') @@ -307,7 +307,7 @@ def _is_open(codomain_subset): if hasattr(codomain_subset, 'minimized_constraints'): try: - from ppl import NNC_Polyhedron, C_Polyhedron + from ppl import C_Polyhedron, NNC_Polyhedron except ImportError: pass else: @@ -837,7 +837,7 @@ def is_closed(self): else: if hasattr(self._codomain_subset, 'is_topologically_closed'): try: - from ppl import NNC_Polyhedron, C_Polyhedron + from ppl import C_Polyhedron, NNC_Polyhedron except ImportError: pass else: diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index a99e6d1fca1..9ea40b0f621 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -45,11 +45,12 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from sage.manifolds.manifold import TopologicalManifold from sage.manifolds.continuous_map import ContinuousMap -from sage.symbolic.expression import Expression -from sage.symbolic.assumptions import assumptions, assume +from sage.manifolds.manifold import TopologicalManifold from sage.misc.lazy_import import lazy_import +from sage.symbolic.assumptions import assume, assumptions +from sage.symbolic.expression import Expression + lazy_import("sage.plot.plot3d.parametric_surface", "ParametricSurface") ############################################################################# diff --git a/src/sage/manifolds/trivialization.py b/src/sage/manifolds/trivialization.py index 4c718db8ffe..5898d38a089 100644 --- a/src/sage/manifolds/trivialization.py +++ b/src/sage/manifolds/trivialization.py @@ -20,9 +20,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.manifolds.local_frame import TrivializationFrame from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.manifolds.local_frame import TrivializationFrame class Trivialization(UniqueRepresentation, SageObject): diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 190213eeb41..e2a01a1416a 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -27,14 +27,15 @@ # **************************************************************************** from operator import pow as _pow -from sage.symbolic.expression import Expression -from sage.symbolic.expression_conversions import ExpressionTreeWalker -from sage.symbolic.ring import SR -from sage.symbolic.constants import pi + from sage.functions.other import abs_symbolic -from sage.misc.functional import sqrt from sage.functions.trig import cos, sin +from sage.misc.functional import sqrt from sage.rings.rational import Rational +from sage.symbolic.constants import pi +from sage.symbolic.expression import Expression +from sage.symbolic.expression_conversions import ExpressionTreeWalker +from sage.symbolic.ring import SR class SimplifySqrtReal(ExpressionTreeWalker): @@ -991,6 +992,7 @@ def _repr_(self): d = d.replace(o, res) import re + from sage.manifolds.manifold import TopologicalManifold if TopologicalManifold.options.omit_function_arguments: list_f = [] @@ -1144,6 +1146,7 @@ def _list_derivatives(ex, list_d, exponent=0): operands = ex.operands() import operator + from sage.misc.latex import latex, latex_variable_name from sage.symbolic.operators import FDerivativeOperator diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index ad830d68469..ebc5e652e14 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -32,14 +32,14 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.category_object import CategoryObject -from sage.categories.vector_bundles import VectorBundles -from sage.structure.unique_representation import UniqueRepresentation import sage.rings.abc +from sage.categories.vector_bundles import VectorBundles +from sage.manifolds.vector_bundle_fiber import VectorBundleFiber from sage.rings.cc import CC -from sage.rings.real_mpfr import RR from sage.rings.integer import Integer -from sage.manifolds.vector_bundle_fiber import VectorBundleFiber +from sage.rings.real_mpfr import RR +from sage.structure.category_object import CategoryObject +from sage.structure.unique_representation import UniqueRepresentation class TopologicalVectorBundle(CategoryObject, UniqueRepresentation): @@ -437,7 +437,7 @@ def trivialization(self, name, domain=None, latex_name=None): """ if domain is None: domain = self._base_space - from .trivialization import Trivialization + from sage.manifolds.trivialization import Trivialization return Trivialization(self, name, domain=domain, latex_name=latex_name) def transitions(self): @@ -638,8 +638,7 @@ def section_module(self, domain=None, force_free=False): """ if domain is None: domain = self._base_space - from sage.manifolds.section_module import (SectionModule, - SectionFreeModule) + from sage.manifolds.section_module import SectionFreeModule, SectionModule if domain not in self._section_modules: if force_free or domain in self._trivial_parts: self._section_modules[domain] = SectionFreeModule(self, domain) @@ -928,8 +927,7 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [1 2] [0 3] """ - from sage.tensor.modules.free_module_automorphism import \ - FreeModuleAutomorphism + from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism sec_module = frame1._fmodule if frame2._fmodule != sec_module: raise ValueError("the two frames are not defined on the same " + @@ -1154,7 +1152,7 @@ def set_orientation(self, orientation): [Local frame (E|_U, (e_0,e_1)), Local frame (E|_V, (f_0,f_1))] """ - from .local_frame import LocalFrame + from sage.manifolds.local_frame import LocalFrame if isinstance(orientation, LocalFrame): orientation = [orientation] elif isinstance(orientation, (tuple, list)): diff --git a/src/sage/manifolds/vector_bundle_fiber.py b/src/sage/manifolds/vector_bundle_fiber.py index 325ac1582b2..a7cebfba9f8 100644 --- a/src/sage/manifolds/vector_bundle_fiber.py +++ b/src/sage/manifolds/vector_bundle_fiber.py @@ -17,9 +17,9 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.manifolds.vector_bundle_fiber_element import VectorBundleFiberElement from sage.symbolic.ring import SR from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.vector_bundle_fiber_element import VectorBundleFiberElement class VectorBundleFiber(FiniteRankFreeModule): diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d2f0815e81e..dec25a76e54 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -3056,7 +3056,7 @@ cdef class Matrix(Matrix1): ALGORITHM: - If the base ring has a method `_matrix_charpoly`, we use it. + If the base ring has a method ``_matrix_charpoly``, we use it. In the generic case of matrices over a ring (commutative and with unity), there is a division-free algorithm, which can be accessed diff --git a/src/sage/matrix/matrix_cyclo_dense.pxd b/src/sage/matrix/matrix_cyclo_dense.pxd index 13f72389cf5..1c740082681 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pxd +++ b/src/sage/matrix/matrix_cyclo_dense.pxd @@ -13,4 +13,3 @@ cdef class Matrix_cyclo_dense(Matrix_dense): cdef _randomize_rational_column_unsafe(Matrix_cyclo_dense self, Py_ssize_t col, mpz_t nump1, mpz_t denp1, distribution=?) - diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 71254649be7..b3ee53e9c37 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -2396,8 +2396,8 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): r""" Return ``True`` if the matrix is (skew-)Hermitian. - For internal purposes. This function is used in `is_hermitian` - and `is_skew_hermitian` functions. + For internal purposes. This function is used in ``is_hermitian`` + and ``is_skew_hermitian`` functions. INPUT: diff --git a/src/sage/matrix/matrix_misc.py b/src/sage/matrix/matrix_misc.py index 35591735e57..a539f22ddff 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -14,8 +14,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.fields import Fields _Fields = Fields() @@ -309,4 +309,4 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): " algorithm... please contact sage-devel@googlegroups.com") p = p[0] - return p[min(nrows,ncols)] if permanent_only else p + return p[min(nrows, ncols)] if permanent_only else p diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 07c54d6add9..55f39acf67f 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1919,6 +1919,103 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse self.cache('rank', r) return r + def _solve_right_general(self, B, check=True): + """ + Solve the matrix equation AX = B for X using the M4RI library. + + INPUT: + + - ``B`` -- a matrix + - ``check`` -- boolean (default: ``True``); whether to check if the + matrix equation has a solution + + EXAMPLES:: + + sage: A = matrix(GF(2), [[1, 0], [0, 1], [1, 1]]) + sage: A.solve_right(vector([1, 1, 0])) + (1, 1) + sage: A.solve_right(vector([1, 1, 1])) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + + TESTS:: + + sage: n = 128 + sage: m = 128 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: m = 64 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: m = 256 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2)) == matrix(GF(2), 0, 2) + True + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2) + 1) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2) + 1, check=False) == matrix(GF(2), 0, 2) + True + sage: matrix(GF(2), 2, 2).solve_right(matrix(GF(2), 2, 0)) == matrix(GF(2), 2, 0) + True + + Check that it can be interrupted:: + + sage: set_random_seed(12345) + sage: n, m = 20000, 19968 + sage: A = random_matrix(GF(2), n, m) + sage: x = random_vector(GF(2), m) + sage: B = A*x + sage: alarm(0.5); sol = A.solve_right(B) + Traceback (most recent call last): + ... + AlarmInterrupt + """ + cdef mzd_t *B_entries = (B)._entries + + cdef Matrix_mod2_dense X # the solution + X = self.new_matrix(nrows=self._entries.ncols, ncols=B_entries.ncols) + if self._entries.ncols == 0 or B_entries.ncols == 0: + # special case: empty matrix + if check and B != 0: + raise ValueError("matrix equation has no solutions") + return X + cdef rci_t rows = self._entries.nrows + if self._entries.nrows < self._entries.ncols: + rows = self._entries.ncols # mzd_solve_left requires ncols <= nrows + + cdef mzd_t *lhs = mzd_init(rows, self._entries.ncols) + mzd_copy(lhs, self._entries) + cdef mzd_t *rhs = mzd_init(rows, B_entries.ncols) + mzd_copy(rhs, B_entries) + + cdef int ret + try: + sig_on() + # although it is called mzd_solve_left, it does the same thing as solve_right + ret = mzd_solve_left(lhs, rhs, 0, check) + sig_off() + + if ret == 0: + # solution is placed in rhs + rhs.nrows = self._entries.ncols + mzd_copy(X._entries, rhs) + return X + else: + raise ValueError("matrix equation has no solutions") + finally: + mzd_free(lhs) + mzd_free(rhs) + def _right_kernel_matrix(self, **kwds): r""" Return a pair that includes a matrix of basis vectors diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 177cebffb38..96ea3b69ad8 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -3241,4 +3241,3 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [0 1] """ return self._entries[j+i*self._ncols] == 0 - diff --git a/src/sage/matrix/meson.build b/src/sage/matrix/meson.build index 932ac4c40c2..a0168c1a117 100644 --- a/src/sage/matrix/meson.build +++ b/src/sage/matrix/meson.build @@ -98,7 +98,7 @@ extension_data = { foreach name, pyx : extension_data dependencies = [py_dep, cysignals, gmp] if name == 'matrix_gfpn_dense' - dependencies += [mtx, meataxe] + dependencies += [mtx] elif name == 'matrix_gap' dependencies += [gap] elif name == 'misc_mpfr' diff --git a/src/sage/matroids/chow_ring.py b/src/sage/matroids/chow_ring.py index 173c8db7f84..92e48f7147f 100644 --- a/src/sage/matroids/chow_ring.py +++ b/src/sage/matroids/chow_ring.py @@ -11,6 +11,7 @@ from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.commutative_rings import CommutativeRings + class ChowRing(QuotientRing_generic): r""" The Chow ring of a matroid. @@ -336,4 +337,4 @@ def homogeneous_degree(self): f = self.lift() if not f.is_homogeneous(): raise ValueError("element is not homogeneous") - return f.degree() \ No newline at end of file + return f.degree() diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 8548b2bfede..f1c0af7bea7 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -805,11 +805,11 @@ def Matroid(groundset=None, data=None, **kwds): if isinstance(data, Graph): key = 'graph' elif isinstance(data, Matrix) or ( - isinstance(data, tuple) and isinstance(data[0], Matrix)): + isinstance(data, tuple) and isinstance(data[0], Matrix)): key = 'matrix' elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or ( - isinstance(data, tuple) and - isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): + isinstance(data, tuple) and + isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): key = 'morphism' elif isinstance(data, sage.matroids.matroid.Matroid): key = 'matroid' @@ -1032,11 +1032,9 @@ def revlex_sort_key(s): subsets = sorted(combinations(range(N), rk), key=revlex_sort_key) if len(data) != len(subsets): raise ValueError("expected string of length %s (%s choose %s), got %s" % - (len(subsets), N, rk, len(data))) - bases = [] - for i, x in enumerate(data): - if x != '0': - bases.append([groundset[c] for c in subsets[i]]) + (len(subsets), N, rk, len(data))) + bases = [[groundset[c] for c in subsets[i]] + for i, x in enumerate(data) if x != '0'] M = BasisMatroid(groundset=groundset, bases=bases) # Circuit closures: diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index d4dce31ddc2..3c7c92e6c9c 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -53,6 +53,7 @@ from sage.matroids.matroid import Matroid + class DualMatroid(Matroid): r""" Dual of a matroid. diff --git a/src/sage/matroids/meson.build b/src/sage/matroids/meson.build index 43c80789811..f60970da5b9 100644 --- a/src/sage/matroids/meson.build +++ b/src/sage/matroids/meson.build @@ -4,6 +4,8 @@ py.install_sources( 'basis_exchange_matroid.pxd', 'basis_matroid.pxd', 'catalog.py', + 'chow_ring.py', + 'chow_ring_ideal.py', 'circuit_closures_matroid.pxd', 'circuits_matroid.pxd', 'constructor.py', diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 52c10174dca..f800cfd27f1 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -1462,7 +1462,7 @@ class CachedMethodPickle(): we replace the actual cached method by a place holder, that kills itself as soon as any attribute is requested. Then, the original cached attribute is reinstated. But the - cached values are in fact saved (if `do_pickle` is set.) + cached values are in fact saved (if ``do_pickle`` is set.) EXAMPLES:: diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index ccd4b1da87c..e245249af20 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -162,9 +162,7 @@ def eval(self, x, globals=None, locals=None): # What follows are the arguments to f2py itself (appended later # just for logical separation) - cmd += ['-c', '-m', name, fortran_file, '--quiet', - '--f77exec=sage-inline-fortran', - '--f90exec=sage-inline-fortran'] + s_lib_path + s_lib + cmd += ['-c', '-m', name, fortran_file, '--quiet', '--backend', 'meson'] + s_lib_path + s_lib try: out = subprocess.check_output(cmd, stderr=subprocess.STDOUT) diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 7429388112e..15476a3ec37 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -57,7 +57,7 @@ from sage.misc.sage_unittest import TestSuite # Apart from this, you are free to use these variables as you like. # # However, the standard utilisation is the following. -# The pickling method (namely `__reduce__`) checks if the id of the +# The pickling method (namely ``__reduce__``) checks if the id of the # current element appears in the dictionary `already_pickled`. If it # does not, the methods records that this element is about to be # pickled by adding the entry { id: True } to `already_pickled`. diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 6aaa8e6fb6f..fcc63bb1013 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -105,7 +105,7 @@ def deprecation_cython(issue_number, message, stacklevel=3): TESTS: - We check that `deprecation_cython` in a cython function generates a warning + We check that ``deprecation_cython`` in a cython function generates a warning with the same callsite reference as `deprecation` in a python function, whereas `deprecation` in a cython function does not:: diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 086e8fd49ed..61ead0537b1 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -69,11 +69,11 @@ class table(SageObject): \end{tabular} sage: table(rows=rows, frame=True) ┌─────┬───┬────┐ - │ a | b | c | + │ a │ b │ c │ ├─────┼───┼────┤ - │ 100 | 2 | 3 | + │ 100 │ 2 │ 3 │ ├─────┼───┼────┤ - │ 4 | 5 | 60 | + │ 4 │ 5 │ 60 │ └─────┴───┴────┘ sage: latex(table(rows=rows, frame=True)) \begin{tabular}{|l|l|l|} \hline @@ -83,11 +83,11 @@ class table(SageObject): \end{tabular} sage: table(rows, header_column=True, frame=True) ┌─────╥───┬────┐ - │ a ║ b | c | + │ a ║ b │ c │ ├─────╫───┼────┤ - │ 100 ║ 2 | 3 | + │ 100 ║ 2 │ 3 │ ├─────╫───┼────┤ - │ 4 ║ 5 | 60 | + │ 4 ║ 5 │ 60 │ └─────╨───┴────┘ sage: latex(table(rows, header_row=True, frame=True)) \begin{tabular}{|l|l|l|} \hline @@ -109,15 +109,15 @@ class table(SageObject): sage: table([(x,n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_row=["$x$", r"$\sin(x)$"], frame=True) ┌─────┬───────────┐ - │ $x$ | $\sin(x)$ | + │ $x$ │ $\sin(x)$ │ ╞═════╪═══════════╡ - │ 0 | 0.00 | + │ 0 │ 0.00 │ ├─────┼───────────┤ - │ 1 | 0.84 | + │ 1 │ 0.84 │ ├─────┼───────────┤ - │ 2 | 0.91 | + │ 2 │ 0.91 │ ├─────┼───────────┤ - │ 3 | 0.14 | + │ 3 │ 0.14 │ └─────┴───────────┘ You can create the transpose of this table in several ways, for @@ -127,9 +127,9 @@ class table(SageObject): ....: [n(sin(x), digits=2) for x in [0..3]]], ....: header_column=['$x$', r'$\sin(x)$'], frame=True) ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ or by passing the original data as the ``columns`` of the table @@ -138,9 +138,9 @@ class table(SageObject): sage: table(columns=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_column=['$x$', r'$\sin(x)$'], frame=True) ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ or by taking the :meth:`transpose` of the original table:: @@ -148,9 +148,9 @@ class table(SageObject): sage: table(rows=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_row=['$x$', r'$\sin(x)$'], frame=True).transpose() ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ In either plain text or LaTeX, entries in tables can be aligned to the @@ -166,11 +166,11 @@ class table(SageObject): 4 5 60 sage: table(rows, align='right', frame=True) ┌─────┬───┬────┐ - │ a | b | c | + │ a │ b │ c │ ├─────┼───┼────┤ - │ 100 | 2 | 3 | + │ 100 │ 2 │ 3 │ ├─────┼───┼────┤ - │ 4 | 5 | 60 | + │ 4 │ 5 │ 60 │ └─────┴───┴────┘ To generate HTML you should use ``html(table(...))``:: @@ -253,7 +253,7 @@ def __init__(self, rows=None, columns=None, header_row=False, sage: table([1,2,3], frame=True) ┌───┬───┬───┐ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ └───┴───┴───┘ """ # If both rows and columns are set, raise an error. @@ -342,20 +342,20 @@ def options(self, **kwds): sage: T = table([[1,2,3], [4,5,6]], header_row=['a', 'b', 'c'], frame=True) sage: T ┌───┬───┬───┐ - │ a | b | c | + │ a │ b │ c │ ╞═══╪═══╪═══╡ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ ├───┼───┼───┤ - │ 4 | 5 | 6 | + │ 4 │ 5 │ 6 │ └───┴───┴───┘ sage: T.options(header_row=False) sage: T ┌───┬───┬───┐ - │ a | b | c | + │ a │ b │ c │ ├───┼───┼───┤ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ ├───┼───┼───┤ - │ 4 | 5 | 6 | + │ 4 │ 5 │ 6 │ └───┴───┴───┘ If you do specify a list for ``header_row``, an error is raised:: @@ -398,11 +398,11 @@ def transpose(self): sage: T = table([[1,2,3], [4,5,6]], header_row=['x', 'y', 'z'], frame=True) sage: T.transpose() ┌───╥───┬───┐ - │ x ║ 1 | 4 | + │ x ║ 1 │ 4 │ ├───╫───┼───┤ - │ y ║ 2 | 5 | + │ y ║ 2 │ 5 │ ├───╫───┼───┤ - │ z ║ 3 | 6 | + │ z ║ 3 │ 6 │ └───╨───┴───┘ """ return table(list(zip(*self._rows)), @@ -508,7 +508,7 @@ def _str_table_row(self, row, header_row=False, last_row=False): ' 1 │ 2 3\n├────┼─────┼───────┤\n' sage: T.options(frame=True) sage: T._str_table_row([1,2,3], False) - '│ 1 ║ 2 | 3 |\n├────╫─────┼───────┤\n' + '│ 1 ║ 2 │ 3 │\n├────╫─────┼───────┤\n' Check that :issue:`14601` has been fixed:: @@ -552,7 +552,7 @@ def _str_table_row(self, row, header_row=False, last_row=False): for entry, width in zip(row, widths): s += ("{!s:" + align_char + str(width) + "}").format(entry) if frame: - s += " | " + s += " │ " else: s += " " s = s.rstrip(' ') @@ -696,15 +696,15 @@ def _html_(self): ....: header_row=True, frame=True) sage: T # needs sage.symbolic ┌─────┬───────────┐ - │ $x$ | $\sin(x)$ | + │ $x$ │ $\sin(x)$ │ ╞═════╪═══════════╡ - │ 0 | 0.00 | + │ 0 │ 0.00 │ ├─────┼───────────┤ - │ 1 | 0.84 | + │ 1 │ 0.84 │ ├─────┼───────────┤ - │ 2 | 0.91 | + │ 2 │ 0.91 │ ├─────┼───────────┤ - │ 3 | 0.14 | + │ 3 │ 0.14 │ └─────┴───────────┘ sage: print(html(T)) # needs sage.symbolic
diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 92b1e9f9abe..c1e0733f38c 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -4501,11 +4501,11 @@ def decomposition(self, simple=True, bound=None): else: X = A.decomposition(bound=bound) for B in X: - for t in divisors(M // N): - D.append(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), - is_simple=True, newform_level=(N, G), - isogeny_number=isogeny_number, - number=(t, M))) + D.extend(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), + is_simple=True, newform_level=(N, G), + isogeny_number=isogeny_number, + number=(t, M)) + for t in divisors(M // N)) isogeny_number += 1 elif A == amb.cuspidal_submodule(): D = [ModularAbelianVariety_modsym(B) diff --git a/src/sage/modular/arithgroup/congroup.pyx b/src/sage/modular/arithgroup/congroup.pyx index d55c0c0ce7c..4972b39f435 100644 --- a/src/sage/modular/arithgroup/congroup.pyx +++ b/src/sage/modular/arithgroup/congroup.pyx @@ -31,7 +31,7 @@ from sage.rings.integer_ring import ZZ Mat2Z = MatrixSpace(ZZ, 2) cdef Matrix_integer_dense genS, genT, genI -genS = Matrix_integer_dense(Mat2Z, [0,-1, 1, 0], True, True) +genS = Matrix_integer_dense(Mat2Z, [0, -1, 1, 0], True, True) genT = Matrix_integer_dense(Mat2Z, [1, 1, 0, 1], True, True) genI = Matrix_integer_dense(Mat2Z, [1, 0, 0, 1], True, True) @@ -123,7 +123,7 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): # try to find another coset representative. cc = M*random.randrange(-halfmax, halfmax+1) dd = random.randrange(-halfmax, halfmax+1) - g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa) + g = arith_int.c_xgcd_int(-cc, dd, &bb, &aa) if g == 0: continue cc = cc // g @@ -297,22 +297,24 @@ def generators_helper(coset_reps, level): [21 5], [ 7 -1], [-7 1] ] """ - cdef Matrix_integer_dense x,y,z,v,vSmod,vTmod + cdef Matrix_integer_dense x, y, z, v, vSmod, vTmod crs = coset_reps.list() try: - reps = [Matrix_integer_dense(Mat2Z,lift_to_sl2z(c, d, level),False,True) for c,d in crs] + reps = [Matrix_integer_dense(Mat2Z, lift_to_sl2z(c, d, level), + False, True) for c, d in crs] except Exception: raise ArithmeticError("Error lifting to SL2Z: level=%s crs=%s" % (level, crs)) ans = [] cdef Py_ssize_t i for i in range(len(crs)): x = reps[i] - v = Matrix_integer_dense(Mat2Z,[crs[i][0],crs[i][1],0,0],False,True) + v = Matrix_integer_dense(Mat2Z, [crs[i][0], crs[i][1], 0, 0], + False, True) vSmod = (v*genS) vTmod = (v*genT) - y_index = coset_reps.normalize(vSmod[0,0],vSmod[0,1]) - z_index = coset_reps.normalize(vTmod[0,0],vTmod[0,1]) + y_index = coset_reps.normalize(vSmod[0, 0], vSmod[0, 1]) + z_index = coset_reps.normalize(vTmod[0, 0], vTmod[0, 1]) y_index = crs.index(y_index) z_index = crs.index(z_index) y = reps[y_index] diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index c965015b41d..af81a0f61fc 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -13,15 +13,15 @@ based on the *KFarey* package by Chris Kurth. Implemented as C++ module for speed. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Hartmut Monien # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.object cimport PyObject_RichCompare from itertools import groupby @@ -206,11 +206,11 @@ cdef class Farey: self.this_ptr = new cpp_farey(data) sig_off() return - ## to accelerate the calculation of the FareySymbol - ## we implement the tests for the standard congruence groups - ## in the c++ module. For a general group the test if an element - ## of SL2Z is in the group the python __contains__ attribute - ## of the group is called + # to accelerate the calculation of the FareySymbol + # we implement the tests for the standard congruence groups + # in the c++ module. For a general group the test if an element + # of SL2Z is in the group the python __contains__ attribute + # of the group is called cdef int p if hasattr(group, "level"): p = group.level() @@ -285,19 +285,19 @@ cdef class Farey: a, b, c, d = pm.matrix().list() newval = gens_dict.get(SL2Z([a, b, c, d])) if newval is not None: - ans.append((newval,1)) + ans.append((newval, 1)) continue newval = gens_dict.get(SL2Z([-a, -b, -c, -d])) if newval is not None: - ans.append((newval,-1)) + ans.append((newval, -1)) continue newval = gens_dict.get(SL2Z([d, -b, -c, a])) if newval is not None: - ans.append((-newval,1)) + ans.append((-newval, 1)) continue newval = gens_dict.get(SL2Z([-d, b, c, -a])) if newval is not None: - ans.append((-newval,-1)) + ans.append((-newval, -1)) continue raise RuntimeError("This should have not happened") return ans @@ -453,7 +453,7 @@ cdef class Farey: result = self.this_ptr.word_problem(a.value, b.value, c.value, d.value, cpp_beta) sig_off() beta = convert_to_SL2Z(cpp_beta[0])**-1 - mbeta = SL2Z([-beta.a(),-beta.b(),-beta.c(),-beta.d()]) + mbeta = SL2Z([-beta.a(), -beta.b(), -beta.c(), -beta.d()]) V = self.pairing_matrices_to_tietze_index() sgn = 1 tietze = [] @@ -500,7 +500,7 @@ cdef class Farey: tietze.reverse() gens = self.generators() if check: - tmp = SL2Z([1,0,0,1]) + tmp = SL2Z([1, 0, 0, 1]) for i in range(len(tietze)): t = tietze[i] tmp = tmp * gens[t-1] if t > 0 else tmp * gens[-t-1]**-1 @@ -1009,7 +1009,7 @@ cdef class Farey: fill=options['fill'], linestyle=options['linestyle'], thickness=options['thickness']) - ## show pairings + # show pairings p = self.pairings() x = self.fractions() if options['show_pairing']: @@ -1033,7 +1033,7 @@ cdef class Farey: return g -#--- conversions ------------------------------------------------------------ +# ----- conversions --------------------------------- cdef public long convert_to_long(n) noexcept: cdef long m = n diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index a063255c6a6..4b2d1e6ea2d 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -541,8 +541,8 @@ def basis(self, reduce=True) -> list: for di in divs: # generate a row of relation matrix row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)] - for p in primedivs: - row.append(Mod(12 * (N // di).valuation(p), 24)) + row.extend(Mod(12 * (N // di).valuation(p), 24) + for p in primedivs) rows.append(row) M = matrix(IntegerModRing(24), rows) @@ -717,8 +717,8 @@ def AllCusps(N) -> list: if n == 1: c.append(CuspFamily(N, d)) elif n > 1: - for i in range(n): - c.append(CuspFamily(N, d, label=str(i + 1))) + c.extend(CuspFamily(N, d, label=str(i + 1)) + for i in range(n)) return c @@ -1036,9 +1036,7 @@ def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): if verbose: print("Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1)) - rows = [] - for j in range(qexp_terms): - rows.append([]) + rows = [[] for _ in range(qexp_terms)] for i in indices: func = (eta1**i[0] * eta2**i[1]).qexp(qexp_terms) for j in range(qexp_terms): diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 383a4e0c035..7c209d146b6 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -91,7 +91,6 @@ def _heckebasis(M): MM = MatrixSpace(QQ, d) S = [] Denom = [] - B = [] B1 = [] for i in range(1, M.hecke_bound() + 1): v = M.hecke_operator(i).matrix() @@ -99,11 +98,9 @@ def _heckebasis(M): Denom.append(den) S.append(v) den = lcm(Denom) - for m in S: - B.append(WW((den * m).list())) + B = [WW((den * m).list()) for m in S] UU = WW.submodule(B) - B = UU.basis() - for u in B: + for u in UU.basis(): u1 = u.list() m1 = M.hecke_algebra()(MM(u1), check=False) B1.append((1 / den) * m1) diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 3ce44fa63ce..0e769d47ace 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -242,10 +242,8 @@ def decomposition_matrix(self): try: return self.__decomposition_matrix_cache except AttributeError: - rows = [] - for A in self.decomposition(): - for x in A.basis(): - rows.append(x.list()) + rows = [x.list() for A in self.decomposition() + for x in A.basis()] A = matrix_space.MatrixSpace(self.base_ring(), self.rank())(rows) self.__decomposition_matrix_cache = A return self.__decomposition_matrix_cache diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 5418a1fff58..393312443bd 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -685,7 +685,7 @@ def zigzag(self, x, flip_beta=False): Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. This function is used to compute the weight and the Hodge numbers. - With `flip_beta` set to ``True``, replace each `b` in `\beta` + With ``flip_beta`` set to ``True``, replace each `b` in `\beta` with `1-b`. .. SEEALSO:: @@ -1317,7 +1317,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): If left unspecified, `prec` is set to the minimum `p`-adic precision needed to recover the Euler factor. - If `cache_p` is ``True``, then the function caches an intermediate + If ``cache_p`` is ``True``, then the function caches an intermediate result which depends only on `p` and `f`. This leads to a significant speedup when iterating over `t`. @@ -1933,13 +1933,13 @@ def euler_factor(self, t, p, deg=None, cache_p=False): P = PolynomialRing(ZZ, 'T') if t.numerator() % p == 0 or t.denominator() % p == 0: ans = P.one() - for m in set(j for i in self.cyclotomic_data() for j in i): + for m in {j for i in self.cyclotomic_data() for j in i}: ans *= self.euler_factor_tame_contribution(t, p, m, deg) if deg is not None: ans = ans.truncate(deg + 1) return ans # now p is good, or p is tame and t is a p-adic unit - elif (t-1) % p == 0: + elif (t - 1) % p == 0: typ = "mult" d = self.degree() - 1 if d % 2: diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index ddd4ed467bc..6d6d8a1c575 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -288,3 +288,18 @@ def hecke_module_of_level(self, N): return constructor.ModularForms(self.character().restrict(N), self.weight(), self.base_ring(), prec=self.prec()) else: raise ValueError("N (=%s) must be a divisor or a multiple of the level of self (=%s)" % (N, self.level())) + + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: m = ModularForms(DirichletGroup(17).0^2, 2) + sage: pari.mfdim(m) + 3 + sage: pari.mfparams(m) + [17, 2, Mod(9, 17), 4, t^4 + 1] + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 4) diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index 5de0805b386..90cf7758cdc 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -377,6 +377,21 @@ def _compute_q_expansion_basis(self, prec=None): return [weight1.modular_ratio_to_prec(chi, f, prec) for f in weight1.hecke_stable_subspace(chi)] + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: A = CuspForms(DirichletGroup(23, QQ).0, 1) + sage: pari.mfparams(A) + [23, 1, -23, 1, t + 1] + sage: pari.mfdim(A) + 1 + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 1) + class CuspidalSubmodule_wt1_gH(CuspidalSubmodule): r""" diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index fbbe2e06da3..72665f3d686 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -586,6 +586,22 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): q^5 + (zeta3 + 1)*q^8 + O(q^10) ] """ + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: e = DirichletGroup(27,CyclotomicField(3)).0**2 + sage: M = ModularForms(e,2,prec=10).eisenstein_subspace() + sage: pari.mfdim(M) + 6 + sage: pari.mfparams(M) + [27, 2, Mod(10, 27), 3, t^2 + t + 1] + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 3) + # TODO # def _compute_q_expansion_basis(self, prec): # B = EisensteinSubmodule_params._compute_q_expansion_basis(self, prec) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 6ce83f0372e..441812135b6 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -219,6 +219,38 @@ def _repr_(self): """ return str(self.q_expansion()) + def _pari_init_(self): + """ + Conversion to Pari. + + TESTS:: + + sage: M = EisensteinForms(96, 2) + sage: M.6 + O(q^6) + sage: M.7 + O(q^6) + sage: pari(M.6) == pari(M.7) + False + sage: pari(M.6).mfcoefs(10) + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + + sage: M = ModularForms(DirichletGroup(17).0^2, 2) + sage: pari(M.0).mfcoefs(5) + [0, 1, Mod(-t^3 + t^2 - 1, t^4 + 1), Mod(t^3 - t^2 - t - 1, t^4 + 1), Mod(2*t^3 - t^2 + 2*t, t^4 + 1), Mod(-t^3 - t^2, t^4 + 1)] + sage: M.0.qexp(5) + q + (-zeta8^3 + zeta8^2 - 1)*q^2 + (zeta8^3 - zeta8^2 - zeta8 - 1)*q^3 + (2*zeta8^3 - zeta8^2 + 2*zeta8)*q^4 + O(q^5) + """ + from sage.libs.pari import pari + from sage.rings.number_field.number_field_element import NumberFieldElement + M = pari(self.parent()) + f = self.qexp(self.parent().sturm_bound()) + coefficients = [ + x.__pari__('t') if isinstance(x, NumberFieldElement) else x + for x in f] + # we cannot compute pari(f) directly because we need to set the variable name as t + return M.mflinear(M.mftobasis(coefficients + [0] * (f.prec() - len(coefficients)))) + def __call__(self, x, prec=None): """ Evaluate the `q`-expansion of this modular form at x. @@ -233,9 +265,150 @@ def __call__(self, x, prec=None): sage: f(0) 0 - """ + + Evaluate numerically:: + + sage: f = ModularForms(1, 12).0 + sage: f(0.3) # rel tol 1e-12 + 2.34524576548591e-6 + sage: f = EisensteinForms(1, 4).0 + sage: f(0.9) # rel tol 1e-12 + 1.26475942209241e7 + + TESTS:: + + sage: f = ModularForms(96, 2).0 + sage: f(0.3) # rel tol 1e-12 + 0.299999997396191 + sage: f(0.0+0.0*I) + 0 + + For simplicity, ``float`` or ``complex`` input are converted to ``CC``, except for + input ``0`` where exact result is returned:: + + sage: result = f(0.3r); result # rel tol 1e-12 + 0.299999997396191 + sage: result.parent() + Complex Field with 53 bits of precision + sage: result = f(0.3r + 0.3jr); result # rel tol 1e-12 + 0.299999359878484 + 0.299999359878484*I + sage: result.parent() + Complex Field with 53 bits of precision + + Symbolic numerical values use precision of ``CC`` by default:: + + sage: f(sqrt(1/2)) # rel tol 1e-12 + 0.700041406692037 + sage: f(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12 + 0.496956554651376 + 0.496956554651376*I + + Higher precision:: + + sage: f(ComplexField(128)(0.3)) # rel tol 1e-36 + 0.29999999739619131029285166058750164058 + sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 0.32165384572356882556790532669389900691 + 0.67061244638367586302820790711257777390*I + + Confirm numerical evaluation matches the q-expansion:: + + sage: f = EisensteinForms(1, 4).0 + sage: f(0.3) # rel tol 1e-12 + 741.741819297986 + sage: f.qexp(50).polynomial()(0.3) # rel tol 1e-12 + 741.741819297986 + + With a nontrivial character:: + + sage: M = ModularForms(DirichletGroup(17).0^2, 2) + sage: M.0(0.5) # rel tol 1e-12 + 0.166916655031616 + 0.0111529051752428*I + sage: M.0.qexp(60).polynomial()(0.5) # rel tol 1e-12 + 0.166916655031616 + 0.0111529051752428*I + + Higher precision:: + + sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I + sage: f.qexp(400).polynomial()(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 429.19994832206294278688085399056359631 - 786.15736284188243351153830824852974999*I + + Check ``SR`` does not make the result lose precision:: + + sage: f(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36 + 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I + """ + from sage.rings.integer import Integer + from sage.misc.functional import log + from sage.structure.element import parent + from sage.rings.complex_mpfr import ComplexNumber + from sage.rings.cc import CC + from sage.rings.real_mpfr import RealNumber + from sage.symbolic.constants import pi + from sage.rings.imaginary_unit import I # import from here instead of sage.symbolic.constants to avoid cast to SR + from sage.symbolic.expression import Expression + if isinstance(x, Expression): + try: + x = x.pyobject() + except TypeError: + pass + if x in CC: + if x == 0: + return self.qexp(1)[0] + if not isinstance(x, (RealNumber, ComplexNumber)): + x = CC(x) # might lose precision if this is done unconditionally (TODO what about interval and ball types?) + if isinstance(x, (RealNumber, ComplexNumber)): + return self.eval_at_tau(log(x)/(2*parent(x)(pi)*I)) # cast to parent(x) to force numerical evaluation of pi return self.q_expansion(prec)(x) + def eval_at_tau(self, tau): + r""" + Evaluate this modular form at the half-period ratio `\tau`. + This is related to `q` by `q = e^{2\pi i \tau}`. + + EXAMPLES:: + + sage: f = ModularForms(1, 12).0 + sage: f.eval_at_tau(0.3 * I) # rel tol 1e-12 + 0.00150904633897550 + + TESTS: + + Symbolic numerical values use precision of ``CC`` by default:: + + sage: f.eval_at_tau(sqrt(1/5)*I) # rel tol 1e-12 + 0.0123633234207127 + sage: f.eval_at_tau(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12 + -0.114263670441098 + + For simplicity, ``complex`` input are converted to ``CC``:: + + sage: result = f.eval_at_tau(0.3jr); result # rel tol 1e-12 + 0.00150904633897550 + sage: result.parent() + Complex Field with 53 bits of precision + + Check ``SR`` does not make the result lose precision:: + + sage: f = EisensteinForms(1, 4).0 + sage: f.eval_at_tau(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36 + -1.0451570582202060056197878314286036966 + 2.7225112098519803098203933583286590274*I + """ + from sage.libs.pari.convert_sage import gen_to_sage + from sage.libs.pari import pari + from sage.rings.cc import CC + from sage.rings.complex_mpfr import ComplexNumber, ComplexField + from sage.rings.real_mpfr import RealNumber + from sage.symbolic.expression import Expression + if isinstance(tau, Expression): + try: + tau = tau.pyobject() + except TypeError: + pass + if not isinstance(tau, (RealNumber, ComplexNumber)): + tau = CC(tau) + precision = tau.prec() + return ComplexField(precision)(pari.mfeval(self.parent(), self, tau, precision=precision)) + @cached_method def valuation(self): """ diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 6aedcba881c..f4a4c3a892b 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -1383,7 +1383,7 @@ def rational_period_functions(self, k, D): The method assumes that ``D > 0``. - Also see the element method `rational_period_function` for more information. + Also see the element method ``rational_period_function`` for more information. - ``k`` -- even integer, the desired weight of the rational period functions diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index beb8509af0f..56e01e8c106 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -1761,9 +1761,9 @@ def factorization(self): else: A._is_simple = True D.append((A, n)) - # The eisenstein part - for E in self.eisenstein_submodule().decomposition(anemic=True): - D.append((E, 1)) + # The Eisenstein part + D.extend((E, 1) for E in + self.eisenstein_submodule().decomposition(anemic=True)) r = self.dimension() s = sum(A.rank() * mult for A, mult in D) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 82adf9efa20..598e8ccfff9 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -202,8 +202,8 @@ cdef class Heilbronn: b[i] = (u * self.list.v[4*i+1]) % N + (v * self.list.v[4*i+3]) % N else: for i in range(self.length): - a[i] = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) - b[i] = llong_prod_mod(u,self.list.v[4*i+1],N) + llong_prod_mod(v,self.list.v[4*i+3], N) + a[i] = llong_prod_mod(u, self.list.v[4*i], N) + llong_prod_mod(v, self.list.v[4*i+2], N) + b[i] = llong_prod_mod(u, self.list.v[4*i+1], N) + llong_prod_mod(v, self.list.v[4*i+3], N) sig_off() cdef apply_to_polypart(self, fmpz_poly_t* ans, int i, int k): @@ -283,8 +283,8 @@ cdef class Heilbronn: else: for i in range(self.length): sig_check() - a = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) - b = llong_prod_mod(u,self.list.v[4*i+1],N) + llong_prod_mod(v,self.list.v[4*i+3], N) + a = llong_prod_mod(u, self.list.v[4*i], N) + llong_prod_mod(v, self.list.v[4*i+2], N) + b = llong_prod_mod(u, self.list.v[4*i+1], N) + llong_prod_mod(v, self.list.v[4*i+3], N) export.c_p1_normalize_llong(N, a, b, &c, &d, &s, 0) X = (c, d) if X in M: @@ -368,15 +368,15 @@ cdef class HeilbronnCremona(Heilbronn): L = &self.list p = self.p - list_append4(L, 1,0,0,p) + list_append4(L, 1, 0, 0, p) # When p==2, then Heilbronn matrices are # [[1,0,0,2], [2,0,0,1], [2,1,0,1], [1,0,1,2]] # which are not given by the algorithm below. if p == 2: - list_append4(L, 2,0,0,1) - list_append4(L, 2,1,0,1) - list_append4(L, 1,0,1,2) + list_append4(L, 2, 0, 0, 1) + list_append4(L, 2, 1, 0, 1) + list_append4(L, 1, 0, 1, 2) self.length = 4 return @@ -489,20 +489,20 @@ cdef class HeilbronnMerel(Heilbronn): sig_on() for a in range(1, n+1): - ## We have ad-bc=n so c=0 and ad=n, or b=(ad-n)/c - ## Must have ad - n >= 0, so d must be >= Ceiling(n/a). + # We have ad-bc=n so c=0 and ad=n, or b=(ad-n)/c + # Must have ad - n >= 0, so d must be >= Ceiling(n/a). q = n // a if q*a == n: d = q for b in range(a): - list_append4(L, a,b,0,d) + list_append4(L, a, b, 0, d) for c in range(1, d): - list_append4(L, a,0,c,d) + list_append4(L, a, 0, c, d) for d in range(q+1, n+1): bc = (a) * (d) - (n) - ## Divisor c of bc must satisfy Floor(bc/c) lt a and c lt d. - ## c ge (bc div a + 1) <=> Floor(bc/c) lt a (for integers) - ## c le d - 1 <=> c lt d + # Divisor c of bc must satisfy Floor(bc/c) lt a and c lt d. + # c ge (bc div a + 1) <=> Floor(bc/c) lt a (for integers) + # c le d - 1 <=> c lt d for c in range(bc // a + 1, d): if bc % c == 0: list_append4(L, a, bc // c, c, d) @@ -569,7 +569,7 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): cdef Heilbronn H t = verbose("computing non-reduced images of symbol under Hecke operators", - level=1, caller_name='hecke_images_gamma0_weight2') + level=1, caller_name='hecke_images_gamma0_weight2') for i, n in enumerate(indices): # List the Heilbronn matrices of determinant n defined by Cremona or Merel H = HeilbronnCremona(n) if is_prime(n) else HeilbronnMerel(n) @@ -601,25 +601,25 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): sig_free(b) t = verbose("finished computing non-reduced images", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') t = verbose("Now reducing images of symbol", - level=1, caller_name='hecke_images_gamma0_weight2') + level=1, caller_name='hecke_images_gamma0_weight2') # Return the product T * R, whose rows are the image of (u,v) under # the Hecke operators T_n for n in indices. if max(indices) <= 30: # In this case T tends to be very sparse ans = T.sparse_matrix()._matrix_times_matrix_dense(R) verbose("did reduction using sparse multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') elif R.is_sparse(): ans = T * R.dense_matrix() verbose("did reduction using dense multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') else: ans = T * R verbose("did reduction using dense multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') if original_base_ring != QQ: ans = ans.change_ring(original_base_ring) @@ -700,7 +700,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) cdef Heilbronn H t = verbose("computing non-reduced images of symbol under Hecke operators", - level=1, caller_name='hecke_images_character_weight2') + level=1, caller_name='hecke_images_character_weight2') # Make a matrix over the rational numbers each of whose columns # are the values of the character chi. diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index 726f78c55a6..0a7feaffb5b 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -401,7 +401,7 @@ cdef class ManinSymbol(Element): N=int(N) if N < 1: raise ArithmeticError("N must be positive") - a,b,c,d = self.lift_to_sl2z() + a, b, c, d = self.lift_to_sl2z() return Cusp(b, d), Cusp(a, c) def weight(self): @@ -453,8 +453,7 @@ cdef class ManinSymbol(Element): # TODO: It would likely be much better to do this slightly more directly from sage.modular.modsym.modular_symbols import ModularSymbol x = ModularSymbol(self.parent(), self.i, 0, Infinity) - a,b,c,d = self.lift_to_sl2z() - return x.apply([a,b,c,d]) + return x.apply(self.lift_to_sl2z()) def _print_polypart(i, j): diff --git a/src/sage/modular/modsym/p1list.pxd b/src/sage/modular/modsym/p1list.pxd index b66f28b8ad6..b559922411c 100644 --- a/src/sage/modular/modsym/p1list.pxd +++ b/src/sage/modular/modsym/p1list.pxd @@ -6,8 +6,8 @@ cdef class export: int compute_s) except -1 cdef int c_p1_normalize_llong(self, int N, int u, int v, - int* uu, int* vv, int* ss, - int compute_s) except -1 + int* uu, int* vv, int* ss, + int compute_s) except -1 cdef class P1List: @@ -22,7 +22,7 @@ cdef class P1List: # for normalizing an element does not need to be used # every time the user calls the normalize function. cdef int (*_normalize)(int N, int u, int v, - int* uu, int* vv, int* ss, - int compute_s) except -1 + int* uu, int* vv, int* ss, + int compute_s) except -1 cpdef index(self, int u, int v) cdef index_and_scalar(self, int u, int v, int* i, int* s) diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 7ceda12d5c8..f7d5f4b209b 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -75,7 +75,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, v += N if u == 0: uu[0] = 0 - if arith_int.c_gcd_int(v,N) == 1: + if arith_int.c_gcd_int(v, N) == 1: vv[0] = 1 else: vv[0] = 0 @@ -96,7 +96,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, # Adjust s modulo N/g so it is coprime to N. if g != 1: d = N // g - while arith_int.c_gcd_int(s,N) != 1: + while arith_int.c_gcd_int(s, N) != 1: s = (s+d) % N # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N) @@ -112,7 +112,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, for k in range(2, g + 1): v = (v + vNg) % N t = (t + Ng) % N - if v N - #if N<=0 or N >= 2**31: - # raise OverflowError("Modulus is too large (must be < 46340)") - # return -1 + # if N <= 0 or N >= 2**31: + # raise OverflowError("Modulus is too large (must be < 46340)") + # return -1 u = u % N v = v % N @@ -333,14 +333,14 @@ cdef int c_p1_normalize_llong(int N, int u, int v, v += N if u == 0: uu[0] = 0 - if arith_int.c_gcd_int(v,N) == 1: + if arith_int.c_gcd_int(v, N) == 1: vv[0] = 1 else: vv[0] = 0 ss[0] = v return 0 - #g = xgcd_int_llong(u, N, &s, &t) + # g = xgcd_int_llong(u, N, &s, &t) g = arith_llong.c_xgcd_longlong(u, N, &ll_s, &ll_t) s = (ll_s % ll_N) t = (ll_t % ll_N) @@ -357,7 +357,7 @@ cdef int c_p1_normalize_llong(int N, int u, int v, # Adjust s modulo N/g so it is coprime to N. if g != 1: d = N // g - while arith_int.c_gcd_int(s,N) != 1: + while arith_int.c_gcd_int(s, N) != 1: s = (s+d) % N # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N) @@ -466,7 +466,7 @@ def p1list_llong(int N): if N == 1: return [(0, 0)] - lst = [(0,1)] + lst = [(0, 1)] c = 1 for d in range(N): lst.append((c, d)) @@ -720,7 +720,7 @@ cdef class P1List(): else: raise OverflowError("p1list not defined for such large N.") self.__list.sort() - self.__end_hash = dict([(x,i) for i, x in enumerate(self.__list[N+1:])]) + self.__end_hash = {x: i for i, x in enumerate(self.__list[N+1:])} # Allocate memory for xgcd table. self.g = NULL @@ -870,7 +870,7 @@ cdef class P1List(): cdef int c, d, N if self.__N == 1: - return [1,0,0,1] + return [1, 0, 0, 1] c, d = self.__list[i] N = self.__N @@ -909,9 +909,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, -u, v, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j def apply_S(self, int i): @@ -941,9 +941,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, -v, u, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j def apply_T(self, int i): @@ -973,9 +973,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, v, -u-v, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j cpdef index(self, int u, int v): @@ -1014,7 +1014,7 @@ cdef class P1List(): return -1 return 0 try: - return self.__end_hash[(uu,vv)] + self.__N + 1 + return self.__end_hash[(uu, vv)] + self.__N + 1 except KeyError: return -1 @@ -1053,7 +1053,7 @@ cdef class P1List(): i[0] = 0 return try: - i[0] = self.__end_hash[(uu,vv)] + self.__N + 1 + i[0] = self.__end_hash[(uu, vv)] + self.__N + 1 return except KeyError: i[0] = -1 @@ -1084,7 +1084,7 @@ cdef class P1List(): sage: all(L.index_of_normalized_pair(L[i][0],L[i][1])==i for i in range(len(L))) True """ - t, i = search(self.__list, (u,v)) + t, i = search(self.__list, (u, v)) if t: return i return -1 @@ -1129,7 +1129,7 @@ cdef class P1List(): """ cdef int uu, vv, ss self._normalize(self.__N, u, v, &uu, &vv, &ss, 0) - return (uu,vv) + return (uu, vv) def normalize_with_scalar(self, int u, int v): r""" @@ -1365,11 +1365,10 @@ def lift_to_sl2z(c, d, N): [1, 0, 0, 1] """ if N <= 46340: - return lift_to_sl2z_int(c,d,N) - elif N <= 2147483647: - return lift_to_sl2z_llong(c,d,N) - else: - raise NotImplementedError("N too large") + return lift_to_sl2z_int(c, d, N) + if N <= 2147483647: + return lift_to_sl2z_llong(c, d, N) + raise NotImplementedError("N too large") def _make_p1list(n): diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index f347da9a278..68a4faa47d4 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -236,15 +236,11 @@ def low_weight_generators(N, p, m, NN): [q + 116*q^4 + 115*q^5 + 102*q^6 + 121*q^7 + 96*q^8 + 106*q^9 + O(q^10)]], 4) """ M = ModularFormsRing(N, base_ring=Zmod(p)) - b = M.gen_forms(maxweight=8) - - weightbound = max([f.weight() for f in b]) - generators = [] - - for k in range(2, weightbound + 2, 2): - generators.append([f.qexp(NN).change_ring(Zmod(p ** m)) for f in b if f.weight() == k]) - + weightbound = max(f.weight() for f in b) + generators = [[f.qexp(NN).change_ring(Zmod(p ** m)) + for f in b if f.weight() == k] + for k in range(2, weightbound + 2, 2)] return generators, weightbound diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 85cccd3bb11..9ed53a955c9 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -43,7 +43,7 @@ from sage.rings.rational_field import QQ from sage.structure.element cimport Element from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool -#from sage.libs.flint.ulong_extras cimport * +# from sage.libs.flint.ulong_extras cimport * cdef long overflow = 1 << (4 * sizeof(long) - 1) cdef long underflow = -overflow @@ -360,8 +360,8 @@ cdef class Dist(ModuleElement): raise ValueError("self is zero") v = a.valuation(p) relprec = n - i - v -# verbose("p=%s, n-i=%s\nself.moment=%s, other.moment=%s" % (p, n-i, a, other._unscaled_moment(i)),level=2) -## RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision + # verbose("p=%s, n-i=%s\nself.moment=%s, other.moment=%s" % (p, n-i, a, other._unscaled_moment(i)),level=2) + # RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision if padic: if i < other_pr: alpha = (other._unscaled_moment(i) / a).add_bigoh(n - i) @@ -373,7 +373,7 @@ cdef class Dist(ModuleElement): else: alpha = 0 verbose("alpha = %s" % alpha, level = 2) -## RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision + # RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision while i < other_pr - 1: i += 1 verbose("comparing p moment %s" % i, level = 2) @@ -656,11 +656,11 @@ cdef class Dist(ModuleElement): zero = R(0) moments.extend([zero] * (M - k - 1)) mu = V(moments) - #val = mu.valuation() - #if val < 0: - # # This seems unnatural - # print("scaling by ", p, "^", -val, " to keep things integral") - # mu *= p**(-val) + # val = mu.valuation() + # if val < 0: + # # This seems unnatural + # print("scaling by ", p, "^", -val, " to keep things integral") + # mu *= p**(-val) return mu def _is_malformed(self): @@ -1129,7 +1129,7 @@ cdef class Dist_vector(Dist): """ # assert self._moments[0][0]==0, "not total measure zero" # print("result accurate modulo p^",self.moment(0).valuation(self.p) ) - #v=[0 for j in range(0,i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] + # v=[0 for j in range(0,i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] M = self.precision_relative() R = self.parent().base_ring() K = R.fraction_field() @@ -1361,7 +1361,7 @@ cdef class WeightKAction_vector(WeightKAction): sage: v * D._act.actor()(g) # indirect doctest (-107, 35, -12, 5) """ - #tim = verbose("Starting") + # tim = verbose("Starting") a, b, c, d = self._adjuster(g) # if g.parent().base_ring().is_exact(): # self._check_mat(a, b, c, d) @@ -1378,17 +1378,17 @@ cdef class WeightKAction_vector(WeightKAction): return B.change_ring(self.codomain().base_ring()) R = PowerSeriesRing(base_ring, 'y', default_prec=M) y = R.gen() - #tim = verbose("Checked, made R",tim) + # tim = verbose("Checked, made R",tim) # special case for small precision, large weight scale = (b + d * y) / (a + c * y) t = (a + c * y) ** k # will already have precision M cdef long row, col - #tim = verbose("Made matrix",tim) + # tim = verbose("Made matrix",tim) for col in range(M): for row in range(M): B.set_unsafe(row, col, t[row]) t *= scale - #verbose("Finished loop",tim) + # verbose("Finished loop",tim) # the changering here is annoying, but otherwise we have to # change ring each time we multiply B = B.change_ring(self.codomain().base_ring()) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 6b407414030..097db985ede 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -172,7 +172,7 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ########################################################################### import itertools @@ -185,7 +185,6 @@ import sage.rings.integer import sage.rings.integer_ring import sage.rings.rational_field -from sage.rings.ring import IntegralDomain from sage.categories.commutative_rings import CommutativeRings from sage.categories.fields import Fields from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets @@ -296,7 +295,7 @@ def create_object(self, version, key): and base_ring.is_maximal() and base_ring.class_number() == 1): return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - if isinstance(base_ring, IntegralDomain) or base_ring in IntegralDomains(): + if base_ring in IntegralDomains(): return FreeModule_ambient_domain(base_ring, rank, sparse=sparse) return FreeModule_ambient(base_ring, rank, sparse=sparse) diff --git a/src/sage/modules/free_module_element.pxd b/src/sage/modules/free_module_element.pxd index 084423a2714..25585564228 100644 --- a/src/sage/modules/free_module_element.pxd +++ b/src/sage/modules/free_module_element.pxd @@ -19,4 +19,3 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): # cdef'd methods cdef _new_c(self, object v) - diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index f840143a073..a9d074007f0 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -3451,7 +3451,7 @@ cdef class FreeModuleElement(Vector): # abstract base class The more general :meth:`sage.matrix.matrix2.tensor_product` is an operation on a pair of matrices. If we construct a pair of vectors as a column vector and a row vector, then an outer product and a - tensor product are identical. Thus `tensor_product` is a synonym + tensor product are identical. Thus ``tensor_product`` is a synonym for this method. :: sage: u = vector(QQ, [1/2, 1/3, 1/4, 1/5]) @@ -4047,7 +4047,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Differentiate with respect to var by differentiating each element with respect to var. - .. seealso: + .. SEEALSO:: :meth:`derivative` diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index a209ae79ee4..553f4b0931d 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -69,8 +69,9 @@ from sage.categories.commutative_rings import CommutativeRings from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.integral_domains import IntegralDomains from sage.modules import free_module -from sage.rings.ring import Field, IntegralDomain +from sage.rings.ring import Field import sage.matrix.matrix_space import sage.misc.latex as latex @@ -175,7 +176,7 @@ def FreeQuadraticModule(base_ring, rank, inner_product_matrix, M = FreeQuadraticModule_ambient_pid( base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) - elif isinstance(base_ring, IntegralDomain) or base_ring.is_integral_domain(): + elif base_ring in IntegralDomains(): M = FreeQuadraticModule_ambient_domain( base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) else: diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index c58f0f3ea1e..3f6a34e778c 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -1556,7 +1556,7 @@ def _fplll_enumerate(self, target=None): gmat = fpylll.IntegerMatrix(dim, dim) for i in range(dim): for j in range(dim): - gmat[i,j] = gram[i,j] + gmat[i, j] = gram[i, j] gso = fpylll.GSO.Mat(gmat, gram=True) ok = gso.update_gso() assert ok @@ -1564,11 +1564,12 @@ def _fplll_enumerate(self, target=None): coord = None if target is not None: coord = basis.solve_left(target) - Mu = 1 + matrix([gso.get_mu(i,j) for j in range(dim)] for i in range(dim)) + Mu = 1 + matrix([gso.get_mu(i, j) for j in range(dim)] + for i in range(dim)) coord *= Mu count = 8 - bound = gso.get_r(dim-1, dim-1) + bound = gso.get_r(dim - 1, dim - 1) seen = set() while True: enum = fpylll.Enumeration(gso, count, fpylll.EvaluatorStrategy.BEST_N_SOLUTIONS) @@ -1579,8 +1580,8 @@ def _fplll_enumerate(self, target=None): if len(combs) < count: bound *= 2 continue - for length,comb in combs: - vec = sum(ZZ(c)*b for c,b in zip(comb,basis)) + for length, comb in combs: + vec = sum(ZZ(c) * b for c, b in zip(comb, basis)) if tuple(vec) not in seen: yield vec seen.add(tuple(vec)) diff --git a/src/sage/modules/meson.build b/src/sage/modules/meson.build index bc505da9372..48aecfdf0f2 100644 --- a/src/sage/modules/meson.build +++ b/src/sage/modules/meson.build @@ -76,7 +76,10 @@ foreach name, pyx : extension_data ) endforeach -extension_data_cpp = {'vector_mod2_dense': files('vector_mod2_dense.pyx')} +extension_data_cpp = { + 'numpy_util' : files('numpy_util.pyx'), + 'vector_mod2_dense': files('vector_mod2_dense.pyx'), +} foreach name, pyx : extension_data_cpp py.extension_module( diff --git a/src/sage/modules/numpy_util.pxd b/src/sage/modules/numpy_util.pxd new file mode 100644 index 00000000000..95d84956039 --- /dev/null +++ b/src/sage/modules/numpy_util.pxd @@ -0,0 +1,6 @@ +from libc.stdint cimport uintptr_t +from sage.libs.m4ri cimport * + +cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1 +# Note: we don't actually need ``cimport`` to work, which means this header file is not used in practice +# neither do we need ``cpdef`` (``def`` is sufficient) diff --git a/src/sage/modules/numpy_util.pyx b/src/sage/modules/numpy_util.pyx new file mode 100644 index 00000000000..a3a90446694 --- /dev/null +++ b/src/sage/modules/numpy_util.pyx @@ -0,0 +1,66 @@ +# sage.doctest: optional - numpy +r""" +Utility functions for numpy. +""" + +cimport numpy as np +import numpy as np +from sage.libs.m4ri cimport * +from libc.stdint cimport uintptr_t + + +ctypedef fused numpy_integral: + np.int8_t + np.int32_t + np.int64_t + + +cdef set_mzd_from_numpy_unsafe(mzd_t* entries, np.ndarray[numpy_integral, ndim=1] x): + """ + Internal function. + Caller are responsible for checking the two arrays have the same length. + """ + for i in range(len(x)): + mzd_write_bit(entries, 0, i, x[i] & 1) + + +cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1: + """ + Set the entries in ``entries_addr`` from numpy array ``x``. + + INPUT: + + - ``entries_addr`` -- must be a ``mzd_t*`` casted to ``uintptr_t``; the casting + is necessary to pass it through Python boundary because of lazy import. + Do not pass arbitrary integer value here, will crash the program. + + - ``degree`` -- the length of the array + + - ``x`` -- a numpy array of integers or booleans, or any other object (in which + case this function will return ``False``) + + OUTPUT: ``True`` if successful, ``False`` otherwise. May throw ``ValueError``. + """ + cdef Py_ssize_t i + cdef np.ndarray[np.npy_bool, ndim=1] x_bool + cdef mzd_t* entries = entries_addr + if isinstance(x, np.ndarray): + if x.ndim != 1: + raise ValueError("numpy array must have dimension 1") + if x.shape[0] != degree: + raise ValueError("numpy array must have the right length") + if x.dtype == np.int8: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.int32: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.int64: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.bool_: + x_bool = x + for i in range(degree): + mzd_write_bit(entries, 0, i, x_bool[i]) + return True + return False diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index ca14af9b313..19f3f07d35c 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -46,6 +46,7 @@ from sage.rings.rational cimport Rational from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport rich_to_bool cimport sage.modules.free_module_element as free_module_element +from libc.stdint cimport uintptr_t from sage.libs.m4ri cimport * @@ -192,8 +193,44 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): TypeError: can...t initialize vector from nonzero non-list sage: (GF(2)**0).zero_vector() () + + Check construction from numpy arrays:: + + sage: # needs numpy + sage: import numpy + sage: VS = VectorSpace(GF(2),3) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int8)) + (0, 1, 1) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int32)) + (0, 1, 1) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int64)) + (0, 1, 1) + sage: VS(numpy.array([False,True,False], dtype=bool)) + (0, 1, 0) + sage: VS(numpy.array([[1]])) + Traceback (most recent call last): + ... + ValueError: numpy array must have dimension 1 + sage: VS(numpy.array([1,2,3,4])) + Traceback (most recent call last): + ... + ValueError: numpy array must have the right length + + Make sure it's reasonably fast:: + + sage: # needs numpy + sage: import numpy + sage: VS = VectorSpace(GF(2),2*10^7) + sage: v = VS(numpy.random.randint(0, 1, size=VS.dimension())) # around 300ms """ - cdef Py_ssize_t i + try: + import numpy + except ImportError: + pass + else: + from .numpy_util import set_mzd_from_numpy + if set_mzd_from_numpy(self._entries, self._degree, x): + return if isinstance(x, (list, tuple)): if len(x) != self._degree: raise TypeError("x must be a list of the right length") diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index 5271c7a6b38..09f2cd9d4df 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -27,6 +27,7 @@ from sage.modules.free_module_element import vector from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + class Representation_abstract: """ Abstract base class for representations of semigroups. diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index e7a2a9f6532..32196e004dc 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -241,12 +241,26 @@ def _element_constructor_(self, x, check=True): sage: F(F(w), check=False) a^2*b^2*c*a*b*a*c + + sage: F = FreeMonoid(3, 'a,b,c') + sage: G = FreeMonoid(2, 'a,c') + sage: F(G(Word("ac"))) + a*c """ # There should really be some careful type checking here... - if isinstance(x, FreeMonoidElement) and x.parent() is self: - return x - if isinstance(x, FreeMonoidElement) and x.parent() == self: - return self.element_class(self, x._element_list, check) + if isinstance(x, FreeMonoidElement): + P = x.parent() + if P is self: + return x + elif P == self: + return self.element_class(self, x._element_list, check) + elif all(v in self.variable_names() + for v in P.variable_names()): + reindex = [next(j for j, w in enumerate(self.variable_names()) + if v == w) + for v in P.variable_names()] + elt = [(reindex[i], exp) for i, exp in x._element_list] + return self.element_class(self, elt, check) if isinstance(x, (int, Integer)) and x == 1: return self.element_class(self, x, check) if isinstance(x, FiniteWord_class): diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 69b67e260f7..8f6efea8487 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -674,6 +674,7 @@ def dict(self): """ return copy(self._monomial) + class IndexedMonoid(Parent, IndexedGenerators, UniqueRepresentation): """ Base class for monoids with an indexed set of generators. @@ -859,6 +860,7 @@ def monoid_generators(self): gens = monoid_generators + class IndexedFreeMonoid(IndexedMonoid): """ Free monoid with an indexed set of generators. @@ -939,6 +941,7 @@ def gen(self, x): except (ValueError, TypeError, NotImplementedError): # Backup (e.g., if it is a string) return self.element_class(self, ((x, ZZ.one()),)) + class IndexedFreeAbelianMonoid(IndexedMonoid): """ Free abelian monoid with an indexed set of generators. diff --git a/src/sage/numerical/backends/cvxpy_backend_test.py b/src/sage/numerical/backends/cvxpy_backend_test.py index 1f5f030248e..d186a1054ce 100644 --- a/src/sage/numerical/backends/cvxpy_backend_test.py +++ b/src/sage/numerical/backends/cvxpy_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + @pytest.importorskip("cvxpy") class TestCVXPYBackend(GenericBackendTests): diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index b7962c3c877..edda183ade9 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -265,7 +265,7 @@ cdef class GenericBackend: @classmethod def _test_sense(cls, tester=None, **options): """ - Run tests on `set_sense` and `is_maximization`. + Run tests on ``set_sense`` and ``is_maximization``. TESTS:: diff --git a/src/sage/numerical/backends/generic_backend_test.py b/src/sage/numerical/backends/generic_backend_test.py index 2b5411fb64e..64c9eb44670 100644 --- a/src/sage/numerical/backends/generic_backend_test.py +++ b/src/sage/numerical/backends/generic_backend_test.py @@ -3,6 +3,7 @@ from sage.structure.sage_object import SageObject from sage.structure.sage_object_test import SageObjectTests + class GenericBackendTests(SageObjectTests): @pytest.fixture diff --git a/src/sage/numerical/backends/glpk_exact_backend_test.py b/src/sage/numerical/backends/glpk_exact_backend_test.py index 125e041f29e..67b169baa82 100644 --- a/src/sage/numerical/backends/glpk_exact_backend_test.py +++ b/src/sage/numerical/backends/glpk_exact_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + class TestGLPKExactBackend(GenericBackendTests): @pytest.fixture diff --git a/src/sage/numerical/backends/interactivelp_backend_test.py b/src/sage/numerical/backends/interactivelp_backend_test.py index 5523c40ce1f..d0e4b091563 100644 --- a/src/sage/numerical/backends/interactivelp_backend_test.py +++ b/src/sage/numerical/backends/interactivelp_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + class TestInteractiveLPBackend(GenericBackendTests): @pytest.fixture diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index d2d7bd98299..a7acf57341f 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -20,6 +20,7 @@ from sage.numerical.backends.generic_backend import GenericBackend + def _format_function_call(fn_name, *v, **k): """ Return a Python function call as a string. @@ -33,6 +34,7 @@ def _format_function_call(fn_name, *v, **k): args = [ repr(a) for a in v ] + [ "%s=%r" % (arg,val) for arg, val in k.items() ] return "{}({})".format(fn_name, ", ".join(args)) + def _make_wrapper(backend, attr): """ Return a wrapper for the backend method named by ``attr`` that does the logging. @@ -90,6 +92,7 @@ def m(self, *args, **kwdargs): update_wrapper(m, getattr(backend, attr)) return m + class LoggingBackend(GenericBackend): """ See :class:`LoggingBackendFactory` for documentation. @@ -232,6 +235,7 @@ def _test_{name}(cls, tester=None, **options): from sage.rings.rational_field import QQ + def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=QQ): """ diff --git a/src/sage/numerical/backends/scip_backend_test.py b/src/sage/numerical/backends/scip_backend_test.py index 136d3ce914b..f10f6edee46 100644 --- a/src/sage/numerical/backends/scip_backend_test.py +++ b/src/sage/numerical/backends/scip_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + @pytest.importorskip("pyscipopt") class TestSCIPBackend(GenericBackendTests): diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index a89da826c77..24dd0ded920 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -213,6 +213,7 @@ # will have to be left. generate_real_LaTeX = False + def _assemble_arrayl(lines, stretch=None): r""" Return ``lines`` assembled in a left-justified array. @@ -442,6 +443,7 @@ def variable(R, v): current_style = 'UAlberta' + def default_variable_name(variable): r""" Return default variable name for the current :func:`style`. @@ -465,6 +467,7 @@ def default_variable_name(variable): """ return available_styles[current_style][variable] + def style(new_style=None): r""" Set or get the current style of problems and dictionaries. @@ -3704,6 +3707,7 @@ def update(self): 5000 """ + class LPDictionary(LPAbstractDictionary): r""" Construct a dictionary for an LP problem. @@ -4265,6 +4269,7 @@ def update(self): random_dictionary = LPDictionary.random_element + class LPRevisedDictionary(LPAbstractDictionary): r""" Construct a revised dictionary for an LP problem. @@ -4783,9 +4788,9 @@ def add_row(self, nonbasic_coefficients, constant, basic_variable=None): The implementation of this method for revised dictionaries adds a new inequality constraint to the problem, in which the given - `basic_variable` becomes the slack variable. The resulting dictionary - (with `basic_variable` added to the basis) will have the given - `nonbasic_coefficients` and `constant` as a new row. + ``basic_variable`` becomes the slack variable. The resulting dictionary + (with ``basic_variable`` added to the basis) will have the given + ``nonbasic_coefficients`` and ``constant`` as a new row. INPUT: diff --git a/src/sage/numerical/knapsack.py b/src/sage/numerical/knapsack.py index 9f9d06fcd3b..8776799d338 100644 --- a/src/sage/numerical/knapsack.py +++ b/src/sage/numerical/knapsack.py @@ -98,6 +98,7 @@ from sage.rings.integer import Integer from sage.structure.sage_object import SageObject + class Superincreasing(SageObject): r""" A class for super-increasing sequences. @@ -545,6 +546,7 @@ def subset_sum(self, N): else: return [] + def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index b86b52b05f6..ca19ef887cb 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -285,7 +285,7 @@ def _multiple_of_constant(n, pos, const): Function for internal use in formatting ticks on axes with nice-looking multiples of various symbolic constants, such as `\pi` or `e`. Should only be used via keyword argument - `tick_formatter` in :meth:`plot.show`. See documentation + ``tick_formatter`` in :meth:`plot.show`. See documentation for the matplotlib.ticker module for more details. EXAMPLES: diff --git a/src/sage/plot/primitive.py b/src/sage/plot/primitive.py index ef69f7f4344..3c4032085cc 100644 --- a/src/sage/plot/primitive.py +++ b/src/sage/plot/primitive.py @@ -146,7 +146,7 @@ def set_zorder(self, zorder): def set_options(self, new_options): """ - Change the options to `new_options`. + Change the options to ``new_options``. EXAMPLES:: diff --git a/src/sage/probability/probability_distribution.pyx b/src/sage/probability/probability_distribution.pyx index fab94479291..a1d11fb2bfb 100644 --- a/src/sage/probability/probability_distribution.pyx +++ b/src/sage/probability/probability_distribution.pyx @@ -40,7 +40,8 @@ REFERENCES: # **************************************************************************** from cysignals.memory cimport sig_malloc, sig_free -from sage.libs.gsl.all cimport * +from sage.libs.gsl.rng cimport * +from sage.libs.gsl.random cimport * import sage.misc.prandom as random import sage.rings.real_double from sage.modules.free_module_element import vector diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index cb5c0426c5a..ce66f36bdb3 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -26,6 +26,7 @@ ################################################################################ ################################################################################ + def is_ProbabilitySpace(S): from sage.misc.superseded import deprecation deprecation(38184, @@ -33,6 +34,7 @@ def is_ProbabilitySpace(S): "use 'isinstance(..., ProbabilitySpace_generic)' instead.") return isinstance(S, ProbabilitySpace_generic) + def is_DiscreteProbabilitySpace(S): from sage.misc.superseded import deprecation deprecation(38184, @@ -40,6 +42,7 @@ def is_DiscreteProbabilitySpace(S): "use 'isinstance(..., DiscreteProbabilitySpace)' instead.") return isinstance(S, DiscreteProbabilitySpace) + def is_RandomVariable(X): from sage.misc.superseded import deprecation deprecation(38184, @@ -47,6 +50,7 @@ def is_RandomVariable(X): "use 'isinstance(..., RandomVariable_generic)' instead.") return isinstance(X, RandomVariable_generic) + def is_DiscreteRandomVariable(X): from sage.misc.superseded import deprecation deprecation(38184, @@ -299,6 +303,7 @@ def translation_correlation(self, other, map): ################################################################################ ################################################################################ + class ProbabilitySpace_generic(RandomVariable_generic): r""" A probability space. diff --git a/src/sage/quadratic_forms/all.py b/src/sage/quadratic_forms/all.py index 5982c6b8a5a..c4832168378 100644 --- a/src/sage/quadratic_forms/all.py +++ b/src/sage/quadratic_forms/all.py @@ -6,13 +6,17 @@ from sage.quadratic_forms.quadratic_form import QuadraticForm, DiagonalQuadraticForm, quadratic_form_from_invariants -from sage.quadratic_forms.random_quadraticform import (random_quadraticform, random_quadraticform_with_conditions, - random_ternaryqf, random_ternaryqf_with_conditions) +from sage.quadratic_forms.random_quadraticform import (random_quadraticform, + random_quadraticform_with_conditions, + random_ternaryqf, + random_ternaryqf_with_conditions) from sage.quadratic_forms.extras import least_quadratic_nonresidue, extend_to_primitive, is_triangular_number -from sage.quadratic_forms.special_values import (gamma__exact, zeta__exact, QuadraticBernoulliNumber, - quadratic_L_function__exact, quadratic_L_function__numerical) +from sage.quadratic_forms.special_values import (gamma__exact, zeta__exact, + QuadraticBernoulliNumber, + quadratic_L_function__exact, + quadratic_L_function__numerical) from sage.quadratic_forms.genera.genus import Genus diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 1a75f415b64..202da0652ff 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -1630,7 +1630,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): ALGORITHM: :pari:`qfbsolve` or :pari:`qfbcornacchia` - TODO:: Replace `_flag` with human-readable parameters c.f. :issue:`37119` + TODO:: Replace ``_flag`` with human-readable parameters c.f. :issue:`37119` EXAMPLES:: @@ -1736,7 +1736,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): sage: Q(*xy) 0 - Test for different `_flag` values:: + Test for different ``_flag`` values:: sage: # needs sage.libs.pari sage: Q = BinaryQF([1, 0, 5]) diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index dc9b30aa763..a88cf660412 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -291,7 +291,7 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # Take cases on the existence of additional nonzero congruence conditions (mod 2) if NZvec is None: total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) \ - * count_all_local_good_types_normal_form(Q_Not8,2, 3, m, list(Z_Not8), None) + * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) else: ZNZ = Z + Set(NZvec) ZNZ_Not8 = Not8.intersection(ZNZ) diff --git a/src/sage/quivers/ar_quiver.py b/src/sage/quivers/ar_quiver.py index f13c67dfa32..f0b2193eece 100644 --- a/src/sage/quivers/ar_quiver.py +++ b/src/sage/quivers/ar_quiver.py @@ -9,8 +9,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 68b2fbb9f8b..7016e12837b 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -15,15 +15,14 @@ sage: 'sage: [False, True]' in output # needs pexpect True """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sys diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 3a269592917..83d22127cd3 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -772,7 +772,8 @@ def __init__(self, app): contact_email = 'sage-support@googlegroups.com' bug_tracker = 'https://github.com/sagemath/sage/issues' CrashHandler.__init__(self, - app, contact_name, contact_email, bug_tracker, show_crash_traceback=True) + app, contact_name, contact_email, + bug_tracker, show_crash_traceback=True) self.crash_report_fname = 'Sage_crash_report.txt' diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index b6fc42bbb37..d7b1821d7d0 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -302,7 +302,7 @@ def display(self, args): max_width = 0 if max_width <= 0: raise ValueError( - "max width must be a positive integer") + "max width must be a positive integer") import sage.typeset.character_art as character_art character_art.MAX_WIDTH = max_width dm.preferences.text = arg0 @@ -342,7 +342,18 @@ def cython(self, line, cell): INPUT: - - ``line`` -- ignored + - ``line`` -- parsed as keyword arguments. The allowed arguments are: + + - ``--verbose N`` / ``-v N`` + - ``--compile-message`` + - ``--use-cache`` + - ``--create-local-c-file`` + - ``--annotate`` + - ``--sage-namespace`` + - ``--create-local-so-file`` + - ``--no-compile-message``, ``--no-use-cache``, etc. + + See :func:`~sage.misc.cython.cython` for details. - ``cell`` -- string; the Cython source code to process @@ -350,19 +361,76 @@ def cython(self, line, cell): EXAMPLES:: + sage: # needs sage.misc.cython sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell( # needs sage.misc.cython + sage: shell.run_cell( ....: ''' - ....: %%cython + ....: %%cython -v1 --annotate --no-sage-namespace ....: def f(): ....: print('test') ....: ''') - sage: f() # needs sage.misc.cython + Compiling ....pyx because it changed. + [1/1] Cythonizing ....pyx + sage: f() test + + TESTS: + + Test unrecognized arguments:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --some-unrecognized-argument + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --some-unrecognized-argument + + Test ``--help`` is disabled:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --help + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --help + + Test invalid quotes (see :mod:`sage.repl.interpreter` for explanation of the dummy line):: + + sage: # needs sage.misc.cython + sage: print("dummy line"); shell.run_cell(''' + ....: %%cython --a=' + ....: print(1) + ....: ''') + dummy line + ... + ValueError...Traceback (most recent call last) + ... + ValueError: No closing quotation """ from sage.misc.cython import cython_compile - return cython_compile(cell) + import shlex + import argparse + + class ExitCatchingArgumentParser(argparse.ArgumentParser): + def error(self, message): + # exit_on_error=False does not work completely in some Python versions + # see https://stackoverflow.com/q/67890157 + # we raise UsageError to make the interface similar to what happens when e.g. + # IPython's ``%run`` gets unrecognized arguments + from IPython.core.error import UsageError + raise UsageError(message) + + parser = ExitCatchingArgumentParser(prog="%%cython", add_help=False) + parser.add_argument("--verbose", "-v", type=int) + parser.add_argument("--compile-message", action=argparse.BooleanOptionalAction) + parser.add_argument("--use-cache", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-c-file", action=argparse.BooleanOptionalAction) + parser.add_argument("--annotate", action=argparse.BooleanOptionalAction) + parser.add_argument("--sage-namespace", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-so-file", action=argparse.BooleanOptionalAction) + args = parser.parse_args(shlex.split(line)) + return cython_compile(cell, **{k: v for k, v in args.__dict__.items() if v is not None}) @cell_magic def fortran(self, line, cell): @@ -435,7 +503,7 @@ def __init__(self, shell=None): self.init_line_transforms() try: - import sage.all # until sage's import hell is fixed + import sage.all # until sage's import hell is fixed except ImportError: import sage.all__sagemath_repl diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index 5113b5845b4..0f347281e82 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -13,14 +13,14 @@ The Sage display manager using the doctest backend """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sys @@ -295,7 +295,7 @@ def validate(self, rich_output): assert data.startswith(b'\0\0\0') # See http://www.ftyps.com/ ftyps = [data[i:i+4] for i in range(8, data[3], 4)] - del ftyps[1] # version number, not an ftyp + del ftyps[1] # version number, not an ftyp expected = [b'avc1', b'iso2', b'mp41', b'mp42'] assert any(i in ftyps for i in expected) elif isinstance(rich_output, OutputVideoFlash): diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index b736aca9538..5b013574507 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -525,7 +525,7 @@ def displayhook(self, plain_text, rich_output): elif isinstance(rich_output, OutputLatex): return ({'text/latex': rich_output.latex.get_str(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputHtml): data = {'text/html': rich_output.html.get_str(), 'text/plain': plain_text.text.get_str()} @@ -535,29 +535,29 @@ def displayhook(self, plain_text, rich_output): elif isinstance(rich_output, OutputImagePng): return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageGif): return ({'text/html': rich_output.html_fragment(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageJpg): return ({'image/jpeg': rich_output.jpg.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageSvg): return ({'image/svg+xml': rich_output.svg.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImagePdf): return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputSceneJmol): from sage.repl.display.jsmol_iframe import JSMolHtml jsmol = JSMolHtml(rich_output, height=500) return ({'text/html': jsmol.iframe(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputSceneThreejs): escaped_html = html.escape(rich_output.html.get_str()) iframe = IFRAME_TEMPLATE.format( @@ -567,7 +567,7 @@ def displayhook(self, plain_text, rich_output): ) return ({'text/html': iframe, 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) else: raise TypeError('rich_output type not supported') diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index 70257f7f4ed..05cff326eb9 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -32,14 +32,14 @@ class is independent of user preferences and of the display file system. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject diff --git a/src/sage/repl/rich_output/output_catalog.py b/src/sage/repl/rich_output/output_catalog.py index 542182eee69..584a077781c 100644 --- a/src/sage/repl/rich_output/output_catalog.py +++ b/src/sage/repl/rich_output/output_catalog.py @@ -5,14 +5,14 @@ If you define another output type then you must add it to the imports here. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .output_basic import ( diff --git a/src/sage/repl/rich_output/test_backend.py b/src/sage/repl/rich_output/test_backend.py index 133fb35ae5d..059eda5de3e 100644 --- a/src/sage/repl/rich_output/test_backend.py +++ b/src/sage/repl/rich_output/test_backend.py @@ -30,14 +30,14 @@ TestOutputPlainText container """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 48caffa1b6a..f7b8b6bb893 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -4317,6 +4317,16 @@ def coefficients_of_generating_function(self, function, singularities, precision ....: 'n', precision=5)) True + Positive and negative singularities:: + + sage: def permutations_odd_cycles(z): + ....: return sqrt((1+z) / (1-z)) + sage: ex = B.coefficients_of_generating_function( + ....: permutations_odd_cycles, (1, -1,), precision=2, + ....: ); ex + sqrt(2)/sqrt(pi)*n^(-1/2) - 1/2*sqrt(1/2)/sqrt(pi)*n^(-3/2)*(-1)^n + + O(n^(-5/2)) + .. WARNING:: Once singular expansions around points other than infinity diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 9eaf85376ca..69ee6a36f6c 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -505,7 +505,7 @@ def dimension(self): from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base R = self.denominator_ring - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base): + if isinstance(R, (PolynomialRing_general, MPolynomialRing_base)): return R.ngens() raise NotImplementedError('only polynomial rings are supported as base') @@ -3167,7 +3167,7 @@ def _element_constructor_(self, *args, **kwargs): from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base): + if isinstance(R, (PolynomialRing_general, MPolynomialRing_base)): if not R(q).is_unit(): # Factor denominator try: @@ -3235,7 +3235,7 @@ def _coerce_map_from_(self, P): B = P.base() from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - if isinstance(B, PolynomialRing_general) or isinstance(B, MPolynomialRing_base): + if isinstance(B, (PolynomialRing_general, MPolynomialRing_base)): if self.base().has_coerce_map_from(B): return True @@ -4032,7 +4032,7 @@ def diff_op_simple(A, B, AB_derivs, x, v, a, N): various natural numbers `e, k, l` that depend on `v` and `N`. Here `DD` is a specific linear differential operator that depends - on `a` and `v` , `A` and `B` are symbolic functions, and `AB_derivs` + on `a` and `v` , `A` and `B` are symbolic functions, and ``AB_derivs`` contains all the derivatives of `A` and `B` evaluated at `p` that are necessary for the computation. diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index bec9978401e..d24e61d2823 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -48,7 +48,6 @@ from sage.rings.integer cimport Integer from sage.rings.complex_double cimport ComplexDoubleElement from sage.rings.real_mpfr cimport RealNumber -from sage.libs.gsl.complex cimport * from sage.libs.mpmath.utils cimport mpfr_to_mpfval from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 803eed59146..106a94c5aca 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -72,6 +72,33 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: imaginary component is 0. - in all other cases: raise an exception. + + TESTS:: + + sage: RIF('0xabc') + Traceback (most recent call last): + ... + TypeError: unable to convert '0xabc' to real interval + sage: RIF("0x123.e1", base=0) # rel tol 1e-12 + 291.87890625000000? + sage: RIF("0x123.@1", base=0) # rel tol 1e-12 + 4656 + sage: RIF("1Xx", base=36) # rel tol 1e-12 + 2517 + sage: RIF("-1Xx@-10", base=62) # rel tol 1e-12 + -7.088054920481391?e-15 + sage: RIF("1", base=1) + Traceback (most recent call last): + ... + ValueError: base (=1) must be 0 or between 2 and 62 + sage: RIF("1", base=-1) + Traceback (most recent call last): + ... + ValueError: base (=-1) must be 0 or between 2 and 62 + sage: RIF("1", base=63) + Traceback (most recent call last): + ... + ValueError: base (=63) must be 0 or between 2 and 62 """ cdef RealIntervalFieldElement ri cdef ComplexIntervalFieldElement zi @@ -79,6 +106,8 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: cdef ComplexDoubleElement zd cdef bytes s + if base != 0 and (base < 2 or base > 62): + raise ValueError(f"base (={base}) must be 0 or between 2 and 62") if im is not NULL and isinstance(x, tuple): # For complex numbers, interpret tuples as real/imag parts if len(x) != 2: diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index b824e16e0d1..a1f80611473 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -996,7 +996,7 @@ def list(self): parent = self.parent() return [self(x) for x in parent.dual_basis()] - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): r""" Return dictionary of nonzero coordinates (on the canonical basis) of this derivation. diff --git a/src/sage/rings/finite_rings/element_base.pxd b/src/sage/rings/finite_rings/element_base.pxd index c214e4745a9..2c509e2d5e3 100644 --- a/src/sage/rings/finite_rings/element_base.pxd +++ b/src/sage/rings/finite_rings/element_base.pxd @@ -9,4 +9,3 @@ cdef class FinitePolyExtElement(FiniteRingElement): cdef class Cache_base(SageObject): cpdef FinitePolyExtElement fetch_int(self, number) - diff --git a/src/sage/rings/finite_rings/stdint.pxd b/src/sage/rings/finite_rings/stdint.pxd index b2b96a90c39..4e4cb6522d3 100644 --- a/src/sage/rings/finite_rings/stdint.pxd +++ b/src/sage/rings/finite_rings/stdint.pxd @@ -16,4 +16,3 @@ from libc.stdint cimport int_fast32_t, int_fast64_t cdef extern from "integer_mod_limits.h": int_fast32_t INTEGER_MOD_INT32_LIMIT int_fast64_t INTEGER_MOD_INT64_LIMIT - diff --git a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py index 2269085539d..9662572d5c0 100644 --- a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py @@ -127,8 +127,8 @@ def __init__(self, gen, category): """ Initialize ``self``. - Validity of the input is checked in `__classcall_private__`. The - `__init__` just saves attributes. + Validity of the input is checked in ``__classcall_private__``. The + ``__init__`` just saves attributes. INPUT: @@ -469,7 +469,7 @@ def _frobenius_charpoly_CSA(self): Compute the characteristic polynomial of the Frobenius from the reduced characteristic polynomial of the Ore polynomial - `phi_T`. This algorithm is particularly interesting when the + `\phi_T`. This algorithm is particularly interesting when the rank of the Drinfeld module is large compared to the degree of the extension `K/\mathbb F_q`. See [CL2023]_. """ diff --git a/src/sage/rings/function_field/jacobian_base.py b/src/sage/rings/function_field/jacobian_base.py index 405d90bfc3f..177ea6058ab 100644 --- a/src/sage/rings/function_field/jacobian_base.py +++ b/src/sage/rings/function_field/jacobian_base.py @@ -52,6 +52,7 @@ We can get the corresponding point in the Jacobian in a different model. :: + sage: # long time sage: p1km = J_km(p1) sage: p1km.order() 5 @@ -111,6 +112,7 @@ def order(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(29), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -640,6 +642,7 @@ def __call__(self, x): TESTS:: + sage: # long time sage: K. = FunctionField(GF(2)); _. = K[] sage: F. = K.extension(Y^2 + Y + x + 1/x) sage: J_hess = F.jacobian(model='hess') @@ -651,6 +654,26 @@ def __call__(self, x): True sage: J_hess(q) == p True + + If ``x`` is an effective divisor, it is checked that the degree + is equal to the degree of the base divisor. See :issue:`38623`. + + sage: K. = FunctionField(GF(7)) + sage: _. = K[] + sage: F. = K.extension(t^2 - x^6 - 3) + sage: O = F.maximal_order() + sage: D1 = (O.ideal(x + 1, y + 2) * O.ideal(x + 2, y + 2)).divisor() + sage: I = O.ideal(x + 3, y+5) * O.ideal(x + 4, y + 5) * O.ideal(x + 5, y + 5) + sage: D2 = I.divisor() + sage: J = F.jacobian(model='hess') + sage: J(D1) + [Place (x + 1, y + 2) + Place (x + 2, y + 2)] + sage: J(D2) + Traceback (most recent call last): + ... + ValueError: effective divisor is not of degree 2 + sage: J.base_divisor().degree() + 2 """ F = self._function_field if isinstance(x, JacobianPoint_base): @@ -666,9 +689,8 @@ def __call__(self, x): if x == 0: return self.group().zero() if x in F.divisor_group(): - G = self.group() - return G.point(x) - raise ValueError(f"Cannot create a point of the Jacobian from {x}") + return self.group()(x) + raise ValueError(f"cannot create a point of the Jacobian from {x}") def curve(self): """ diff --git a/src/sage/rings/function_field/jacobian_hess.py b/src/sage/rings/function_field/jacobian_hess.py index a85bc10e256..882b2eb917d 100644 --- a/src/sage/rings/function_field/jacobian_hess.py +++ b/src/sage/rings/function_field/jacobian_hess.py @@ -606,7 +606,7 @@ def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. - If ``x`` is an effective divisor, then it is assumed to of + If ``x`` is an effective divisor, then it must be of degree `g`, the genus of the function field. EXAMPLES:: @@ -634,9 +634,11 @@ def _element_constructor_(self, x): if x.degree() == 0: return self.point(x) if x.is_effective(): + if x.degree() != self._genus: + raise ValueError(f"effective divisor is not of degree {self._genus}") return self.element_class(self, *self._get_dS_ds(x)) - raise ValueError(f"Cannot construct a point from {x}") + raise ValueError(f"cannot construct a point from {x}") def _get_dS_ds(self, divisor): """ @@ -805,6 +807,8 @@ def point(self, divisor): sage: G.point(p - b) [Place (y + 2, z + 1)] """ + if divisor.degree() != 0: + raise ValueError('divisor not of degree zero') c = divisor + self._base_div f = c.basis_function_space()[0] d = f.divisor() + c diff --git a/src/sage/rings/function_field/jacobian_khuri_makdisi.py b/src/sage/rings/function_field/jacobian_khuri_makdisi.py index 2c9a2e5da97..4a86a2d4a08 100644 --- a/src/sage/rings/function_field/jacobian_khuri_makdisi.py +++ b/src/sage/rings/function_field/jacobian_khuri_makdisi.py @@ -68,6 +68,7 @@ EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -154,6 +155,7 @@ class JacobianPoint(JacobianPoint_base): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -176,6 +178,7 @@ def __init__(self, parent, w): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -196,6 +199,7 @@ def _repr_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -218,6 +222,7 @@ def __hash__(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -242,6 +247,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -275,6 +281,7 @@ def _add_(self, other): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -306,6 +313,7 @@ def _neg_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -340,6 +348,7 @@ def _rmul_(self, n): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -363,6 +372,7 @@ def multiple(self, n): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -394,6 +404,7 @@ def addflip(self, other): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -426,6 +437,7 @@ def defining_matrix(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -450,6 +462,7 @@ def divisor(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -493,6 +506,7 @@ class JacobianGroupEmbedding(Map): EXAMPLES:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -514,6 +528,7 @@ def __init__(self, base_group, extension_group): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -538,6 +553,7 @@ def _repr_type(self): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -561,6 +577,7 @@ def _call_(self, x): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -592,6 +609,7 @@ class JacobianGroup(UniqueRepresentation, JacobianGroup_base): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -609,6 +627,7 @@ def __init__(self, parent, function_field, base_div): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -619,6 +638,7 @@ def __init__(self, parent, function_field, base_div): D0 = base_div + self._base_div_degree = base_div.degree() self._V_cache = 10*[None] V_cache = self._V_cache @@ -672,6 +692,7 @@ def _repr_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -693,6 +714,7 @@ def _wd_from_divisor(self, x): TESTS: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -719,6 +741,7 @@ def _element_constructor_(self, x): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -760,10 +783,12 @@ def _element_constructor_(self, x): if x.degree() == 0: return self.point(x) if x.is_effective(): + if x.degree() != self._base_div_degree: + raise ValueError(f"effective divisor is not of degree {self._base_div_degree}") wd = self._wd_from_divisor(x) return self.element_class(self, wd) - raise ValueError(f"Cannot construct a point from {x}") + raise ValueError(f"cannot construct a point from {x}") def point(self, divisor): """ @@ -775,6 +800,7 @@ def point(self, divisor): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -808,6 +834,7 @@ def zero(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -839,6 +866,7 @@ class JacobianGroup_finite_field(JacobianGroup, JacobianGroup_finite_field_base) EXAMPLES:: + sage: # long time sage: k = GF(7) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) @@ -862,6 +890,7 @@ def __init__(self, parent, function_field, base_div): TESTS:: + sage: # long time sage: k = GF(7) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) @@ -952,6 +981,7 @@ def _frobenius_on(self, pt): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -986,6 +1016,7 @@ def __init__(self, function_field, base_div, model, **kwds): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: J = C.jacobian(model='km_large') @@ -993,6 +1024,7 @@ def __init__(self, function_field, base_div, model, **kwds): :: + sage: # long time sage: J = C.jacobian(model='km_unknown') Traceback (most recent call last): ... diff --git a/src/sage/rings/function_field/khuri_makdisi.pyx b/src/sage/rings/function_field/khuri_makdisi.pyx index 5933abcd1ce..aa64322b0ed 100644 --- a/src/sage/rings/function_field/khuri_makdisi.pyx +++ b/src/sage/rings/function_field/khuri_makdisi.pyx @@ -86,6 +86,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -180,6 +181,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -205,6 +207,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -230,6 +233,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -255,6 +259,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -324,6 +329,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -357,6 +363,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -414,6 +421,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: J = C.jacobian(model='km_large') @@ -476,6 +484,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -507,6 +516,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -537,6 +547,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -588,6 +599,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -623,6 +635,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -642,6 +655,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): We check the computation in other model:: + sage: # long time sage: J = C.jacobian(model='km_large', base_div=h) sage: G = J.group() sage: p1 = G.point(pl1 - b) @@ -671,6 +685,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -702,6 +717,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -759,6 +775,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -793,6 +810,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -812,6 +830,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): We check the computation in other model:: + sage: # long time sage: h = C.function(y/x).divisor_of_poles() sage: Jl = C.jacobian(model='km_large', base_div=h) sage: G = J.group() @@ -840,6 +859,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -874,6 +894,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 346a67481e1..d6555ac0eab 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -1142,22 +1142,6 @@ cdef class IntegerRing_class(CommutativeRing): """ return 1 - def is_integrally_closed(self): - """ - Return that the integer ring is, in fact, integrally closed. - - .. NOTE:: - - This should rather be inherited from the category - of ``DedekindDomains``. - - EXAMPLES:: - - sage: ZZ.is_integrally_closed() - True - """ - return True - def completion(self, p, prec, extras={}): r""" Return the metric completion of the integers at the prime `p`. diff --git a/src/sage/rings/laurent_series_ring_element.pxd b/src/sage/rings/laurent_series_ring_element.pxd index 8df5a92c9e7..3fc8e5dfffd 100644 --- a/src/sage/rings/laurent_series_ring_element.pxd +++ b/src/sage/rings/laurent_series_ring_element.pxd @@ -7,4 +7,3 @@ cdef class LaurentSeries(AlgebraElement): cdef _normalize(self) cpdef _add_(self, other) cpdef _mul_(self, other) - diff --git a/src/sage/rings/meson.build b/src/sage/rings/meson.build index 14ed48a7c7a..171592eccbd 100644 --- a/src/sage/rings/meson.build +++ b/src/sage/rings/meson.build @@ -72,6 +72,7 @@ py.install_sources( 'ring_extension_element.pxd', 'ring_extension_homset.py', 'ring_extension_morphism.pxd', + 'species.py', 'sum_of_squares.pxd', 'tate_algebra.py', 'tate_algebra_element.pxd', diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 9c27ba678bb..046f8338e05 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -1099,7 +1099,7 @@ def __mod__(self, other): return self.change_ring(Zmod(other)) raise NotImplementedError("Mod on multivariate power series ring elements not defined except modulo an integer.") - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return underlying dictionary with keys the exponents and values the coefficients of this power series. diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 7128d40032e..2559771ae62 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1762,8 +1762,8 @@ def _element_constructor_(self, x, check=True): return self._convert_from_str(s.replace('!', '')) elif isinstance(x, str): return self._convert_from_str(x) - elif (isinstance(x, (tuple, list)) or - isinstance(x, sage.modules.free_module_element.FreeModuleElement)): + elif isinstance(x, (tuple, list, + sage.modules.free_module_element.FreeModuleElement)): if len(x) != self.relative_degree(): raise ValueError("Length must be equal to the degree of this number field") base = self.base_ring() diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pxd b/src/sage/rings/number_field/number_field_element_quadratic.pxd index 6dce9c04d90..7bb9e57a3a2 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pxd +++ b/src/sage/rings/number_field/number_field_element_quadratic.pxd @@ -31,4 +31,3 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): pass cpdef bint is_sqrt_disc(Rational ad, Rational bd) noexcept - diff --git a/src/sage/rings/number_field/number_field_morphisms.pyx b/src/sage/rings/number_field/number_field_morphisms.pyx index e71bad5db7c..330e0a8ab69 100644 --- a/src/sage/rings/number_field/number_field_morphisms.pyx +++ b/src/sage/rings/number_field/number_field_morphisms.pyx @@ -20,16 +20,14 @@ fields (generally `\RR` or `\CC`). # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.rings.complex_double - from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map from sage.categories.pushout import pushout +from sage.rings.complex_double import CDF from sage.rings.real_lazy import RLF, CLF, LazyField, LazyAlgebraic - cdef class NumberFieldEmbedding(Morphism): cdef _gen_image @@ -254,7 +252,7 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): candidate_ambient_fields.append(ambient_field.algebraic_closure()) except NotImplementedError: pass - candidate_ambient_fields.append(sage.rings.complex_double.CDF) + candidate_ambient_fields.append(CDF) else: candidate_ambient_fields = [ambient_field] diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 9dee6a8a481..fd5662048df 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -631,9 +631,11 @@ def is_noetherian(self): """ return True - def is_integrally_closed(self): + def is_integrally_closed(self) -> bool: r""" - Return ``True`` if this ring is integrally closed, i.e., is equal + Return whether this ring is integrally closed. + + This is true if and only if it is equal to the maximal order. EXAMPLES:: diff --git a/src/sage/rings/number_field/totallyreal_data.pxd b/src/sage/rings/number_field/totallyreal_data.pxd index 61973829ddb..006189325f9 100644 --- a/src/sage/rings/number_field/totallyreal_data.pxd +++ b/src/sage/rings/number_field/totallyreal_data.pxd @@ -23,4 +23,3 @@ cdef class tr_data: cdef int *df cdef void incr(self, int *f_out, int verbose, int haltk, int phc) noexcept - diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index cee585d48a1..44093d2cf67 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -2570,7 +2570,7 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, True """ if check: - if isinstance(q, Factorization) or isinstance(q, (list, tuple)): + if isinstance(q, (Factorization, list, tuple)): if not isinstance(q, Factorization) and len(q) == 2: F = [(Integer(q[0]), Integer(q[1]))] else: @@ -2592,7 +2592,8 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, if isinstance(names, (list, tuple)): names = names[0] from sage.structure.element import Expression - if not (modulus is None or isinstance(modulus, Polynomial) or isinstance(modulus, Expression)): + if not (modulus is None or isinstance(modulus, (Polynomial, + Expression))): raise TypeError("modulus must be a polynomial") if names is not None and not isinstance(names, str): names = str(names) diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 073a3d98f5f..81b164a03f9 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1349,7 +1349,7 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: Zp(5)(0).gamma() 1 + O(5^20) - Check the cached version of `dwork_expansion` from :issue:`24433`:: + Check the cached version of ``dwork_expansion`` from :issue:`24433`:: sage: p = next_prime(200) sage: F = Qp(p) diff --git a/src/sage/rings/polynomial/all.py b/src/sage/rings/polynomial/all.py index 853f422bdc7..f2295443420 100644 --- a/src/sage/rings/polynomial/all.py +++ b/src/sage/rings/polynomial/all.py @@ -54,3 +54,5 @@ # Integer-valued Univariate Polynomial Ring lazy_import('sage.rings.polynomial.integer_valued_polynomials', 'IntegerValuedPolynomialRing') +lazy_import('sage.rings.polynomial.q_integer_valued_polynomials', + 'QuantumValuedPolynomialRing') diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index 6354bbcd382..32d07423e91 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -167,7 +167,7 @@ def __init__(self, domain): variables = [] intermediate_rings = [] - while isinstance(ring, PolynomialRing_general) or isinstance(ring, MPolynomialRing_base): + while isinstance(ring, (PolynomialRing_general, MPolynomialRing_base)): intermediate_rings.append(ring) v = ring.variable_names() variables.extend(reversed(v)) @@ -538,7 +538,9 @@ def __init__(self, domain, D): # Construct unflattened codomain R new_vars = [] R = domain - while isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base) or isinstance(R, FractionField_generic): + while isinstance(R, (PolynomialRing_general, + MPolynomialRing_base, + FractionField_generic)): if isinstance(R, FractionField_generic): # We've hit base_ring, so set _sub_specialization and exit the loop field_over = R.base() diff --git a/src/sage/rings/polynomial/meson.build b/src/sage/rings/polynomial/meson.build index 94a0a0c8b9a..cbd48976335 100644 --- a/src/sage/rings/polynomial/meson.build +++ b/src/sage/rings/polynomial/meson.build @@ -52,6 +52,7 @@ py.install_sources( 'polynomial_singular_interface.py', 'polynomial_zmod_flint.pxd', 'polynomial_zz_pex.pxd', + 'q_integer_valued_polynomials.py', 'real_roots.pxd', 'skew_polynomial_element.pxd', 'skew_polynomial_finite_field.pxd', diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 1b54a1fd0aa..0e25b72dbb9 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -208,6 +208,56 @@ cdef class MPolynomial(CommutativePolynomial): return R(self.polynomial(self._parent(var))) return R([self]) + def leading_support(self, *args, **kwds): + r""" + Return the maximal element of the support of ``self``, + according to the term order. + + If the term ordering of the basis elements is not what is + desired, a comparison key, ``key(x)``, can be provided. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (0, 4, 0) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (1, 2, 0) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (0, 1, 3) + """ + if 'key' in kwds: + return max(self.support(), *args, **kwds) + kwds['key'] = self._parent.term_order().sortkey + return max(self.support(), *args, **kwds) + + def trailing_support(self, *args, **kwds): + r""" + Return the minimal element of the support of ``self``, + according to the term order. + + If the term ordering of the basis elements is not what is + desired, a comparison key, ``key(x)``, can be provided. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (1, 1, 1) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (0, 1, 3) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (1, 2, 0) + """ + if 'key' in kwds: + return min(self.support(), *args, **kwds) + kwds['key'] = self._parent.term_order().sortkey + return min(self.support(), *args, **kwds) + def coefficients(self): r""" Return the nonzero coefficients of this polynomial in a list. @@ -429,7 +479,7 @@ cdef class MPolynomial(CommutativePolynomial): for e, val in self.monomial_coefficients().items() if not e[ind]} v = [B(w)] # coefficients that don't involve var z = var - for i in range(1,d+1): + for i in range(1, d+1): c = self.coefficient(z).monomial_coefficients() w = {remove_from_tuple(e, ind): val for e, val in c.items()} v.append(B(w)) @@ -487,7 +537,7 @@ cdef class MPolynomial(CommutativePolynomial): elif my_vars[-1] not in vars: x = base_ring(self) if base_ring is not None else self const_ix = ETuple((0,)*len(vars)) - return { const_ix: x } + return {const_ix: x} elif not set(my_vars).issubset(set(vars)): # we need to split it up p = self.polynomial(self._parent.gen(len(my_vars)-1)) @@ -769,7 +819,7 @@ cdef class MPolynomial(CommutativePolynomial): subclasses. """ M = self.monomials() - if M==[]: + if M == []: return True d = M.pop().degree() for m in M: @@ -1099,14 +1149,14 @@ cdef class MPolynomial(CommutativePolynomial): g = R.gen_names() v = [] for m, c in zip(self.monomials(), self.coefficients()): - v.append('(%s)*%s'%( c._magma_init_(magma), - m._repr_with_changed_varnames(g))) + v.append('(%s)*%s' % (c._magma_init_(magma), + m._repr_with_changed_varnames(g))) if len(v) == 0: s = '0' else: s = '+'.join(v) - return '%s!(%s)'%(R.name(), s) + return '%s!(%s)' % (R.name(), s) def _giac_init_(self): r""" @@ -1183,7 +1233,7 @@ cdef class MPolynomial(CommutativePolynomial): """ from sage.geometry.polyhedron.constructor import Polyhedron e = self.exponents() - P = Polyhedron(vertices = e, base_ring=ZZ) + P = Polyhedron(vertices=e, base_ring=ZZ) return P def __iter__(self): @@ -1399,7 +1449,7 @@ cdef class MPolynomial(CommutativePolynomial): raise TypeError("k must be a finite field") p = k.characteristic() e = k.degree() - v = [self] + [self.map_coefficients(k.hom([k.gen()**(p**i)])) for i in range(1,e)] + v = [self] + [self.map_coefficients(k.hom([k.gen()**(p**i)])) for i in range(1, e)] return prod(v).change_ring(k.prime_subfield()) def sylvester_matrix(self, right, variable=None): @@ -1854,7 +1904,7 @@ cdef class MPolynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except(AttributeError): + except AttributeError: return self.base_ring().one() def numerator(self): @@ -1975,7 +2025,7 @@ cdef class MPolynomial(CommutativePolynomial): ArithmeticError: element is non-invertible """ P = self.parent() - B = I.gens() + B = I.gens() try: XY = P.one().lift((self,) + tuple(B)) return P(XY[0]) @@ -2061,7 +2111,7 @@ cdef class MPolynomial(CommutativePolynomial): #Corner case, note that the degree of zero is an Integer return Integer(-1) - if len(weights) == 1: + if len(weights) == 1: # First unwrap it if it is given as one element argument weights = weights[0] @@ -2082,9 +2132,9 @@ cdef class MPolynomial(CommutativePolynomial): for i in range(n): l += weights[i]*m[i] deg = l - for j in range(1,len(A)): + for j in range(1, len(A)): l = Integer(0) - m = A[j] + m = A[j] for i in range(n): l += weights[i]*m[i] if deg < l: @@ -2510,12 +2560,12 @@ cdef class MPolynomial(CommutativePolynomial): from sage.rings.real_mpfr import RealField if self.parent().ngens() != 2: - raise ValueError("(=%s) must have two variables"%self) + raise ValueError("(=%s) must have two variables" % self) if not self.is_homogeneous(): - raise ValueError("(=%s) must be homogeneous"%self) + raise ValueError("(=%s) must be homogeneous" % self) prec = kwds.get('prec', 300) - return_conjugation =kwds.get('return_conjugation', True) + return_conjugation = kwds.get('return_conjugation', True) error_limit = kwds.get('error_limit', 0.000001) emb = kwds.get('emb', None) @@ -2523,14 +2573,14 @@ cdef class MPolynomial(CommutativePolynomial): CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error RF = RealField(prec=prec) R = self.parent() - x,y = R.gens() + x, y = R.gens() # finding quadratic Q_0, gives us our covariant, z_0 from sage.rings.polynomial.binary_form_reduce import covariant_z0 try: z, th = covariant_z0(self, prec=prec, emb=emb, z0_cov=True) except ValueError:# multiple roots - F = self.lc()*prod([p for p,e in self.factor()]) + F = self.lc()*prod([p for p, e in self.factor()]) z, th = covariant_z0(F, prec=prec, emb=emb, z0_cov=True) z = CF(z) # this moves z_0 to our fundamental domain using the three steps laid @@ -2544,11 +2594,11 @@ cdef class MPolynomial(CommutativePolynomial): # moves z into fundamental domain by m m = zc.real().round() # finds amount to move z's real part by Qm = QQ(m) - M = M * matrix(QQ, [[1,Qm], [0,1]]) # move + M = M * matrix(QQ, [[1, Qm], [0, 1]]) # move z -= m # M.inverse()*z is supposed to move z by m elif (zc.real() <= RF(0) and zc.abs() < RF(1)) or (zc.real() > RF(0) and zc.abs() <= RF(1)): # flips z z = -1/z - M = M * matrix(QQ, [[0,-1], [1,0]])# multiply on left because we are taking inverse matrices + M = M * matrix(QQ, [[0, -1], [1, 0]])# multiply on left because we are taking inverse matrices zc = z.center() smallest_coeffs = kwds.get('smallest_coeffs', True) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 3e00ef62991..a22330ef4b8 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -802,7 +802,7 @@ def monomial_coefficient(self, mon): zero = self.parent().base_ring().zero() return self.element().get(exp, zero) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return underlying dictionary with keys the exponents and values the coefficients of this polynomial. diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index d06f07d722e..8db6eb03ea6 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -248,6 +248,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.noncommutative_ideals import Ideal_nc from sage.rings.qqbar_decorators import handle_AA_and_QQbar +from sage.structure.element import parent from sage.structure.richcmp import (op_EQ, op_GE, op_GT, op_LE, op_LT, op_NE, rich_to_bool, richcmp_method) from sage.structure.sequence import Sequence @@ -4965,6 +4966,23 @@ def reduce(self, f): Requires computation of a Groebner basis, which can be a very expensive operation. + + TESTS: + + Check for :issue:`38560`:: + + sage: I.reduce(1) + 1 + sage: I.reduce(1r) + 1 + sage: I.reduce(pi.n()) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Real Field with 53 bits of precision to Multivariate Polynomial Ring in x, y over Rational Field + sage: I.reduce(float(pi.n())) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from to Multivariate Polynomial Ring in x, y over Rational Field """ try: strat = self._groebner_strategy() @@ -4973,6 +4991,7 @@ def reduce(self, f): pass gb = self.groebner_basis() + f = self.ring().coerce(f) return f.reduce(gb) def _contains_(self, f): diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 72b4aea43ce..9c940755987 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2997,7 +2997,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): return self._parent._base._zero_element - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a dictionary representing ``self``. This dictionary is in the same format as the generic MPolynomial: The dictionary diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index db276a75c25..4a596cea922 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -301,7 +301,7 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): except ImportError: BooleanMonomialMonoid = () - is_ring = lambda r: isinstance(r, MPolynomialRing_base) or isinstance(r, BooleanMonomialMonoid) or (isinstance(r, QuotientRing_nc) and isinstance(r.cover_ring(), MPolynomialRing_base)) + is_ring = lambda r: isinstance(r, (MPolynomialRing_base, BooleanMonomialMonoid)) or (isinstance(r, QuotientRing_nc) and isinstance(r.cover_ring(), MPolynomialRing_base)) if is_ring(arg1): ring, gens = arg1, arg2 diff --git a/src/sage/rings/polynomial/polynomial_element.pxd b/src/sage/rings/polynomial/polynomial_element.pxd index a8f2cf3057b..45e64ce6744 100644 --- a/src/sage/rings/polynomial/polynomial_element.pxd +++ b/src/sage/rings/polynomial/polynomial_element.pxd @@ -61,4 +61,3 @@ cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec) cpdef list _dict_to_list(dict x, zero) cpdef bint polynomial_is_variable(x) noexcept - diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index feb0ef1b03b..389e538f83e 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4461,7 +4461,7 @@ cdef class Polynomial(CommutativePolynomial): if self.get_unsafe(n) else zero for n in range(self.degree() + 1)] return S(p) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a sparse dictionary representation of this univariate polynomial. @@ -10038,7 +10038,7 @@ cdef class Polynomial(CommutativePolynomial): sage: f.is_irreducible() True - If the base ring implements `_is_irreducible_univariate_polynomial`, + If the base ring implements ``_is_irreducible_univariate_polynomial``, then this method gets used instead of the generic algorithm which just factors the input:: @@ -10285,7 +10285,7 @@ cdef class Polynomial(CommutativePolynomial): sage: f.is_squarefree.cache False - If the base ring implements `_is_squarefree_univariate_polynomial`, + If the base ring implements ``_is_squarefree_univariate_polynomial``, then this method gets used instead of the generic algorithm in :meth:`_is_squarefree_generic`:: diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 7bbd4e611a9..db8139bddad 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -128,7 +128,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): if check: self.__normalize() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a new copy of the dict of the underlying elements of ``self``. diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pxd b/src/sage/rings/polynomial/polynomial_gf2x.pxd index 293715c0379..3a27019f77c 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pxd +++ b/src/sage/rings/polynomial/polynomial_gf2x.pxd @@ -7,4 +7,3 @@ include "polynomial_template_header.pxi" cdef class Polynomial_GF2X(Polynomial_template): pass - diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 9851c477abf..7275a122c06 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -383,7 +383,7 @@ class of the category, and store the current class of the quotient 1 The test suite passes. However, we have to skip the test for its elements, - since `an_element` has been cached in the call above and its class does not + since ``an_element`` has been cached in the call above and its class does not match the new category's element class anymore:: sage: TestSuite(Q).run(skip=['_test_elements']) # needs sage.rings.number_field diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pxd b/src/sage/rings/polynomial/polynomial_rational_flint.pxd index f4644f19d04..fab8ac5463c 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pxd +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pxd @@ -17,4 +17,3 @@ cdef class Polynomial_rational_flint(Polynomial): cpdef _mod_(self, right) cpdef _unsafe_mutate(self, unsigned long n, value) cpdef Polynomial truncate(self, long n) - diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 0ab8074ec1e..8391d791e92 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -289,7 +289,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: PolynomialRing(Zmod(1), 'x').category() Category of finite commutative rings - Check `is_finite` inherited from category (:issue:`24432`):: + Check ``is_finite`` inherited from category (:issue:`24432`):: sage: Zmod(1)['x'].is_finite() True @@ -642,7 +642,7 @@ def flattening_morphism(self): """ from .multi_polynomial_ring import MPolynomialRing_base base = self.base_ring() - if isinstance(base, PolynomialRing_general) or isinstance(base, MPolynomialRing_base): + if isinstance(base, (PolynomialRing_general, MPolynomialRing_base)): from .flatten import FlatteningMorphism return FlatteningMorphism(self) else: diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 1bdca3af614..60d2dd74b52 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -430,8 +430,8 @@ def can_convert_to_singular(R): base_ring = R.base_ring() if (base_ring is ZZ - or isinstance(base_ring, RationalField) - or isinstance(base_ring, (sage.rings.abc.IntegerModRing, + or isinstance(base_ring, (RationalField, + sage.rings.abc.IntegerModRing, sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField))): return True diff --git a/src/sage/rings/polynomial/q_integer_valued_polynomials.py b/src/sage/rings/polynomial/q_integer_valued_polynomials.py new file mode 100644 index 00000000000..fdcca6d5fff --- /dev/null +++ b/src/sage/rings/polynomial/q_integer_valued_polynomials.py @@ -0,0 +1,1263 @@ +r""" +Quantum-valued polynomial rings + +This provides a `q`-analogue of the :class:`~sage.rings.polynomials.integer_valued_polynomials.IntegerValuedPolynomialRing`. + +AUTHORS: + +- Frédéric Chapoton (2024-03): Initial version +""" +# **************************************************************************** +# Copyright (C) 2024 Frédéric Chapoton +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** +from sage.arith.misc import binomial +from sage.categories.algebras import Algebras +from sage.categories.realizations import Category_realization_of_parent +from sage.categories.rings import Rings +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.q_analogues import q_binomial, q_int +from sage.data_structures.blas_dict import linear_combination +from sage.matrix.constructor import matrix +from sage.misc.bindable_class import BindableClass +from sage.misc.cachefunc import cached_method +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.structure.element import parent +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation + + +def q_int_x(n, q=None): + """ + Return the interpolating polynomial of `q`-integers. + + INPUT: + + - ``n`` -- a positive integer + + - ``q`` -- optional variable + + EXAMPLES:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_int_x + sage: q_int_x(3) + q^2*x + q + 1 + + TESTS:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_int_x + sage: q_int_x(3, 1) + x + 2 + """ + if q is None: + ring_q = PolynomialRing(ZZ, 'q') + q = ring_q.gen() + else: + ring_q = q.parent() + x = polygen(ring_q, 'x') + return q_int(n - 1, q) + q**(n - 1) * x + + +def q_binomial_x(m, n, q=None): + r""" + Return a `q`-analogue of ``binomial(m + x, n)``. + + When evaluated at the `q`-integer `[k]_q`, this gives + the usual `q`-binomial coefficient `[m + k, n]_q`. + + INPUT: + + - ``m`` and ``n`` -- positive integers + + - ``q`` -- optional variable + + EXAMPLES:: + + sage: from sage.combinat.q_analogues import q_int + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_binomial_x, q_int_x + sage: q_binomial_x(4,2)(0) == q_binomial(4,2) + True + sage: q_binomial_x(3,2)(1) == q_binomial(4,2) + True + sage: q_binomial_x(3,1) == q_int_x(4) + True + sage: q_binomial_x(2,0).parent() + Univariate Polynomial Ring in x over Fraction Field of + Univariate Polynomial Ring in q over Integer Ring + + TESTS:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_binomial_x + sage: q_binomial_x(4,2,1) + 1/2*x^2 + 7/2*x + 6 + """ + if q is None: + ring_q = PolynomialRing(ZZ, 'q') + else: + ring_q = q.parent() + ring = PolynomialRing(ring_q.fraction_field(), 'x') + if n == 0: + return ring.one() + return ring.prod(q_int_x(m + 2 - i, q) / q_int(i, q) + for i in range(1, n + 1)) + + +class QuantumValuedPolynomialRing(UniqueRepresentation, Parent): + r""" + The quantum-valued polynomial ring over a base ring. + + Quantum-valued polynomial rings are commutative and associative + algebras, with a basis indexed by nonnegative integers. + + The elements are polynomials in one variable `x` with coefficients in + the field of rational functions in `q`, such that the value at + every nonegative `q`-integer is a polynomial in `q`. + + This algebra is endowed with two bases, named ``B`` or ``Binomial`` + and ``S`` or ``Shifted``. + + INPUT: + + - ``R`` -- commutative ring + + - ``q`` -- optional variable + + There are two possible input formats: + + - If the argument ``q`` is not given, then the ring ``R`` is + taken as a base ring and the ring of Laurent polynomials in `q` + over ``R`` is built and used. + + - If the argument ``q`` is given, then it should belong to the ring ``R`` + and be invertible in this ring. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S(); F + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + + sage: F.gen() + S[1] + + sage: S = QuantumValuedPolynomialRing(ZZ); S + Quantum-Valued Polynomial Ring over Integer Ring + sage: S.base_ring() + Univariate Laurent Polynomial Ring in q over Integer Ring + + Quantum-valued polynomial rings commute with their base ring:: + + sage: K = QuantumValuedPolynomialRing(QQ).S() + sage: a = K.gen() + sage: c = K.monomial(2) + + Quantum-valued polynomial rings are commutative:: + + sage: c^3 * a == c * a * c * c + True + + We can also manipulate elements in the basis and coerce elements from our + base field:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: B = F.basis() + sage: B[2] * B[3] + (q^-5+q^-4+q^-3)*S[3] - (q^-6+2*q^-5+3*q^-4+3*q^-3+2*q^-2+q^-1)*S[4] + + (q^-6+q^-5+2*q^-4+2*q^-3+2*q^-2+q^-1+1)*S[5] + sage: 1 - B[2] * B[2] / 2 + S[0] - (1/2*q^-3)*S[2] + (1/2*q^-4+q^-3+q^-2+1/2*q^-1)*S[3] + - (1/2*q^-4+1/2*q^-3+q^-2+1/2*q^-1+1/2)*S[4] + """ + @staticmethod + def __classcall_private__(cls, R, q=None) -> None: + """ + Normalize the input. + + EXAMPLES:: + + sage: q = LaurentPolynomialRing(QQ, 'q').gen() + sage: F1 = QuantumValuedPolynomialRing(QQ) + sage: F2 = QuantumValuedPolynomialRing(q.parent(), q) + sage: F1 is F2 + True + """ + if R not in Rings().Commutative(): + msg = "argument R must be a commutative ring" + raise TypeError(msg) + + if q is None: + laurent = LaurentPolynomialRing(R, 'q') + q = laurent.gen() + else: + laurent = q.parent() + return super().__classcall__(cls, laurent, q) + + def __init__(self, R, q) -> None: + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ); F + Quantum-Valued Polynomial Ring over Rational Field + sage: TestSuite(F).run() + + sage: F = QuantumValuedPolynomialRing(QQ, 1); F + Quantum-Valued Polynomial Ring over Integer Ring + sage: TestSuite(F).run() + + TESTS:: + + sage: QuantumValuedPolynomialRing(24) + Traceback (most recent call last): + ... + TypeError: argument R must be a commutative ring + """ + self._ground_ring = R.base_ring() + self._q = q + cat = Algebras(R).Commutative().WithBasis() + Parent.__init__(self, base=R, category=cat.WithRealizations()) + + _shorthands = ["B", "S"] + + def _repr_(self) -> str: + r""" + Return the string representation. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ) + sage: F # indirect doctest + Quantum-Valued Polynomial Ring over Rational Field + + sage: QuantumValuedPolynomialRing(ZZ) + Quantum-Valued Polynomial Ring over Integer Ring + """ + base = self.base_ring().base_ring() + return f"Quantum-Valued Polynomial Ring over {base}" + + def a_realization(self): + """ + Return a default realization. + + The Shifted realization is chosen. + + EXAMPLES:: + + sage: QuantumValuedPolynomialRing(QQ).a_realization() + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + """ + return self.Shifted() + + class Bases(Category_realization_of_parent): + def super_categories(self) -> list: + r""" + Return the super-categories of ``self``. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ); A + Quantum-Valued Polynomial Ring over Rational Field + sage: C = A.Bases(); C + Category of bases of Quantum-Valued Polynomial Ring + over Rational Field + sage: C.super_categories() + [Category of realizations of Quantum-Valued Polynomial Ring + over Rational Field, + Join of Category of algebras with basis + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of filtered algebras + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of commutative algebras + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of realizations of unital magmas] + """ + A = self.base() + category = Algebras(A.base_ring()).Commutative().Filtered() + return [A.Realizations(), + category.Realizations().WithBasis()] + + class ParentMethods: + def ground_ring(self): + """ + Return the ring of coefficients. + + This ring is not supposed to contain the variable `q`. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.ground_ring() + Rational Field + """ + return self.realization_of()._ground_ring + + def _repr_(self) -> str: + r""" + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F # indirect doctest + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + """ + real = self.realization_of() + return f"{real} in the {self._realization_name()} basis" + + @cached_method + def one_basis(self): + r""" + Return the number 0, which index the unit of this algebra. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.one_basis() + 0 + sage: A.one() + S[0] + """ + return self.basis().keys()(0) + + def q(self): + """ + Return the variable `q`. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.q() + q + """ + return self.realization_of()._q + + def degree_on_basis(self, m): + r""" + Return the degree of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.degree_on_basis(4) + 4 + """ + return ZZ(m) + + def from_polynomial(self, p): + r""" + Convert a polynomial into the ring of quantum-valued polynomials. + + This raises a :exc:`ValueError` if this is not possible. + + INPUT: + + - ``p`` -- a polynomial in ``x`` with coefficients in ``QQ(q)`` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: A.from_polynomial((S[1]).polynomial()) + S[1] + sage: A.from_polynomial((S[2]+2*S[3]).polynomial()) + S[2] + 2*S[3] + + sage: A = QuantumValuedPolynomialRing(ZZ).B() + sage: B = A.basis() + sage: A.from_polynomial((B[1]).polynomial()) + B[1] + sage: A.from_polynomial((B[2]+2*B[3]).polynomial()) + B[2] + 2*B[3] + + TESTS:: + + sage: A = QuantumValuedPolynomialRing(QQ).B() + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(),'x') + sage: A.from_polynomial(x**2/(q+1)+1) + Traceback (most recent call last): + ... + ValueError: not a polynomial with integer values : 1/(q + 1) is not a Laurent polynomial + """ + B = self.basis() + poly = self._poly + laurent_polys = self.base_ring() + remain = p.change_variable_name('x') + result = self.zero() + while remain: + N = remain.degree() + base_N = poly(N) + top_coeff = remain.leading_coefficient() / base_N.lc() + denom = top_coeff.denominator() + if denom.is_term(): + numer = top_coeff.numerator() + top_coeff_laurent = laurent_polys(numer) / laurent_polys(denom) + else: + msg = 'not a polynomial with integer values :' + msg += f' {top_coeff} is not a Laurent polynomial' + raise ValueError(msg) + remain += -top_coeff * base_N + result += top_coeff_laurent * B[N] + return result + + def gen(self, i=0): + r""" + Return the generator of the algebra. + + The optional argument is ignored. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: F.gen() + S[1] + """ + return self.basis()[1] + + @cached_method + def algebra_generators(self): + r""" + Return the generators of this algebra. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S(); A + Quantum-Valued Polynomial Ring over Integer Ring + in the shifted basis + sage: A.algebra_generators() + Family (S[1],) + """ + return Family([self.basis()[1]]) + + gens = algebra_generators + + class ElementMethods: + def __call__(self, v): + """ + Return the evaluation at some value ``v``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: f = B**2+4*B+6 + sage: f(1/3) + (q^2 + 18*q + 99)/9 + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: f = F.monomial(2)+4*B+6 + sage: f(1/3) + (66*q^2 + 66*q - 2)/(9*q^2 + 9*q) + """ + return self.polynomial()(v) + + def polynomial(self): + """ + Convert to a polynomial in `x`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: S = F.gen() + sage: (S+1).polynomial() + q*x + 2 + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: (B+1).polynomial() + x + 1 + + TESTS:: + + sage: F.zero().polynomial().parent() + Univariate Polynomial Ring in x over Fraction Field + of Univariate Polynomial Ring in q over Integer Ring + """ + ring = self.parent().ground_ring() + fractions = PolynomialRing(ring, 'q').fraction_field() + R = PolynomialRing(fractions, 'x') + p = self.parent()._poly + return R.sum(c * p(i) for i, c in self) + + def shift(self, j=1): + """ + Shift all indices by `j`. + + INPUT: + + - `j` -- integer (default 1) + + In the binomial basis, the shift by 1 corresponds to + a summation operator from `0` to `x`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).shift() + S[1] + S[2] + """ + A = self.parent() + return A._from_dict({A._indices(i + j): c for i, c in self}) + + def sum_of_coefficients(self): + """ + Return the sum of coefficients. + + In the shifted basis, this is the evaluation at `x=0`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.basis() + sage: (B[2]*B[4]).sum_of_coefficients() + 1 + """ + R = self.parent().base_ring() + return R.sum(self._monomial_coefficients.values()) + + class Shifted(CombinatorialFreeModule, BindableClass): + r""" + The quantum-valued polynomial ring in the shifted basis. + + The basis used here is given by `S[i] = \genfrac{[}{]}{0pt}{}{i+x}{i}_q` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `S[n_1] \cdot S[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} (-1)^k q^{\binom{k}{2} - n_1 * n_2} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q S[n_1 + n_2 - k]. + """ + def __init__(self, A): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S(); F + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + sage: TestSuite(F).run() # not tested + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + category=A.Bases(), + prefix="S", + latex_prefix=r"\mathbb{S}") + + def _an_element_(self): + """ + Return a small element of ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F.an_element() + 2*S[0] + 4*S[2] + """ + NonNeg = self.basis().keys() + ring = self.base_ring() + return self.element_class(self, {NonNeg(0): ring(2), + NonNeg(2): ring(4)}) + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F._realization_name() + 'shifted' + """ + return "shifted" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.product_on_basis(0, 1) + S[1] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + q = self.q() + return self._from_dict({i + j - k: (-1)**k + * q_binomial(i, k) + * q_binomial(i + j - k, i) + * q**(binomial(k, 2) - i * j) + for k in range(i + 1)}) + + def _from_binomial_basis(self, i): + """ + Convert from the ``binomial(x,k)`` basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = QuantumValuedPolynomialRing(ZZ).S() + sage: B = QuantumValuedPolynomialRing(ZZ).B() + sage: b = B.basis() + sage: S(b[3]+1) # indirect doctest + -(q^-6-1)*S[0] + (q^-8+q^-7+q^-6)*S[1] + - (q^-9+q^-8+q^-7)*S[2] + (q^-9)*S[3] + sage: B(_) + B[0] + B[3] + """ + i = ZZ(i) + R = self.base_ring() + q = self.q() + return self._from_dict({k: R((-1)**(i - k) * q_binomial(i, k)) + * q**(-i**2 + binomial(i - k, 2)) + for k in range(i + 1)}) + + def from_h_vector(self, hv): + """ + Convert from some `h`-vector. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: B = A.basis() + sage: ex = B[2] + B[3] + sage: A.from_h_vector(ex.h_vector()) + S[2] + S[3] + + sage: q = A.base_ring().gen() + sage: ex = B[2] + q*B[3] + sage: A.from_h_vector(ex.h_vector()) + S[2] + q*S[3] + """ + B = self.basis() + ring = self.base_ring() + q = self.q() + d = len(hv) - 1 + m = matrix(ring, d + 1, d + 1, + [(-1)**(d - j) * q_binomial(d - i, d - j, q) * + q**(-d * (d - i) + binomial(d - j, 2)) + for j in range(d + 1) + for i in range(d + 1)]) + v = vector(ring, [hv[i] for i in range(d + 1)]) + return sum(ring(c) * B[i] for i, c in enumerate(m * v)) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + INPUT: + + - ``x`` -- an element of the base ring or something convertible + + EXAMPLES:: + + sage: R = QuantumValuedPolynomialRing(QQ).S() + sage: x = R.gen() + sage: R(3) + 3*S[0] + sage: R(x) + S[1] + """ + P = parent(x) + if isinstance(P, QuantumValuedPolynomialRing.Shifted): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a quantum-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if not x: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R) -> bool: + r""" + Return whether there is a coercion from ``R`` into ``self``. + + INPUT: + + - ``R`` -- a commutative ring + + The things that coerce into ``self`` are + + - Quantum-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(GF(7)).S(); F + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the quantum-valued polynomial ring canonically coerce in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + (6*q^-1)*S[1] + (q^-1+1)*S[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to GF(7):: + + sage: F.coerce(1) # indirect doctest + S[0] + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field to + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*S[0] + + The quantum-valued polynomial ring over `\ZZ` on `x` coerces in, since + `\ZZ` coerces to `\GF{7}`:: + + sage: G = QuantumValuedPolynomialRing(ZZ).S() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + -(q^-1)*S[1] + (q^-1+1)*S[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the shuffle + algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Quantum-Valued Polynomial + Ring over Finite Field of size 7 in the shifted basis + to Quantum-Valued Polynomial Ring over Integer Ring + in the shifted basis + + TESTS:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: G = QuantumValuedPolynomialRing(QQ).S() + sage: H = QuantumValuedPolynomialRing(ZZ).S() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ, 'x')) + False + """ + # quantum-valued polynomial rings in the same variable + # over any base that coerces in: + if isinstance(R, QuantumValuedPolynomialRing.Shifted): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, QuantumValuedPolynomialRing.Binomial): + return R.module_morphism(self._from_binomial_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `S[i]` to a polynomial. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: F._poly(4).factor() + (1/(q^6 + 3*q^5 + 5*q^4 + 6*q^3 + 5*q^2 + 3*q + 1)) * + (q*x + 1) * (q^2*x + q + 1) * (q^3*x + q^2 + q + 1) * + (q^4*x + q^3 + q^2 + q + 1) + """ + return q_binomial_x(i, i) + + class Element(CombinatorialFreeModule.Element): + def umbra(self): + """ + Return the Bernoulli umbra. + + This is the derivative at `-1` of the shift by one. + + This is related to Carlitz's `q`-Bernoulli numbers. + + .. SEEALSO:: :meth:`derivative_at_minus_one` + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).umbra() + (q + 2)/(q + 1) + """ + return self.shift().derivative_at_minus_one() + + def variable_shift(self, k=1): + r""" + Return the image by the shift on variables. + + The shift is the substitution operator + + .. MATH:: + + x \mapsto q x + 1. + + INPUT: + + - `k` -- integer (default: 1) + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: S[5].variable_shift() + S[0] + q*S[1] + q^2*S[2] + q^3*S[3] + q^4*S[4] + q^5*S[5] + + sage: S[5].variable_shift(-1) + -(q^-5)*S[4] + (q^-5)*S[5] + + TESTS:: + + sage: S[5].variable_shift(0) + S[5] + sage: S[5].variable_shift().variable_shift(-1) + S[5] + sage: S[5].variable_shift(2).variable_shift(-2) + S[5] + sage: S[3].variable_shift(-2) + (q^-5)*S[1] - (q^-6+q^-5)*S[2] + (q^-6)*S[3] + """ + if k == 0: + return self + + A = self.parent() + q = A.q() + + def on_basis(n): + return {A._indices(j): q**(k * j) + * q_binomial(k + n - 1 - j, n - j) + for j in range(n + 1)} + + mc = self._monomial_coefficients + ret = linear_combination((on_basis(index), coeff) + for index, coeff in mc.items()) + return A.element_class(A, ret) + + def derivative_at_minus_one(self): + """ + Return the 'derivative' at -1. + + .. SEEALSO:: :meth:`umbra` + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).derivative_at_minus_one() + 1 + """ + ring = q_int(1).parent() + return ring.sum(c / q_int(i) for i, c in self if i > 0) + + def h_vector(self): + """ + Return the numerator of the generating series of values. + + If ``self`` is an Ehrhart polynomial, this is the h-vector. + + .. SEEALSO:: :meth:`h_polynomial`, :meth:`fraction` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: ex = A.basis()[4] + sage: ex.h_vector() + (0, 0, 0, 0, 1) + + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(),'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.h_vector() + (0, q^3, 2*q + 2*q^2, 1) + """ + d = max(self.support()) + ring = self.parent().base_ring() + q = self.parent().q() + + def fn(j, i): + return ((-1)**(d - j) * + q**(binomial(d - j + i + 1, 2) - + binomial(i + 1, 2)) * + q_binomial(d - i, d - j)) + m = matrix(ring, d + 1, d + 1, fn) + v = vector(ring, [self.coefficient(i) for i in range(d + 1)]) + return m * v + + def h_polynomial(self): + """ + Return the `h`-vector as a polynomial. + + .. SEEALSO:: :meth:`h_vector`, :meth:`fraction` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: q = polygen(ZZ,'q') + sage: x = polygen(q.parent(),'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.h_polynomial() + z^3 + (2*q + 2*q^2)*z^2 + q^3*z + """ + ring = PolynomialRing(self.parent().base_ring(), 'z') + return ring(list(self.h_vector())) + + def fraction(self): + """ + Return the generating series of values as a fraction. + + .. SEEALSO:: :meth:`h_vector`, :meth:`h_polynomial` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: ex = A.basis()[4] + sage: ex.fraction().factor() + (-1) * (t - 1)^-1 * (q*t - 1)^-1 * (q^2*t - 1)^-1 * (q^3*t - 1)^-1 * (q^4*t - 1)^-1 + + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(), 'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.fraction().factor() + (t - 1)^-1 * (q*t - 1)^-1 * (q^2*t - 1)^-1 * (q^3*t - 1)^-1 * (q^3*t^2 + 2*q^2*t + 2*q*t + 1) + sage: ex.fraction().numerator() + q^3*t^2 + 2*q^2*t + 2*q*t + 1 + """ + v = self.h_vector() + d = len(v) + R = PolynomialRing(QQ, 'q,t') + frac_R = R.fraction_field() + q, t = R.gens() + denom = R.prod(1 - q**i * t for i in range(d)) + numer = sum(frac_R(v[i]) * t**(d - 1 - i) for i in range(d)) + return numer / denom + + S = Shifted + + # ===== Another basis for the same algebra ===== + + class Binomial(CombinatorialFreeModule, BindableClass): + r""" + The quantum-valued polynomial ring in the binomial basis. + + The basis used here is given by `B[i] = \genfrac{[}{]}{0pt}{}{x}{i}_q` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `B[n_1] \cdot B[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} q^{(k-n_1)(k-n_2)} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q B[n_1 + n_2 - k]. + """ + def __init__(self, A) -> None: + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).B(); F + Quantum-Valued Polynomial Ring over Rational Field + in the binomial basis + sage: TestSuite(F).run() # not tested + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + category=A.Bases(), + prefix="B", + latex_prefix=r"\mathbb{B}") + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = QuantumValuedPolynomialRing(QQ).B() + sage: F._realization_name() + 'binomial' + """ + return "binomial" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + The formula is taken from Theorem 3.4 in [HaHo2017]_. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).B() + sage: A.product_on_basis(0, 1) + B[1] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + + q = self.q() + return self._from_dict({i + j - k: + q_binomial(i, k) + * q_binomial(i + j - k, i) + * q**((k - i) * (k - j)) + for k in range(i + 1)}) + + def _from_shifted_basis(self, i): + """ + Convert from the shifted binomial(x+k,k) basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = QuantumValuedPolynomialRing(ZZ).S() + sage: B = QuantumValuedPolynomialRing(ZZ).B() + sage: s = S.basis() + sage: B(s[3]+1) # indirect doctest + 2*B[0] + (q+q^2+q^3)*B[1] + (q^4+q^5+q^6)*B[2] + q^9*B[3] + sage: S(_) + S[0] + S[3] + """ + i = ZZ(i) + R = self.base_ring() + q = self.q() + return self._from_dict({k: R(q_binomial(i, k)) + * q**(k**2) + for k in range(i + 1)}) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: R = QuantumValuedPolynomialRing(QQ).B() + sage: x = R.gen() + sage: R(3) + 3*B[0] + sage: R(x) + B[1] + """ + P = x.parent() + if isinstance(P, QuantumValuedPolynomialRing.Binomial): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a quantum-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if not x: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return whether there is a coercion from ``R`` into ``self``. + + INPUT: + + - ``R`` -- a commutative ring + + The things that coerce into ``self`` are + + - Quantum-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(GF(7)).B(); F + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the integer-valued polynomial ring canonically coerce + in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + B[1] + (q+q^2)*B[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to `\GF(7)`:: + + sage: F.coerce(1) # indirect doctest + B[0] + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field to + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*B[0] + + The integer-valued polynomial ring over `\ZZ` on `x` coerces in, + since `\ZZ` coerces to `\GF{7}`:: + + sage: G = QuantumValuedPolynomialRing(ZZ).B() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + B[1] + (q+q^2)*B[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + integer-valued polynomial algebra over `\GF{7}` does not + coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis to Quantum-Valued Polynomial Ring + over Integer Ring in the binomial basis + + TESTS:: + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: G = QuantumValuedPolynomialRing(QQ).B() + sage: H = QuantumValuedPolynomialRing(ZZ).B() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ,'x')) + False + """ + # quantum-valued polynomial rings over any base + # that coerces in: + if isinstance(R, QuantumValuedPolynomialRing.Binomial): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, QuantumValuedPolynomialRing.Shifted): + return R.module_morphism(self._from_shifted_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `B[i]` to a polynomial. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: F._poly(4).factor() + (1/(q^12 + 3*q^11 + 5*q^10 + 6*q^9 + 5*q^8 + 3*q^7 + q^6)) * + (x - 1) * x * (x - q - 1) * (x - q^2 - q - 1) + """ + return q_binomial_x(0, i) + + class Element(CombinatorialFreeModule.Element): + def variable_shift(self, k=1): + r""" + Return the image by the shift of variables. + + On polynomials, the action for `k=1` is the shift + on variables `x \mapsto 1 + qx`. + + This implementation follows formula (5.5) in [HaHo2017]_. + + INPUT: + + - `k` -- nonnegative integer (default: 1) + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).B() + sage: B = A.basis() + sage: B[5].variable_shift() + B[4] + q^5*B[5] + + TESTS:: + + sage: B[5].variable_shift(0) + B[5] + """ + if k == 0: + return self + + A = self.parent() + q = A.q() + + def on_basis(n): + return {A._indices(j): q**((k + j - n) * j) + * q_binomial(k, n - j) + for j in range(n + 1)} + + mc = self._monomial_coefficients + ret = linear_combination((on_basis(index), coeff) + for index, coeff in mc.items()) + return A.element_class(A, ret) + + B = Binomial diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd index 438773a39ef..4c6a4b638c9 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd @@ -7,4 +7,3 @@ cdef class SkewPolynomial_finite_order_dense (SkewPolynomial_generic_dense): cdef _matphir_c(self) cdef _matmul_c(self) - diff --git a/src/sage/rings/polynomial/weil/weil_polynomials.pyx b/src/sage/rings/polynomial/weil/weil_polynomials.pyx index e2dd7bd04e7..4c5517ad6d1 100755 --- a/src/sage/rings/polynomial/weil/weil_polynomials.pyx +++ b/src/sage/rings/polynomial/weil/weil_polynomials.pyx @@ -83,7 +83,7 @@ cdef class dfs_manager: """ Data structure to manage depth-first search. - Such a structure is created and managed by an instance of `WeilPolynomials_iter`. + Such a structure is created and managed by an instance of ``WeilPolynomials_iter``. There is generally no need for a user to manipulate it directly. """ cdef int d @@ -156,8 +156,8 @@ cdef class dfs_manager: """ Count nodes. - This method should not be called directly. Instead, use the `node_count` method - of an instance of `WeilPolynomials` or `WeilPolynomials_iter`. + This method should not be called directly. Instead, use the ``node_count`` method + of an instance of ``WeilPolynomials`` or ``WeilPolynomials_iter``. TESTS:: @@ -179,7 +179,7 @@ cdef class dfs_manager: Advance the tree exhaustion. This method should not be called directly. Instead, use the iterator - `WeilPolynomials_iter` or the iterable `WeilPolynomials`. + ``WeilPolynomials_iter`` or the iterable ``WeilPolynomials``. TESTS:: diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index 8f7ff769dd1..baeef616e02 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -734,7 +734,7 @@ cdef class PowerSeries_pari(PowerSeries): else: return [R(g)] + [R.zero()] * (n - 1) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a dictionary of coefficients for ``self``. diff --git a/src/sage/rings/power_series_poly.pxd b/src/sage/rings/power_series_poly.pxd index e37e1fb26cf..82539afef3f 100644 --- a/src/sage/rings/power_series_poly.pxd +++ b/src/sage/rings/power_series_poly.pxd @@ -7,4 +7,3 @@ cdef class PowerSeries_poly(PowerSeries): cdef class BaseRingFloorDivAction(Action): pass - diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 39b05cce069..c284b06a5e4 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -794,7 +794,7 @@ cdef class PowerSeries_poly(PowerSeries): """ return self.__f.list() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): """ Return a dictionary of coefficients for ``self``. @@ -814,7 +814,7 @@ cdef class PowerSeries_poly(PowerSeries): sage: f.dict() {0: 1, 10: 1} """ - return self.__f.monomial_coefficients() + return self.__f.monomial_coefficients(copy=copy) dict = monomial_coefficients diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 72df892337b..3806663eaf0 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -7098,12 +7098,26 @@ def exactify(self): sage: cp.exactify() sage: cp._exact True + + TESTS: + + Check that interrupting ``exactify()`` does not lead to incoherent state:: + + sage: x = polygen(AA) + sage: p = AA(2)^(1/100) * x + AA(3)^(1/100) + sage: cp = AA.common_polynomial(p) + sage: alarm(0.5); cp.generator() + Traceback (most recent call last): + ... + AlarmInterrupt + sage: alarm(0.5); cp.generator() + Traceback (most recent call last): + ... + AlarmInterrupt """ if self._exact: return - self._exact = True - if self._poly.base_ring() is QQ: self._factors = [fac_exp[0] for fac_exp in self._poly.factor()] self._gen = qq_generator @@ -7128,6 +7142,8 @@ def exactify(self): self._factors = [fac_exp[0] for fac_exp in fp.factor()] + self._exact = True + def factors(self): r""" EXAMPLES:: diff --git a/src/sage/rings/real_double_element_gsl.pyx b/src/sage/rings/real_double_element_gsl.pyx index 001564dee37..7fea4dbc155 100644 --- a/src/sage/rings/real_double_element_gsl.pyx +++ b/src/sage/rings/real_double_element_gsl.pyx @@ -8,7 +8,16 @@ from cysignals.signals cimport sig_on, sig_off from sage.arith.constants cimport * -from sage.libs.gsl.all cimport * +from sage.libs.gsl.errno cimport gsl_set_error_handler_off +from sage.libs.gsl.math cimport * +from sage.libs.gsl.exp cimport * +from sage.libs.gsl.log cimport gsl_sf_log +from sage.libs.gsl.trig cimport * +from sage.libs.gsl.dilog cimport gsl_sf_dilog +from sage.libs.gsl.gamma cimport gsl_sf_fact, gsl_sf_gamma +from sage.libs.gsl.zeta cimport gsl_sf_zeta +from sage.libs.gsl.erf cimport gsl_sf_erf + gsl_set_error_handler_off() diff --git a/src/sage/rings/real_lazy.pxd b/src/sage/rings/real_lazy.pxd index 60a6580a550..c7aa82cd596 100644 --- a/src/sage/rings/real_lazy.pxd +++ b/src/sage/rings/real_lazy.pxd @@ -27,4 +27,3 @@ cdef class LazyUnop(LazyFieldElement): cdef class LazyNamedUnop(LazyUnop): cdef readonly _extra_args - diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 7e1ab748b55..a870c6bf0c7 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -1437,6 +1437,33 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RealNumber('1_3.1e-32_45') 1.31000000000000e-3244 + + Test conversion from base different from `10`:: + + sage: RR('0xabc') + Traceback (most recent call last): + ... + TypeError: unable to convert '0xabc' to a real number + sage: RR("0x123.e1", base=0) # rel tol 1e-12 + 291.878906250000 + sage: RR("0x123.@1", base=0) # rel tol 1e-12 + 4656.00000000000 + sage: RR("1Xx", base=36) # rel tol 1e-12 + 2517.00000000000 + sage: RR("-1Xx@-10", base=62) # rel tol 1e-12 + -7.08805492048139e-15 + sage: RR("1", base=1) + Traceback (most recent call last): + ... + ValueError: base (=1) must be 0 or between 2 and 62 + sage: RR("1", base=-1) + Traceback (most recent call last): + ... + ValueError: base (=-1) must be 0 or between 2 and 62 + sage: RR("1", base=63) + Traceback (most recent call last): + ... + ValueError: base (=63) must be 0 or between 2 and 62 """ if x is not None: self._set(x, base) @@ -1485,6 +1512,8 @@ cdef class RealNumber(sage.structure.element.RingElement): # Real Numbers are supposed to be immutable. cdef RealField_class parent parent = self._parent + if base != 0 and (base < 2 or base > 62): + raise ValueError(f"base (={base}) must be 0 or between 2 and 62") if isinstance(x, RealNumber): if isinstance(x, RealLiteral): s = (x).literal diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 28f272a18f0..c4137a6974f 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -218,7 +218,7 @@ cdef class Ring(ParentWithGens): sage: CDF._repr_option('element_is_atomic') # needs sage.rings.complex_double False - Check that categories correctly implement `is_finite` and `cardinality`:: + Check that categories correctly implement ``is_finite`` and ``cardinality``:: sage: QQ.is_finite() False @@ -1018,37 +1018,6 @@ cdef class IntegralDomain(CommutativeRing): CommutativeRing.__init__(self, base_ring, names=names, normalize=normalize, category=category) - def is_integrally_closed(self): - r""" - Return ``True`` if this ring is integrally closed in its field of - fractions; otherwise return ``False``. - - When no algorithm is implemented for this, then this - function raises a :exc:`NotImplementedError`. - - Note that ``is_integrally_closed`` has a naive implementation - in fields. For every field `F`, `F` is its own field of fractions, - hence every element of `F` is integral over `F`. - - EXAMPLES:: - - sage: ZZ.is_integrally_closed() - True - sage: QQ.is_integrally_closed() - True - sage: QQbar.is_integrally_closed() # needs sage.rings.number_field - True - sage: GF(5).is_integrally_closed() - True - sage: Z5 = Integers(5); Z5 - Ring of integers modulo 5 - sage: Z5.is_integrally_closed() - Traceback (most recent call last): - ... - AttributeError: 'IntegerModRing_generic_with_category' object has no attribute 'is_integrally_closed'... - """ - raise NotImplementedError - def is_field(self, proof=True): r""" Return ``True`` if this ring is a field. @@ -1228,18 +1197,6 @@ cdef class Field(CommutativeRing): """ return True - def is_integrally_closed(self): - """ - Return ``True`` since fields are trivially integrally closed in - their fraction field (since they are their own fraction field). - - EXAMPLES:: - - sage: Frac(ZZ['x,y']).is_integrally_closed() - True - """ - return True - def krull_dimension(self): """ Return the Krull dimension of this field, which is 0. diff --git a/src/sage/rings/ring_extension_conversion.pxd b/src/sage/rings/ring_extension_conversion.pxd index e3815a411ba..5a7c871841e 100644 --- a/src/sage/rings/ring_extension_conversion.pxd +++ b/src/sage/rings/ring_extension_conversion.pxd @@ -13,5 +13,3 @@ cpdef from_backend_morphism(f, RingExtension_generic E) cpdef to_backend(arg) cpdef from_backend(arg, E) - - diff --git a/src/sage/rings/ring_extension_element.pxd b/src/sage/rings/ring_extension_element.pxd index 9bd662f3d0f..ca83f669643 100644 --- a/src/sage/rings/ring_extension_element.pxd +++ b/src/sage/rings/ring_extension_element.pxd @@ -18,5 +18,3 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): cdef _trace(self, Parent base) cdef _norm(self, Parent base) cpdef minpoly(self, base=*, var=*) - - diff --git a/src/sage/rings/species.py b/src/sage/rings/species.py index bcda9a9f510..494e7020331 100644 --- a/src/sage/rings/species.py +++ b/src/sage/rings/species.py @@ -31,7 +31,7 @@ """ -from itertools import accumulate, chain +from itertools import accumulate, chain, product from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.modules import Modules @@ -381,7 +381,7 @@ def __init__(self, names): TESTS: - We have to exclude `_test_graded_components`, because + We have to exclude ``_test_graded_components``, because :meth:`~sage.combinat.integer_vector.IntegerVectors.some_elements` yields degrees that are too large:: @@ -730,16 +730,17 @@ def _an_element_(self): Element = AtomicSpeciesElement -def _stabilizer_subgroups(G, X, a): +def _stabilizer_subgroups(G, X, a, side='right', check=True): r""" Return subgroups conjugate to the stabilizer subgroups of the - given (left) group action. + given group action. INPUT: - ``G`` -- the acting group - ``X`` -- the set ``G`` is acting on - - ``a`` -- the (left) action + - ``a`` -- the action, a function `G\times X\to X` if ``side`` is + ``'left'``, `X\times G\to X` if ``side`` is ``'right'`` EXAMPLES:: @@ -747,17 +748,17 @@ def _stabilizer_subgroups(G, X, a): sage: S = SymmetricGroup(4) sage: X = SetPartitions(S.degree(), [2,2]) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,2), (1,3)(2,4)]] sage: S = SymmetricGroup(8) sage: X = SetPartitions(S.degree(), [3,3,2]) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left', check=False) [Permutation Group with generators [(7,8), (6,7), (4,5), (1,3)(2,6)(4,7)(5,8), (1,3)]] sage: S = SymmetricGroup(4) sage: X = SetPartitions(S.degree(), 2) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,4), (1,3,4)], Permutation Group with generators [(1,3)(2,4), (1,4)]] @@ -766,19 +767,54 @@ def _stabilizer_subgroups(G, X, a): sage: S = SymmetricGroup([1,2,4,5,3,6]).young_subgroup([4, 2]) sage: X = [pi for pi in SetPartitions(6, [3,3]) if all(sum(1 for e in b if e % 3) == 2 for b in pi)] - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,2), (4,5), (1,4)(2,5)(3,6)]] TESTS:: - sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H) + sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H, side='left') [Permutation Group with generators [(1,2)]] + + sage: _stabilizer_subgroups(SymmetricGroup(2), [1, 1], lambda pi, H: H, side='left') + Traceback (most recent call last): + ... + ValueError: The argument X must be a set, but [1, 1] contains duplicates + + sage: G = SymmetricGroup(3) + sage: X = [1, 2, 3] + sage: _stabilizer_subgroups(G, X, lambda pi, x: pi(x), side='left') + [Permutation Group with generators [(2,3)]] + sage: _stabilizer_subgroups(G, X, lambda x, pi: pi(x), side='right') + Traceback (most recent call last): + ... + ValueError: The given function is not a right group action: g=(1,3,2), h=(2,3), x=1 do not satisfy the condition """ to_gap = {x: i for i, x in enumerate(X, 1)} - X = set(X) # because orbit_decomposition turns X into a set - g_orbits = [orbit_decomposition(X, lambda x: a(g, x)) - for g in G.gens()] + X_set = set(X) # because orbit_decomposition turns X into a set + + if len(X_set) != len(X): + raise ValueError(f"The argument X must be a set, but {X} contains duplicates") + + if side == "left": + if check: + for g, h, x in product(G, G, X): + # Warning: the product in permutation groups is left-to-right composition + if not a(h * g, x) == a(g, a(h, x)): + raise ValueError(f"The given function is not a left group action: g={g}, h={h}, x={x} do not satisfy the condition") + + g_orbits = [orbit_decomposition(X_set, lambda x: a(g, x)) + for g in G.gens()] + elif side == "right": + if check: + for g, h, x in product(G, G, X): + if not a(x, h * g) == a(a(x, g), h): + raise ValueError(f"The given function is not a right group action: g={g}, h={h}, x={x} do not satisfy the condition") + + g_orbits = [orbit_decomposition(X_set, lambda x: a(x, g)) + for g in G.gens()] + else: + raise ValueError(f"The argument side must be 'left' or 'right' but is {side}") gens = [PermutationGroupElement([tuple([to_gap[x] for x in o]) for o in g_orbit]) @@ -834,7 +870,7 @@ def __init__(self, names): TESTS: - We have to exclude `_test_graded_components`, because + We have to exclude ``_test_graded_components``, because :meth:`~sage.combinat.integer_vector.IntegerVectors.some_elements` yields degrees that are too large:: @@ -873,13 +909,15 @@ def _element_constructor_(self, G, pi=None, check=True): INPUT: - ``G`` -- element of ``self`` (in this case ``pi`` must be - ``None``) permutation group, or pair ``(X, a)`` consisting - of a finite set and a transitive action + ``None``) or permutation group, or triple ``(X, a, side)`` + consisting of a finite set, a transitive action and + a string 'left' or 'right'; the side can be omitted, it is + then assumed to be 'right' - ``pi`` -- ``dict`` mapping sorts to iterables whose union is the domain of ``G`` (if ``G`` is a permutation group) or the domain of the acting symmetric group (if ``G`` is a - pair ``(X, a)``); if `k=1` and ``G`` is a permutation - group, ``pi`` can be omitted + triple ``(X, a, side)``); if `k=1` and ``G`` is a + permutation group, ``pi`` can be omitted - ``check`` -- boolean (default: ``True``); skip input checking if ``False`` @@ -901,11 +939,11 @@ def _element_constructor_(self, G, pi=None, check=True): sage: M = MolecularSpecies("X") sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) sage: X = SetPartitions(4, [2, 2]) - sage: M((X, a), {0: X.base_set()}) + sage: M((X, a, 'left'), {0: X.base_set()}) P_4 sage: X = SetPartitions(8, [4, 2, 2]) - sage: M((X, a), {0: X.base_set()}) + sage: M((X, a, 'left'), {0: X.base_set()}, check=False) E_4*P_4 TESTS:: @@ -922,7 +960,7 @@ def _element_constructor_(self, G, pi=None, check=True): sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: M((X, a), {0: [1,2], 1: [3,4]}) + sage: M((X, a, 'left'), {0: [1,2], 1: [3,4]}) Traceback (most recent call last): ... ValueError: action is not transitive @@ -962,18 +1000,25 @@ def _element_constructor_(self, G, pi=None, check=True): ... ValueError: 0 must be a permutation group or a pair (X, a) specifying a group action of the symmetric group on pi=None + """ if parent(G) is self: # pi cannot be None because of framework raise ValueError("cannot reassign sorts to a molecular species") if isinstance(G, tuple): - X, a = G + if len(G) == 2: + X, a = G + side = 'right' + else: + X, a, side = G + if side not in ['left', 'right']: + raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) - H = _stabilizer_subgroups(S, X, a) + H = _stabilizer_subgroups(S, X, a, side=side, check=check) if len(H) > 1: raise ValueError("action is not transitive") G = H[0] @@ -1575,6 +1620,55 @@ def is_atomic(self): """ return self.is_molecular() and len(self.support()[0]) == 1 + def tilde(self): + r""" + Return the tilde species of ``self``. + + The tilde species `\tilde F` of a species `F` has as + structures the set of pairs `(s, a)`, consisting of an + `F`-structure `s` and an automorphism `a` of `s`. + + We use https://mathoverflow.net/a/480852 to compute it. + + EXAMPLES:: + + sage: from sage.rings.species import AtomicSpecies, MolecularSpecies, PolynomialSpecies + sage: M = MolecularSpecies("X") + sage: P = PolynomialSpecies(QQ, "X") + sage: sortkey = lambda x: (len(x[1]), sum(x[1].coefficients()), str(x[0])) + sage: n=4; table(sorted([(m, P.monomial(m).tilde()) for m in M.subset(n)], key=sortkey)) + X^4 X^4 + X^2*E_2 2*X^2*E_2 + {((1,2)(3,4),)} 2*{((1,2)(3,4),)} + X*C_3 3*X*C_3 + C_4 4*C_4 + E_2^2 4*E_2^2 + Pb_4 4*Pb_4 + X*E_3 X*E_3 + X^2*E_2 + X*C_3 + Eo_4 Eo_4 + 2*X*C_3 + Pb_4 + P_4 2*P_4 + E_2^2 + Pb_4 + C_4 + E_4 E_4 + E_2^2 + X*C_3 + P_4 + C_4 + + sage: P. = PolynomialSpecies(QQ) + sage: E2 = PolynomialSpecies(QQ, "X")(SymmetricGroup(2)) + sage: E2(X*Y).tilde() + 2*E_2(XY) + """ + P = self.parent() + M = P._indices + P_one = P.one() + one = ZZ.one() + result = P.zero() + for m, c in self: + result_m = P_one + for a, e in m: + G, pi = a.permutation_group() + result_a = P.sum(P(G.centralizer(g), pi) + for g in G.conjugacy_classes_representatives()) + result_m *= result_a ** e + result += c * result_m + return result + def hadamard_product(self, other): r""" Compute the hadamard product of ``self`` and ``other``. @@ -2072,8 +2166,10 @@ def _element_constructor_(self, G, pi=None, check=True): INPUT: - ``G`` -- element of ``self`` (in this case ``pi`` must be - ``None``), permutation group, or pair ``(X, a)`` consisting - of a finite set and an action + ``None``) or permutation group, or triple ``(X, a, side)`` + consisting of a finite set, an action and a string 'left' + or 'right'; the side can be omitted, it is then assumed to + be 'right' - ``pi`` -- ``dict`` mapping sorts to iterables whose union is the domain of ``G`` (if ``G`` is a permutation group) or the domain of the acting symmetric group (if ``G`` is a @@ -2091,13 +2187,13 @@ def _element_constructor_(self, G, pi=None, check=True): sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: P((X, a), {0: [1,2], 1: [3,4]}) + sage: P((X, a, 'left'), {0: [1,2], 1: [3,4]}) E_2(X)*E_2(Y) + X^2*E_2(Y) + E_2(XY) + Y^2*E_2(X) sage: P = PolynomialSpecies(ZZ, ["X"]) sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: P((X, a), {0: [1,2,3,4]}) + sage: P((X, a, 'left'), {0: [1,2,3,4]}) X*E_3 + P_4 The species of permutation groups:: @@ -2106,10 +2202,10 @@ def _element_constructor_(self, G, pi=None, check=True): sage: n = 4 sage: S = SymmetricGroup(n) sage: X = S.subgroups() - sage: def act(pi, G): # WARNING: returning H does not work because of equality problems + sage: def act(G, pi): # WARNING: returning H does not work because of equality problems ....: H = S.subgroup(G.conjugate(pi).gens()) ....: return next(K for K in X if K == H) - sage: P((X, act), {0: range(1, n+1)}) + sage: P((X, act), {0: range(1, n+1)}, check=False) 4*E_4 + 4*P_4 + E_2^2 + 2*X*E_3 Create a multisort species given an action:: @@ -2127,7 +2223,7 @@ def _element_constructor_(self, G, pi=None, check=True): ....: if r == t and c == b: ....: return r, c ....: raise ValueError - sage: P((X, lambda g, x: act(x[0], x[1], g)), pi) + sage: P((X, lambda g, x: act(x[0], x[1], g), 'left'), pi) 2*Y*E_2(X) TESTS:: @@ -2157,18 +2253,25 @@ def _element_constructor_(self, G, pi=None, check=True): ValueError: 1/2 must be an element of the base ring, a permutation group or a pair (X, a) specifying a group action of the symmetric group on pi=None + """ if parent(G) is self: # pi cannot be None because of framework raise ValueError("cannot reassign sorts to a polynomial species") if isinstance(G, tuple): - X, a = G + if len(G) == 2: + X, a = G + side = 'right' + else: + X, a, side = G + if side not in ['left', 'right']: + raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) - Hs = _stabilizer_subgroups(S, X, a) + Hs = _stabilizer_subgroups(S, X, a, side=side, check=check) return self.sum_of_terms((self._indices(H, pi, check=check), ZZ.one()) for H in Hs) diff --git a/src/sage/rings/tate_algebra_element.pxd b/src/sage/rings/tate_algebra_element.pxd index 3cafe330fb0..a1566f0e053 100644 --- a/src/sage/rings/tate_algebra_element.pxd +++ b/src/sage/rings/tate_algebra_element.pxd @@ -46,4 +46,3 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): cdef _quo_rem_c(self, list divisors, bint quo, bint rem, bint integral) cdef _quo_rem_check(self, divisors, bint quo, bint rem) cdef TateAlgebraElement _Spoly_c(self, TateAlgebraElement other) - diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 2deeb100ffc..80f2b7bf939 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -770,7 +770,7 @@ def reduce_tree(v, w): reduce_init=[]).run_serial() else: raise NotImplementedError(algorithm) - leafs = set([node.valuation for node in nodes]) + leafs = {node.valuation for node in nodes} for node in nodes: if node.parent is None: continue diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index 24e5f598624..d5f5dc8e5ec 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -1214,14 +1214,16 @@ def _test_mul(self, **options): sage: v = QQ.valuation(5) sage: v._test_mul() """ + from sage.rings.infinity import infinity + from itertools import product tester = self._tester(**options) S = self.domain().some_elements() - from itertools import product + infis = {infinity, -infinity} + for x, y in tester.some_elements(product(S, S)): - from sage.rings.infinity import infinity - if set([self(x), self(y)]) == set([infinity, -infinity]): + if {Sx := self(x), Sy := self(y)} == infis: continue - tester.assertEqual(self(x * y), self(x) + self(y)) + tester.assertEqual(self(x * y), Sx + Sy) def _test_no_infinite_units(self, **options): r""" diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index f3afd30c413..0ec0a087bac 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -439,7 +439,7 @@ def __classcall__(cls, generators): """ if generators in QQ: generators = [generators] - generators = list(set([QQ.coerce(g) for g in generators if g != 0])) + generators = list({QQ.coerce(g) for g in generators if g != 0}) generators.sort() simplified_generators = generators @@ -450,7 +450,7 @@ def __classcall__(cls, generators): if g == h: continue from sage.rings.semirings.non_negative_integer_semiring import NN - if h/g in NN: + if h / g in NN: simplified_generators.remove(h) break diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 6fb9720b945..6d685bcd6b7 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -318,7 +318,7 @@ # Copyright (C) 2011 David Perkinson # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from collections import Counter @@ -525,10 +525,10 @@ def __init__(self, g, sink=None): EXAMPLES: - Below, ``g`` represents a square with directed, multiple edges with three - vertices, ``a``, ``b``, ``c``, and ``d``. The vertex ``a`` has - outgoing edges to itself (weight 2), to vertex ``b`` (weight 1), and - vertex ``c`` (weight 3), for example. + Below, ``g`` represents a square with directed, multiple edges + with three vertices, ``a``, ``b``, ``c``, and ``d``. + The vertex ``a`` has outgoing edges to itself (weight 2), to + vertex ``b`` (weight 1), and vertex ``c`` (weight 3), for example. :: @@ -552,7 +552,9 @@ def __init__(self, g, sink=None): [-1 -2 3 0] [ 0 0 0 0] sage: s.dict() - {0: {1: 1, 2: 1, 3: 1}, 1: {0: 1, 1: 1, 2: 3}, 2: {0: 1, 1: 2, 2: 4}} + {0: {1: 1, 2: 1, 3: 1}, + 1: {0: 1, 1: 1, 2: 3}, + 2: {0: 1, 1: 2, 2: 4}} Sandpiles can be created from Graphs and DiGraphs. :: @@ -571,14 +573,16 @@ def __init__(self, g, sink=None): .. NOTE:: - Loops are allowed. There are four admissible input formats. Two of - these are dictionaries whose keys are the vertex names. In one, the - values are dictionaries with keys the names of vertices which are the - heads of outgoing edges and with values the weights of the edges. In - the other format, the values are lists of names of vertices which are - the heads of the outgoing edges, with weights determined by the number - of times a name of a vertex appears in the list. Both Graphs and - DiGraphs can also be used as inputs. + Loops are allowed. There are four admissible input + formats. Two of these are dictionaries whose keys are the + vertex names. In one, the values are dictionaries with + keys the names of vertices which are the heads of outgoing + edges and with values the weights of the edges. In the + other format, the values are lists of names of vertices + which are the heads of the outgoing edges, with weights + determined by the number of times a name of a vertex + appears in the list. Both Graphs and DiGraphs can also be + used as inputs. TESTS:: @@ -678,71 +682,71 @@ def __getattr__(self, name): if name == '_max_stable_div': self._set_max_stable_div() return deepcopy(self.__dict__[name]) - elif name == '_out_degrees': + if name == '_out_degrees': self._set_out_degrees() return deepcopy(self.__dict__[name]) - elif name == '_in_degrees': + if name == '_in_degrees': self._set_in_degrees() return deepcopy(self.__dict__[name]) - elif name == '_burning_config' or name == '_burning_script': + if name in ['_burning_config', '_burning_script']: self._set_burning_config() return deepcopy(self.__dict__[name]) - elif name == '_identity': + if name == '_identity': self._set_identity() return deepcopy(self.__dict__[name]) - elif name == '_recurrents': + if name == '_recurrents': self._set_recurrents() return deepcopy(self.__dict__[name]) - elif name == '_min_recurrents': + if name == '_min_recurrents': self._set_min_recurrents() return deepcopy(self.__dict__[name]) - elif name == '_superstables': + if name == '_superstables': self._set_superstables() return deepcopy(self.__dict__[name]) - elif name == '_group_gens': + if name == '_group_gens': self._set_group_gens() return deepcopy(self.__dict__[name]) elif name == '_group_order': self.__dict__[name] = det(self._reduced_laplacian.dense_matrix()) return self.__dict__[name] - elif name == '_invariant_factors': + if name == '_invariant_factors': self._set_invariant_factors() return deepcopy(self.__dict__[name]) - elif name == '_smith_form': + if name == '_smith_form': self._set_smith_form() return deepcopy(self.__dict__[name]) - elif name == '_jacobian_representatives': + if name == '_jacobian_representatives': self._set_jacobian_representatives() return deepcopy(self.__dict__[name]) - elif name == '_avalanche_polynomial': + if name == '_avalanche_polynomial': self._set_avalanche_polynomial() return deepcopy(self.__dict__[name]) - elif name == '_stationary_density': + if name == '_stationary_density': self._set_stationary_density() return self.__dict__[name] - elif name == '_betti_complexes': + if name == '_betti_complexes': self._set_betti_complexes() return deepcopy(self.__dict__[name]) elif name in ['_postulation', '_h_vector', '_hilbert_function']: self._set_hilbert_function() return deepcopy(self.__dict__[name]) - elif (name == '_ring' or name == '_unsaturated_ideal'): + if name in ['_ring', '_unsaturated_ideal']: self._set_ring() return self.__dict__[name] - elif name == '_ideal': + if name == '_ideal': self._set_ideal() return self.__dict__[name] - elif name in ['_resolution', '_betti', '_singular_resolution']: + if name in ['_resolution', '_betti', '_singular_resolution']: self._set_resolution() return self.__dict__[name] - elif name == '_groebner': + if name == '_groebner': self._set_groebner() return self.__dict__[name] - elif name == '_points': + if name == '_points': self._set_points() return self.__dict__[name] - else: - raise AttributeError(name) + + raise AttributeError(name) def __str__(self) -> str: r""" @@ -762,7 +766,7 @@ def __str__(self) -> str: """ return self.name() - def _repr_(self): + def _repr_(self) -> str: r""" String representation of ``self``. @@ -803,7 +807,8 @@ def show3d(self, **kwds): INPUT: - - ``kwds`` -- (optional) arguments passed to the show method for Graph or DiGraph + - ``kwds`` -- (optional) arguments passed to the show method + for Graph or DiGraph EXAMPLES:: @@ -856,7 +861,9 @@ def sink(self): def laplacian(self): r""" - The Laplacian matrix of the graph. Its *rows* encode the vertex firing rules. + The Laplacian matrix of the graph. + + Its *rows* encode the vertex firing rules. OUTPUT: matrix @@ -1125,12 +1132,12 @@ def burning_config(self): nonnegative entries and such that every vertex has a path from some vertex in its support. The corresponding *burning script* gives the integer-linear combination needed to obtain the burning - configuration. So if `b` is the burning configuration, `\sigma` is its - script, and `\tilde{L}` is the reduced Laplacian, then `\sigma\cdot - \tilde{L} = b`. The *minimal burning configuration* is the one - with the minimal script (its components are no larger than the - components of any other script - for a burning configuration). + configuration. So if `b` is the burning configuration, `\sigma` + is its script, and `\tilde{L}` is the reduced Laplacian, + then `\sigma\cdot \tilde{L} = b`. The *minimal burning + configuration* is the one with the minimal script (its + components are no larger than the components of any other + script for a burning configuration). The following are equivalent for a configuration `c` with burning configuration `b` having script `\sigma`: @@ -1266,7 +1273,9 @@ def _set_identity(self): def identity(self, verbose=True): r""" - The identity configuration. If ``verbose`` is ``False``, the + The identity configuration. + + If ``verbose`` is ``False``, the configuration is converted to a list of integers. INPUT: @@ -1339,7 +1348,9 @@ def recurrents(self, verbose=True): sage: r = Sandpile(graphs.HouseXGraph(),0).recurrents() sage: r[:3] - [{1: 2, 2: 3, 3: 3, 4: 1}, {1: 1, 2: 3, 3: 3, 4: 0}, {1: 1, 2: 3, 3: 3, 4: 1}] + [{1: 2, 2: 3, 3: 3, 4: 1}, + {1: 1, 2: 3, 3: 3, 4: 0}, + {1: 1, 2: 3, 3: 3, 4: 1}] sage: sandpiles.Complete(4).recurrents(False) # needs sage.combinat [[2, 2, 2], [2, 2, 1], @@ -1395,7 +1406,9 @@ def superstables(self, verbose=True): sage: sp = Sandpile(graphs.HouseXGraph(),0).superstables() sage: sp[:3] - [{1: 0, 2: 0, 3: 0, 4: 0}, {1: 1, 2: 0, 3: 0, 4: 1}, {1: 1, 2: 0, 3: 0, 4: 0}] + [{1: 0, 2: 0, 3: 0, 4: 0}, + {1: 1, 2: 0, 3: 0, 4: 1}, + {1: 1, 2: 0, 3: 0, 4: 0}] sage: sandpiles.Complete(4).superstables(False) # needs sage.combinat [[0, 0, 0], [0, 0, 1], @@ -1437,9 +1450,11 @@ def _set_group_gens(self): self._group_gens = [SandpileConfig(self, [Integer(j) for j in F.column(i)]).equivalent_recurrent() for i in range(F.nrows()) if D[i][i] != 1] - def group_gens(self, verbose=True): + def group_gens(self, verbose=True) -> list: r""" - A minimal list of generators for the sandpile group. If ``verbose`` is ``False`` + A minimal list of generators for the sandpile group. + + If ``verbose`` is ``False`` then the generators are represented as lists of integers. INPUT: @@ -1448,7 +1463,8 @@ def group_gens(self, verbose=True): OUTPUT: - list of SandpileConfig (or of lists of integers if ``verbose`` is ``False``) + list of SandpileConfig + (or of lists of integers if ``verbose`` is ``False``) EXAMPLES:: @@ -1683,7 +1699,7 @@ def avalanche_polynomial(self, multivariable=True): return self._avalanche_polynomial.subs({X[i]: X[0] for i in range(1, self.num_verts() - 1)}) - def nonspecial_divisors(self, verbose=True): + def nonspecial_divisors(self, verbose=True) -> list: r""" The nonspecial divisors. Only for undirected graphs. (See NOTE.) @@ -1708,11 +1724,12 @@ def nonspecial_divisors(self, verbose=True): .. NOTE:: - The "nonspecial divisors" are those divisors of degree `g-1` with - empty linear system. The term is only defined for undirected graphs. - Here, `g = |E| - |V| + 1` is the genus of the graph (not counting loops - as part of `|E|`). If ``verbose`` is ``False``, the divisors are converted - to lists of integers. + The "nonspecial divisors" are those divisors of degree + `g-1` with empty linear system. The term is only defined + for undirected graphs. Here, `g = |E| - |V| + 1` is the + genus of the graph (not counting loops as part of `|E|`). + If ``verbose`` is ``False``, the divisors are converted to + lists of integers. .. WARNING:: @@ -1750,7 +1767,8 @@ def canonical_divisor(self): The underlying graph must be undirected. """ if self.is_undirected(): - return SandpileDivisor(self, [self.laplacian()[i][i] - 2 for i in range(self.num_verts())]) + return SandpileDivisor(self, [self.laplacian()[i][i] - 2 + for i in range(self.num_verts())]) raise TypeError("only for undirected graphs") def _set_invariant_factors(self): @@ -1868,7 +1886,7 @@ def _set_smith_form(self): """ self._smith_form = self.laplacian().transpose().smith_form() - def smith_form(self): + def smith_form(self) -> list: r""" The Smith normal form for the Laplacian. In detail: a list of integer matrices `D, U, V` such that `ULV = D` where `L` is the transpose of the @@ -2000,7 +2018,7 @@ def jacobian_representatives(self, verbose=True): [{0: -5, 1: 3, 2: 2}, {0: -4, 1: 3, 2: 1}] Let `\tau` be the nonnegative generator of the kernel of the transpose of - the Laplacian, and let `tau_s` be it sink component, then the sandpile + the Laplacian, and let `\tau_s` be its sink component, then the sandpile group is isomorphic to the direct sum of the cyclic group of order `\tau_s` and the Jacobian group. In the example above, we have:: @@ -2011,8 +2029,8 @@ def jacobian_representatives(self, verbose=True): .. NOTE:: - The Jacobian group is the set of all divisors of degree zero modulo the - integer rowspan of the Laplacian matrix. + The Jacobian group is the set of all divisors of degree + zero modulo the integer rowspan of the Laplacian matrix. """ if verbose: return deepcopy(self._jacobian_representatives) @@ -2021,8 +2039,9 @@ def jacobian_representatives(self, verbose=True): def picard_representatives(self, d, verbose=True): r""" - Representatives of the divisor classes of degree `d` in the Picard group. (Also - see the documentation for ``jacobian_representatives``.) + Representatives of the divisor classes of degree `d` in the Picard group. + + (Also see the documentation for ``jacobian_representatives``.) INPUT: @@ -2051,10 +2070,12 @@ def picard_representatives(self, d, verbose=True): def stable_configs(self, smax=None): r""" - Generator for all stable configurations. If ``smax`` is provided, then - the generator gives all stable configurations less than or equal to - ``smax``. If ``smax`` does not represent a stable configuration, then each - component of ``smax`` is replaced by the corresponding component of the + Generator for all stable configurations. + + If ``smax`` is provided, then the generator gives all stable + configurations less than or equal to ``smax``. If ``smax`` + does not represent a stable configuration, then each component + of ``smax`` is replaced by the corresponding component of the maximal stable configuration. INPUT: @@ -2079,8 +2100,9 @@ def stable_configs(self, smax=None): smax = self.max_stable().values() else: c = SandpileConfig(self, smax) - if not c <= self.max_stable(): - smax = [min(c[v], self.max_stable()[v]) for v in self.nonsink_vertices()] + if c > self.max_stable(): + smax = [min(c[v], self.max_stable()[v]) + for v in self.nonsink_vertices()] else: smax = c.values() for c in IntegerVectorsIterator(smax): @@ -2145,20 +2167,25 @@ def markov_chain(self, state, distrib=None): .. NOTE:: - The ``closed sandpile Markov chain`` has state space consisting of the configurations - on a sandpile. It transitions from a state by choosing a vertex at random - (according to the probability distribution ``distrib``), dropping a grain of sand at - that vertex, and stabilizing. If the chosen vertex is the sink, the chain stays - at the current state. - - The ``open sandpile Markov chain`` has state space consisting of the recurrent elements, - i.e., the state space is the sandpile group. It transitions from the configuration `c` - by choosing a vertex `v` at random according to ``distrib``. The next state is the - stabilization of `c+v`. If `v` is the sink vertex, then the stabilization of `c+v` - is defined to be `c`. - - Note that in either case, if ``distrib`` is specified, its length is equal to - the total number of vertices (including the sink). + The ``closed sandpile Markov chain`` has state space + consisting of the configurations on a sandpile. It + transitions from a state by choosing a vertex at random + (according to the probability distribution ``distrib``), + dropping a grain of sand at that vertex, and stabilizing. + If the chosen vertex is the sink, the chain stays at the + current state. + + The ``open sandpile Markov chain`` has state space + consisting of the recurrent elements, i.e., the state + space is the sandpile group. It transitions from the + configuration `c` by choosing a vertex `v` at random + according to ``distrib``. The next state is the + stabilization of `c+v`. If `v` is the sink vertex, then + the stabilization of `c+v` is defined to be `c`. + + Note that in either case, if ``distrib`` is specified, its + length is equal to the total number of vertices (including + the sink). REFERENCES: @@ -2248,9 +2275,9 @@ def stationary_density(self): .. NOTE:: - The stationary density of a sandpile is the sum `\sum_c (\deg(c) + \deg(s))` - where `\deg(s)` is the degree of the sink and the sum is over all - recurrent configurations. + The stationary density of a sandpile is the sum `\sum_c + (\deg(c) + \deg(s))` where `\deg(s)` is the degree of the + sink and the sum is over all recurrent configurations. REFERENCES: @@ -2308,16 +2335,17 @@ def _set_betti_complexes(self): r = self.recurrents() for D in r: d = D.deg() - # change D to a dict since SandpileConfig will not allow adding a key - D = dict(D) - D[self.sink()] = -d - D = SandpileDivisor(self, D) + # change D to a dict since SandpileConfig will not allow + # adding a key + dD = dict(D) + dD[self.sink()] = -d + sD = SandpileDivisor(self, dD) test = True while test: - D[self.sink()] += 1 - complex = D.Dcomplex() + sD[self.sink()] += 1 + complex = sD.Dcomplex() if sum(complex.betti().values()) > 1: # change from 0 to 1 - results.append([deepcopy(D), complex]) + results.append([deepcopy(sD), complex]) if len(complex.maximal_faces()) == 1 and list(complex.maximal_faces()[0]) == verts: test = False self._betti_complexes = results @@ -2529,9 +2557,10 @@ def _set_resolution(self): def resolution(self, verbose=False): r""" - A minimal free resolution of the homogeneous toppling ideal. If - ``verbose`` is ``True``, then all of the mappings are returned. - Otherwise, the resolution is summarized. + A minimal free resolution of the homogeneous toppling ideal. + + If ``verbose`` is ``True``, then all of the mappings are + returned. Otherwise, the resolution is summarized. INPUT: @@ -2756,8 +2785,9 @@ def symmetric_recurrents(self, orbits): .. NOTE:: - The user is responsible for ensuring that the list of orbits comes from - a group of symmetries of the underlying graph. + The user is responsible for ensuring that the list of + orbits comes from a group of symmetries of the underlying + graph. """ sym_recurrents = [] active = [self._max_stable] @@ -2784,7 +2814,9 @@ class SandpileConfig(dict): @staticmethod def help(verbose=True): r""" - List of SandpileConfig methods. If ``verbose``, include short descriptions. + List of SandpileConfig methods. + + If ``verbose``, include short descriptions. INPUT: @@ -2920,8 +2952,9 @@ def __setitem__(self, key, item): .. NOTE:: - In the example, above, changing the value of ``c`` at some vertex makes - a call to setitem, which resets some of the stored variables for ``c``. + In the example, above, changing the value of ``c`` at some + vertex makes a call to setitem, which resets some of the + stored variables for ``c``. """ if key in self: dict.__setitem__(self, key, item) @@ -3086,7 +3119,8 @@ def __neg__(self): sage: -c {1: -1, 2: -2} """ - return SandpileConfig(self._sandpile, [-self[v] for v in self._vertices]) + return SandpileConfig(self._sandpile, + [-self[v] for v in self._vertices]) # recurrent addition or multiplication on the right by an integer def __mul__(self, other): @@ -3123,7 +3157,8 @@ def __mul__(self, other): if isinstance(other, SandpileConfig): return (self+other).equivalent_recurrent() if isinstance(other, Integer): - return SandpileConfig(self.sandpile(), [other*i for i in self.values()]) + return SandpileConfig(self.sandpile(), + [other*i for i in self.values()]) raise TypeError(other) def __rmul__(self, other): @@ -3149,7 +3184,7 @@ def __rmul__(self, other): """ return SandpileConfig(self.sandpile(), [other*i for i in self.values()]) - def __le__(self, other): + def __le__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at most that of ``other``. @@ -3179,7 +3214,7 @@ def __le__(self, other): """ return all(self[v] <= other[v] for v in self._vertices) - def __lt__(self, other): + def __lt__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at most that of ``other`` and the two configurations are not equal. @@ -3204,7 +3239,7 @@ def __lt__(self, other): """ return self <= other and self != other - def __ge__(self, other): + def __ge__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at least that of ``other``. @@ -3234,7 +3269,7 @@ def __ge__(self, other): """ return all(self[v] >= other[v] for v in self._vertices) - def __gt__(self, other): + def __gt__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at least that of ``other`` and the two configurations are not equal. @@ -3352,8 +3387,6 @@ def values(self): OUTPUT: list of integers - boolean - EXAMPLES:: sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') @@ -3444,7 +3477,7 @@ def fire_script(self, sigma): c[e[1]] += sigma[i]*e[2] return SandpileConfig(self._sandpile, c) - def unstable(self): + def unstable(self) -> list: r""" The unstable vertices. @@ -3457,8 +3490,8 @@ def unstable(self): sage: c.unstable() [2, 3] """ - return [v for v in self._vertices if - self[v] >= self._sandpile.out_degree(v)] + return [v for v in self._vertices + if self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -3576,13 +3609,17 @@ def support(self): def add_random(self, distrib=None): r""" - Add one grain of sand to a random vertex. Optionally, a probability - distribution, ``distrib``, may be placed on the vertices or the nonsink vertices. + Add one grain of sand to a random vertex. + + Optionally, a probability distribution, ``distrib``, may be + placed on the vertices or the nonsink vertices. + See NOTE for details. INPUT: - - ``distrib`` -- (optional) list of nonnegative numbers summing to 1 (representing a prob. dist.) + - ``distrib`` -- (optional) list of nonnegative numbers + summing to 1 (representing a prob. dist.) OUTPUT: SandpileConfig @@ -3998,7 +4035,7 @@ def show(self, sink=True, colors=True, heights=False, directed=None, **kwds): a[i] = str(i)+":"+str(self[i]) T.relabel(a) if colors: - vc = {} # vertex colors + vc: dict[str, list] = {} # vertex colors r = rainbow(max_height) # colors # noqa: F821 for i in range(max_height): vc[r[i]] = [] @@ -4305,7 +4342,7 @@ def __mul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(),[i*other for i in self.values()]) + return SandpileDivisor(self.sandpile(), [i*other for i in self.values()]) def __rmul__(self, other): r""" @@ -4328,7 +4365,7 @@ def __rmul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(),[other*i for i in self.values()]) + return SandpileDivisor(self.sandpile(), [other*i for i in self.values()]) def __radd__(self, other): r""" @@ -4604,7 +4641,7 @@ def fire_vertex(self, v): D[v] -= self._sandpile.out_degree(v) for e in self._sandpile.outgoing_edge_iterator(v): D[e[1]] += e[2] - return SandpileDivisor(self._sandpile,D) + return SandpileDivisor(self._sandpile, D) def fire_script(self, sigma): r""" @@ -4673,7 +4710,7 @@ def fire_unstable(self): D[v] -= self._sandpile.out_degree(v) for e in self._sandpile.outgoing_edge_iterator(v): D[e[1]] += e[2] - return SandpileDivisor(self._sandpile,D) + return SandpileDivisor(self._sandpile, D) def _set_q_reduced(self): r""" @@ -4688,11 +4725,11 @@ def _set_q_reduced(self): True """ S = self.sandpile() - c = SandpileConfig(S,[self[i] for i in S.nonsink_vertices()]) + c = SandpileConfig(S, [self[i] for i in S.nonsink_vertices()]) c = c.equivalent_superstable() - D = {v:c[v] for v in S.nonsink_vertices()} + D = {v: c[v] for v in S.nonsink_vertices()} D[S.sink()] = self.deg() - c.deg() - self._q_reduced = SandpileDivisor(S,D) + self._q_reduced = SandpileDivisor(S, D) def q_reduced(self, verbose=True): r""" @@ -4758,7 +4795,7 @@ def is_q_reduced(self): True """ S = self.sandpile() - c = SandpileConfig(S,[self[v] for v in S.nonsink_vertices()]) + c = SandpileConfig(S, [self[v] for v in S.nonsink_vertices()]) return c.is_superstable() def is_linearly_equivalent(self, D, with_firing_vector=False): @@ -4800,12 +4837,12 @@ def is_linearly_equivalent(self, D, with_firing_vector=False): """ # First try to convert D into a vector. v = vector(self.values()) - if isinstance(D,SandpileDivisor): + if isinstance(D, SandpileDivisor): w = vector(D.values()) else: w = vector(D) # Now test for linear equivalence and find firing vector - D,U,V = self.sandpile()._smith_form + D, U, V = self.sandpile()._smith_form b = v - w ub = U*b if ub[-1] != 0: @@ -4815,7 +4852,7 @@ def is_linearly_equivalent(self, D, with_firing_vector=False): return False else: try: - x = vector(ZZ,[ub[i]/D[i][i] for i in range(D.nrows()-1)]+[0]) + x = vector(ZZ, [ub[i]/D[i][i] for i in range(D.nrows()-1)]+[0]) if with_firing_vector: return V*x else: @@ -4903,7 +4940,7 @@ def _set_linear_system(self): mat_file.write(str(n)+' ') mat_file.write(str(n)+'\n') for r in L: - mat_file.write(''.join(map(str,r))) + mat_file.write(''.join(map(str, r))) mat_file.write('\n') # relations file with open(lin_sys_rel, 'w') as rel_file: @@ -4977,7 +5014,7 @@ def _set_polytope(self): """ S = self.sandpile() myL = S.laplacian().transpose().delete_columns([S._sink_ind]) - my_ieqs = [[self[v]] + list(-myL[i]) for i,v in enumerate(S.vertices(sort=True))] + my_ieqs = [[self[v]] + list(-myL[i]) for i, v in enumerate(S.vertices(sort=True))] self._polytope = Polyhedron(ieqs=my_ieqs) def polytope(self): @@ -5067,7 +5104,7 @@ def _set_effective_div(self): S = self.sandpile() myL = S.laplacian().transpose().delete_columns([S._sink_ind]) dv = vector(ZZ, self.values()) - self._effective_div = [SandpileDivisor(S,list(dv - myL*i)) + self._effective_div = [SandpileDivisor(S, list(dv - myL*i)) for i in self._polytope_integer_pts] def effective_div(self, verbose=True, with_firing_vectors=False): @@ -5193,14 +5230,14 @@ def _set_rank(self, set_witness=False): while k >= 0: rk += 1 try: - d = next(i for i,j in enumerate(c) if i == j and i != 0) + d = next(i for i, j in enumerate(c) if i == j and i != 0) except Exception: d = n - 1 k = k - d if k >= 0: c[0] = n - 1 - d - b1 = [c[i] + n - d for i in range(1,d)] - b2 = [c[i] - d for i in range(d,n-1)] + b1 = [c[i] + n - d for i in range(1, d)] + b2 = [c[i] - d for i in range(d, n-1)] c = b2 + [c[0]] + b1 self._rank = rk # All other cases. @@ -5319,10 +5356,10 @@ def _set_r_of_D(self, verbose=False): if w not in new_level: new_level.append(w) C = d - w - C = SandpileDivisor(self._sandpile,list(C)) + C = SandpileDivisor(self._sandpile, list(C)) eff = C.effective_div() if not eff: - self._r_of_D = (r, SandpileDivisor(self._sandpile,list(w))) + self._r_of_D = (r, SandpileDivisor(self._sandpile, list(w))) return level = new_level @@ -5355,7 +5392,7 @@ def weierstrass_rank_seq(self, v='sink'): verts = s.vertices(sort=True) Ei = s.zero_div() Ei[verts.index(v)] = 1 - Ei = SandpileDivisor(s,Ei) + Ei = SandpileDivisor(s, Ei) r = D.rank() seq = [r] while r != -1: @@ -5916,28 +5953,28 @@ def triangle_sandpile(n): sage: T.group_order() 135418115000 """ - T = {(-1, -1):{}} + T = {(-1, -1): {}} for i in range(n): for j in range(n-i): - T[(i,j)] = {} + T[(i, j)] = {} if i < n-j-1: - T[(i,j)][(i+1,j)] = 1 - T[(i,j)][(i,j+1)] = 1 + T[(i, j)][(i+1, j)] = 1 + T[(i, j)][(i, j+1)] = 1 if i > 0: - T[(i,j)][(i-1,j+1)] = 1 - T[(i,j)][(i-1,j)] = 1 + T[(i, j)][(i-1, j+1)] = 1 + T[(i, j)][(i-1, j)] = 1 if j > 0: - T[(i,j)][(i,j-1)] = 1 - T[(i,j)][(i+1,j-1)] = 1 - d = len(T[(i,j)]) + T[(i, j)][(i, j-1)] = 1 + T[(i, j)][(i+1, j-1)] = 1 + d = len(T[(i, j)]) if d < 6: - T[(i,j)][(-1, -1)] = 6-d + T[(i, j)][(-1, -1)] = 6-d T = Sandpile(T, (-1, -1)) pos = {} for x in T.nonsink_vertices(): coords = list(x) coords[0] += QQ(1)/2*coords[1] - pos[x] = coords + pos[x] = tuple(coords) pos[(-1, -1)] = (-1, -1) T.set_pos(pos) return T @@ -6206,7 +6243,7 @@ def admissible_partitions(S, k): yield p -def partition_sandpile(S, p): +def partition_sandpile(S, p) -> Sandpile: r""" Each set of vertices in `p` is regarded as a single vertex, with and edge between `A` and `B` if some element of `A` is connected by an edge to some @@ -6252,7 +6289,7 @@ def partition_sandpile(S, p): return Sandpile(g, i) -def min_cycles(G, v): +def min_cycles(G, v) -> list: r""" Minimal length cycles in the digraph `G` starting at vertex `v`. @@ -6271,9 +6308,8 @@ def min_cycles(G, v): sage: [min_cycles(T, i) for i in T.vertices(sort=True)] [[], [[1, 3]], [[2, 3, 1], [2, 3]], [[3, 1], [3, 2]]] """ - pr = G.neighbors_in(v) sp = G.shortest_paths(v) - return [sp[i] for i in pr if i in sp] + return [sp[i] for i in G.neighbor_in_iterator(v) if i in sp] def wilmes_algorithm(M): @@ -6289,6 +6325,7 @@ def wilmes_algorithm(M): EXAMPLES:: + sage: from sage.sandpiles.sandpile import wilmes_algorithm sage: P = matrix([[2,3,-7,-3],[5,2,-5,5],[8,2,5,4],[-5,-9,6,6]]) sage: wilmes_algorithm(P) [ 3279 -79 -1599 -1600] @@ -6303,13 +6340,12 @@ def wilmes_algorithm(M): # find the gcd of the row-sums, and perform the corresponding row # operations on M if M.matrix_over_field().is_invertible(): - L = deepcopy(M) - L = matrix(ZZ, L) + L = matrix(ZZ, M) U = matrix(ZZ, [sum(i) for i in L]).smith_form()[2].transpose() L = U*M for k in range(1, M.nrows()-1): - smith = matrix(ZZ, [i[k-1] for i in L[k:]]).smith_form()[2].transpose() - U = identity_matrix(ZZ, k).block_sum(smith) + sm = matrix(ZZ, [i[k-1] for i in L[k:]]).smith_form()[2].transpose() + U = identity_matrix(ZZ, k).block_sum(sm) L = U*L L[k] = -L[k] if L[-1][-2] > 0: diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index bad6b33d4d3..ab6567d37fb 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -303,7 +303,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): if S[0] is None: return None elif S[-1] is False: - return S[0:-1] + return S[0:-1] return S @@ -395,7 +395,7 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa try: lc = solver.learnt_clauses() except (AttributeError, NotImplementedError): - # solver does not support recovering learnt clauses + # solver does not support recovering learnt clauses lc = [] for c in lc: if len(c) <= max_learnt_length: diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index 27437c472ec..860a8a7e093 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -128,7 +128,7 @@ def __init__(self, solver, ring, max_vars_sparse=6, use_xor_clauses=None, cuttin self.cutting_number = cutting_number if use_xor_clauses is None: - use_xor_clauses = hasattr(solver,"add_xor_clause") + use_xor_clauses = hasattr(solver, "add_xor_clause") self.use_xor_clauses = use_xor_clauses self.ring = ring @@ -222,7 +222,7 @@ def choose(s): indices.append(nav.value()) nav = t else: - if self.random_generator.randint(0,1): + if self.random_generator.randint(0, 1): indices.append(nav.value()) nav = t @@ -337,11 +337,11 @@ def clauses_dense(self, f): for fpart, this_equal_zero in self.split_xor(f, equal_zero): ll = len(fpart) for p in self.permutations(ll, this_equal_zero): - self.solver.add_clause([ p[i]*fpart[i] for i in range(ll) ]) + self.solver.add_clause([p[i] * fpart[i] for i in range(ll)]) else: ll = len(f) for p in self.permutations(ll, equal_zero): - self.solver.add_clause([ p[i]*f[i] for i in range(ll) ]) + self.solver.add_clause([p[i] * f[i] for i in range(ll)]) @cached_method def monomial(self, m): @@ -387,19 +387,19 @@ def monomial(self, m): For correctness, this function is cached. """ if m.deg() == 1: - return m.index()+1 - else: - # we need to encode the relationship between the monomial - # and its variables - variables = [self.monomial(v) for v in m.variables()] - monomial = self.var(m) + return m.index() + 1 - # (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b - for v in variables: - self.solver.add_clause( (v, -monomial) ) - self.solver.add_clause( tuple([monomial] + [-v for v in variables]) ) + # we need to encode the relationship between the monomial + # and its variables + variables = [self.monomial(v) for v in m.variables()] + monomial = self.var(m) + + # (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b + for v in variables: + self.solver.add_clause((v, -monomial)) + self.solver.add_clause(tuple([monomial] + [-v for v in variables])) - return monomial + return monomial @cached_function def permutations(length, equal_zero): diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index fb8c10afd80..736aeebd05a 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -160,8 +160,8 @@ def __call__(self, assumptions=None): sage: solver() # optional - pycosat False """ - #import pycosat - #self._solve = pycosat.solve + # import pycosat + # self._solve = pycosat.solve sol = self._solve(self._clauses, verbose=self._verbosity, prop_limit=self._prop_limit, vars=self._nvars) # sol = pycosat.solve(self._clauses) diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index 5a027f6ae9b..05aa4812230 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -57,7 +57,7 @@ def var(self): nvars = n = self._LP.number_of_variables() while nvars == self._LP.number_of_variables(): n += 1 - self._vars[n] # creates the variable if needed + self._vars[n] # creates the variable if needed return n def nvars(self): @@ -143,7 +143,7 @@ def __call__(self): b = self._LP.get_values(self._vars, convert=bool, tolerance=self._integrality_tolerance) n = max(b) - return [None]+[b.get(i, False) for i in range(1,n+1)] + return [None] + [b.get(i, False) for i in range(1, n + 1)] def __repr__(self): """ diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 0729c5a98ad..d9a7321ade4 100755 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1805,7 +1805,6 @@ def fundamental_group(self): ....: + (x-18*z)*(z^2+11*x*z-x^2)^2) sage: G0 = C.fundamental_group() # needs sirocco sage: G.is_isomorphic(G0) # needs sirocco - #I Forcing finiteness test True sage: C = P.curve(z) sage: C.fundamental_group() # needs sirocco diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 4f694e0f252..9bed4936f7b 100755 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1364,7 +1364,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al From: Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31 To: Elliptic Curve defined by y^2 + x*y = x^3 + 2*x + 26 over Finite Field of size 31 - Multiple ways to set the `velu_sqrt_bound`:: + Multiple ways to set the ``velu_sqrt_bound``:: sage: E = EllipticCurve_from_j(GF(97)(42)) sage: P = E.gens()[0]*4 @@ -1427,7 +1427,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: phi.codomain()._order 170141183460469231746191640949390434666 - Check that ``'factored'`` recursively apply `velu_sqrt_bound`:: + Check that ``factored`` recursively apply ``velu_sqrt_bound``:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound sage: _velu_sqrt_bound.get() @@ -2141,7 +2141,7 @@ def isogenies_degree(self, n, *, _intermediate=False): """ def compute_key(phi): """ - Data used in ``hash(phi)`` excluding the expensive `.kernel_polynomial`. + Data used in ``hash(phi)`` excluding the expensive ``.kernel_polynomial``. """ return (phi.domain(), phi.codomain(), phi.degree(), phi.scaling_factor()) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 905cc63e149..34de89b7f12 100755 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -2810,18 +2810,8 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): try: endo = iso * E.isogeny(None, iso.domain(), degree=q) except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481 - #FIXME this code could be simplified/optimized after #37388 and/or #35949 - def _isogs(E, d): - if d.is_one(): - yield E.identity_morphism() - return - l = d.prime_factors()[-1] - for phi in E.isogenies_prime_degree(l): - for psi in _isogs(phi.codomain(), d//l): - yield psi * phi - endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E)) -# endos = (iso*phi for phi in E.isogenies_degree(q) -# for iso in phi.codomain().isomorphisms(E)) + endos = (iso*phi for phi in E.isogenies_degree(q) + for iso in phi.codomain().isomorphisms(E)) endo = next(endo for endo in endos if endo.trace().is_zero()) endo._degree = ZZ(q) @@ -2942,6 +2932,7 @@ def find_q(m, m4_fac, D): seen.add(Et) yield Et + def EllipticCurve_with_prime_order(N): r""" Given a prime number ``N``, find another prime number `p` and construct an diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 2f2868d37ca..134531ad1a5 100755 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -808,16 +808,28 @@ def two_descent(self, verbose=True, - ``selmer_only`` -- boolean (default: ``False``); selmer_only switch - - ``first_limit`` -- (default: 20) firstlim is bound - on x+z second_limit- (default: 8) secondlim is bound on log max - x,z , i.e. logarithmic - - - ``n_aux`` -- (default: -1) n_aux only relevant for - general 2-descent when 2-torsion trivial; n_aux=-1 causes default - to be used (depends on method) - - - ``second_descent`` -- (default: ``True``) - second_descent only relevant for descent via 2-isogeny + - ``first_limit`` -- integer (default: 20); naive height bound on + first point search on quartic homogeneous spaces (before + testing local solubility; very simple search with no + overheads). + + - ``second_limit`` -- integer (default: 8); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search) + + - ``n_aux`` -- integer (default: -1); if positive, the number of + auxiliary primes used in sieve-assisted search for quartics. + If -1 (the default) use a default value (set in the eclib + code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). + Only relevant for curves with no 2-torsion, where full + 2-descent is carried out. Worth increasing for curves + expected to be of rank > 6 to one or two more than the + expected rank. + + - ``second_descent`` -- boolean (default: ``True``); flag specifying + whether or not a second descent will be carried out. Only relevant + for curves with 2-torsion. Recommended left as the default except for + experts interested in details of Selmer groups. OUTPUT: @@ -2256,9 +2268,9 @@ def gens(self, proof=None, **kwds): - ``algorithm`` -- one of the following: - - ``'mwrank_shell'`` -- default; call mwrank shell command + - ``'mwrank_lib'`` -- default; call mwrank C library - - ``'mwrank_lib'`` -- call mwrank C library + - ``'mwrank_shell'`` -- call mwrank shell command - ``'pari'`` -- use ellrank in pari @@ -2268,7 +2280,11 @@ def gens(self, proof=None, **kwds): - ``use_database`` -- boolean (default: ``True``); if ``True``, attempts to find curve and gens in the (optional) database - - ``descent_second_limit`` -- (default: 12) used in 2-descent + - ``descent_second_limit`` -- (default: 12); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search). Used in 2-descent. + See also ``second_limit`` + in :meth:`~sage.libs.eclib.interface.mwrank_EllipticCurve.two_descent` - ``sat_bound`` -- (default: 1000) bound on primes used in saturation. If the computed bound on the index of the diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py index efc2a805bc0..c83c1a0997c 100755 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py @@ -185,7 +185,7 @@ def _have_established_geometrically_trivial(self): trivial. This is related to the warning at the top of the - `jacobian_endomorphism_utils.py` module. + ``jacobian_endomorphism_utils.py`` module. INPUT: @@ -214,7 +214,7 @@ def _have_established_geometrically_field(self): trivial. This is related to the warning at the top of the - `jacobian_endomorphism_utils.py` module. + ``jacobian_endomorphism_utils.py`` module. INPUT: diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index c2cce67037f..b991094924b 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -556,8 +556,8 @@ cdef class DisjointSet_of_integers(DisjointSet_class): Add a new element into a new set containing only the new element. According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` the - `make_set` operation adds a new element into a new set containing only - the new element. The new set is added at the end of `self`. + ``make_set`` operation adds a new element into a new set containing only + the new element. The new set is added at the end of ``self``. EXAMPLES:: sage: d = DisjointSet(5) @@ -874,8 +874,8 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): Add a new element into a new set containing only the new element. According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` - the `make_set` operation adds a new element into a new set containing - only the new element. The new set is added at the end of `self`. + the ``make_set`` operation adds a new element into a new set containing + only the new element. The new set is added at the end of ``self``. INPUT: diff --git a/src/sage/sets/family.pyx b/src/sage/sets/family.pyx index f87768f3989..0ccc4606ded 100644 --- a/src/sage/sets/family.pyx +++ b/src/sage/sets/family.pyx @@ -337,7 +337,10 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa sage: f = Family(list(range(1,27)), lambda i: chr(i+96)) sage: f - Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'} + Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', + 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', + 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', + 24: 'x', 25: 'y', 26: 'z'} sage: f[2] 'b' diff --git a/src/sage/sets/finite_set_map_cy.pyx b/src/sage/sets/finite_set_map_cy.pyx index f41450d5842..73dbdfdd934 100644 --- a/src/sage/sets/finite_set_map_cy.pyx +++ b/src/sage/sets/finite_set_map_cy.pyx @@ -621,11 +621,10 @@ cdef class FiniteSetEndoMap_N(FiniteSetMap_MN): sage: F([1, 0, 2]) * F([2, 1, 0]) [1, 2, 0] """ - assert(self._parent is other._parent), "Parent mismatch" + assert (self._parent is other._parent), "Parent mismatch" if self._parent._action == "right": return self._compose_internal_(other, self._parent) - else: - return other._compose_internal_(self, self._parent) + return other._compose_internal_(self, self._parent) def __pow__(self, n, dummy): """ @@ -679,11 +678,10 @@ cdef class FiniteSetEndoMap_Set(FiniteSetMap_Set): sage: g * f map: a -> c, b -> c, c -> c """ - assert(self._parent is other._parent), "Parent mismatch" + assert (self._parent is other._parent), "Parent mismatch" if self._parent._action == "right": return self._compose_internal_(other, self._parent) - else: - return other._compose_internal_(self, self._parent) + return other._compose_internal_(self, self._parent) def __pow__(self, n, dummy): """ diff --git a/src/sage/sets/pythonclass.pyx b/src/sage/sets/pythonclass.pyx index 02f34931b64..8aab718a39c 100644 --- a/src/sage/sets/pythonclass.pyx +++ b/src/sage/sets/pythonclass.pyx @@ -3,15 +3,15 @@ Set of all objects of a given Python class """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport rich_to_bool diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index 3d9d4a00f75..b20fa8cbe8a 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -286,8 +286,9 @@ from collections import deque def RecursivelyEnumeratedSet(seeds, successors, structure=None, - enumeration=None, max_depth=float("inf"), post_process=None, - facade=None, category=None): + enumeration=None, max_depth=float("inf"), + post_process=None, + facade=None, category=None): r""" Return a recursively enumerated set. @@ -470,7 +471,7 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): A recursively enumerated set (breadth first search) """ assert enumeration in ['naive', 'depth', 'breadth'], \ - "unknown enumeration(={})".format(enumeration) + "unknown enumeration(={})".format(enumeration) self._seeds = seeds self.successors = successors @@ -480,7 +481,8 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): if post_process is not None: self.post_process = post_process self._graded_component = None - Parent.__init__(self, facade=facade, category=EnumeratedSets().or_subcategory(category)) + Parent.__init__(self, facade=facade, + category=EnumeratedSets().or_subcategory(category)) def __reduce__(self): r""" @@ -1532,10 +1534,7 @@ def search_forest_iterator(roots, children, algorithm='depth'): # (you ask the children for the last node you met). Setting # position on 0 results in a breadth search (enumerate all the # descendants of a node before going on to the next father) - if algorithm == 'depth': - position = -1 - else: - position = 0 + position = -1 if algorithm == 'depth' else 0 # Invariant: # - for breadth first search: stack[i] contains an iterator over the nodes @@ -1555,7 +1554,7 @@ def search_forest_iterator(roots, children, algorithm='depth'): continue yield node - stack.append( iter(children(node)) ) + stack.append(iter(children(node))) class RecursivelyEnumeratedSet_forest(Parent): @@ -1742,8 +1741,8 @@ class RecursivelyEnumeratedSet_forest(Parent): sage: loads(dumps(S)) An enumerated set with a forest structure """ - def __init__(self, roots = None, children = None, post_process = None, - algorithm = 'depth', facade = None, category=None): + def __init__(self, roots=None, children=None, post_process=None, + algorithm='depth', facade=None, category=None): r""" TESTS:: @@ -1759,7 +1758,8 @@ class RecursivelyEnumeratedSet_forest(Parent): if post_process is not None: self.post_process = post_process self._algorithm = algorithm - Parent.__init__(self, facade = facade, category = EnumeratedSets().or_subcategory(category)) + Parent.__init__(self, facade=facade, + category=EnumeratedSets().or_subcategory(category)) __len__ = None @@ -1833,7 +1833,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ iter = search_forest_iterator(self.roots(), self.children, - algorithm = self._algorithm) + algorithm=self._algorithm) if hasattr(self, "post_process"): iter = _imap_and_filter_none(self.post_process, iter) return iter @@ -2016,7 +2016,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ stack = [iter(self.roots())] while stack: - position = randint(0,len(stack)-1) + position = randint(0, len(stack) - 1) try: node = next(stack[position]) except StopIteration: @@ -2025,12 +2025,12 @@ class RecursivelyEnumeratedSet_forest(Parent): if node == elt: return True - stack.append( iter(self.children(node)) ) + stack.append(iter(self.children(node))) return False - def map_reduce(self, map_function = None, - reduce_function = None, - reduce_init = None): + def map_reduce(self, map_function=None, + reduce_function=None, + reduce_init=None): r""" Apply a Map/Reduce algorithm on ``self``. @@ -2084,7 +2084,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ import sage.parallel.map_reduce return sage.parallel.map_reduce.RESetMapReduce( - forest = self, - map_function = map_function, - reduce_function = reduce_function, - reduce_init = reduce_init).run() + forest=self, + map_function=map_function, + reduce_function=reduce_function, + reduce_init=reduce_init).run() diff --git a/src/sage/stats/distributions/catalog.py b/src/sage/stats/distributions/catalog.py index f03bdd97ae3..8ae97fb24c4 100644 --- a/src/sage/stats/distributions/catalog.py +++ b/src/sage/stats/distributions/catalog.py @@ -17,14 +17,14 @@ sage: from sage.stats.distributions.catalog import * """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2024 Gareth Ma # # Distributed under the terms of the GNU General Public License (GPL), # version 2 or later (at your preference). # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_import import lazy_import lazy_import("sage.stats.distributions.discrete_gaussian_integer", ["DiscreteGaussianDistributionIntegerSampler"]) diff --git a/src/sage/stats/hmm/hmm.pxd b/src/sage/stats/hmm/hmm.pxd index 1abcb95392b..e1a2fa8590e 100644 --- a/src/sage/stats/hmm/hmm.pxd +++ b/src/sage/stats/hmm/hmm.pxd @@ -14,4 +14,3 @@ cdef class HiddenMarkovModel: cdef TimeSeries A, pi cdef TimeSeries _baum_welch_gamma(self, TimeSeries alpha, TimeSeries beta) - diff --git a/src/sage/stats/hmm/util.pxd b/src/sage/stats/hmm/util.pxd index b0d399d9aaf..4be9fbd77d5 100644 --- a/src/sage/stats/hmm/util.pxd +++ b/src/sage/stats/hmm/util.pxd @@ -4,4 +4,3 @@ cdef class HMM_Util: cpdef normalize_probability_TimeSeries(self, TimeSeries T, Py_ssize_t i, Py_ssize_t j) cpdef TimeSeries initial_probs_to_TimeSeries(self, pi, bint normalize) cpdef TimeSeries state_matrix_to_TimeSeries(self, A, int N, bint normalize) - diff --git a/src/sage/structure/__init__.py b/src/sage/structure/__init__.py index 2534e5a71f8..bf977ccc379 100644 --- a/src/sage/structure/__init__.py +++ b/src/sage/structure/__init__.py @@ -1,3 +1,3 @@ # sage_setup: distribution = sagemath-objects # Resolve a cyclic import -import sage.structure.element \ No newline at end of file +import sage.structure.element diff --git a/src/sage/structure/all.py b/src/sage/structure/all.py index 40b9daa67e8..785acc174e3 100644 --- a/src/sage/structure/all.py +++ b/src/sage/structure/all.py @@ -21,10 +21,10 @@ from sage.structure.proof import all as proof -from sage.misc.lazy_import import lazy_import -lazy_import('sage.structure.formal_sum', ['FormalSums', 'FormalSum']) -del lazy_import - from sage.structure.mutability import Mutability from sage.structure.element_wrapper import ElementWrapper + +from sage.misc.lazy_import import lazy_import +lazy_import('sage.structure.formal_sum', ['FormalSums', 'FormalSum']) +del lazy_import diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index cc2f1124cb4..6861cfb5be3 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1891,7 +1891,7 @@ cdef class CoercionModel: 1/2*x sage: cm.discover_action(F, ZZ, operator.truediv) Right inverse action by Rational Field on - Free Algebra on 1 generators (x,) over Rational Field + Free Algebra on 1 generator (x,) over Rational Field with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 14cae09d6f0..4860b4efabd 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -4661,7 +4661,7 @@ def coerce_binop(method): EXAMPLES: - Sparse polynomial rings uses `@coerce_binop` on `gcd`:: + Sparse polynomial rings uses ``@coerce_binop`` on ``gcd``:: sage: S. = PolynomialRing(ZZ, sparse=True) sage: f = x^2 @@ -4695,7 +4695,7 @@ def coerce_binop(method): sage: h.gcd(f, 'modular') 1 - We demonstrate a small class using `@coerce_binop` on a method:: + We demonstrate a small class using ``@coerce_binop`` on a method:: sage: from sage.structure.element import coerce_binop sage: class MyRational(Rational): diff --git a/src/sage/structure/element_wrapper.pxd b/src/sage/structure/element_wrapper.pxd index dda6630c84d..158d5687a8a 100644 --- a/src/sage/structure/element_wrapper.pxd +++ b/src/sage/structure/element_wrapper.pxd @@ -10,4 +10,3 @@ cdef class ElementWrapper(Element): cdef class ElementWrapperCheckWrappedClass(ElementWrapper): pass - diff --git a/src/sage/structure/formal_sum.py b/src/sage/structure/formal_sum.py index ab72ff5eb2d..662e3b33240 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -65,11 +65,11 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.misc.repr import repr_lincomb import operator from collections import OrderedDict +from sage.misc.persist import register_unpickle_override +from sage.misc.repr import repr_lincomb from sage.modules.module import Module from sage.structure.element import ModuleElement from sage.structure.richcmp import richcmp @@ -392,11 +392,14 @@ def _element_constructor_(self, x, check=True, reduce=True): else: x = x._data if isinstance(x, list): - return self.element_class(x, check=check,reduce=reduce,parent=self) + return self.element_class(x, check=check, + reduce=reduce, parent=self) if x == 0: - return self.element_class([], check=False, reduce=False, parent=self) + return self.element_class([], check=False, + reduce=False, parent=self) else: - return self.element_class([(self.base_ring()(1), x)], check=False, reduce=False, parent=self) + return self.element_class([(self.base_ring()(1), x)], + check=False, reduce=False, parent=self) def _coerce_map_from_(self, X): r""" @@ -413,7 +416,7 @@ def _coerce_map_from_(self, X): From: Abelian Group of all Formal Finite Sums over Integer Ring To: Abelian Group of all Formal Finite Sums over Rational Field """ - if isinstance(X,FormalSums): + if isinstance(X, FormalSums): if self.base_ring().has_coerce_map_from(X.base_ring()): return True return False @@ -475,7 +478,7 @@ def _an_element_(self, check=False, reduce=False): 1/2 """ return self.element_class([(self.base_ring().an_element(), 1)], - check=check, reduce=reduce, parent=self) + check=check, reduce=reduce, parent=self) formal_sums = FormalSums() @@ -483,5 +486,4 @@ def _an_element_(self, check=False, reduce=False): # Formal sums now derives from UniqueRepresentation, which makes the # factory function unnecessary. This is why the name was changed from # class FormalSums_generic to class FormalSums. -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.structure.formal_sum', 'FormalSums_generic', FormalSums) diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index 6d3fcae2520..99d881ae2cd 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -3,7 +3,7 @@ Pure python code for abstract base class for objects with generators """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -15,8 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** def multiplicative_iterator(M): diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index 0f3308cc80f..cbf08174532 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -1296,7 +1296,7 @@ def __setstate__(self, state): the :class:`GlobalOptions` class. The :meth:`__getstate__` method returns a dictionary with an - `options_class` key which identifies the "parent" class for the options. + ``options_class`` key which identifies the "parent" class for the options. This is then used to unpickle the options class. EXAMPLES:: diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index 7586eb06aaf..259398761bc 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -316,7 +316,7 @@ def _parse_names(self, m, use_latex): return names[m] except KeyError: return None - else: # treat it like a list + else: # treat it like a list try: i = self._indices.rank(m) except (AttributeError, TypeError, KeyError, ValueError): @@ -458,7 +458,7 @@ def _repr_generator(self, m): return self.prefix() + left + (', '.join(repr(val) for val in m)) + right if not quotes and isinstance(m, str): return self.prefix() + left + m + right - return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m + return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m def _ascii_art_generator(self, m): r""" diff --git a/src/sage/structure/list_clone_timings.py b/src/sage/structure/list_clone_timings.py index a072b7287a5..500167b1157 100644 --- a/src/sage/structure/list_clone_timings.py +++ b/src/sage/structure/list_clone_timings.py @@ -73,12 +73,12 @@ cy_add1_mutable(e) : 625 loops, best of 3: 14.1 µs per loop cy_add1_with(e) : 625 loops, best of 3: 17.5 µs per loop """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009-2010 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.list_clone import ClonableArray from sage.structure.list_clone_demo import IncreasingArrays @@ -116,7 +116,7 @@ def check(self): ##################################################################### -###### Timings functions ###### +# Timings functions # ##################################################################### def add1_internal(bla): """ diff --git a/src/sage/structure/proof/all.py b/src/sage/structure/proof/all.py index 0db573b93ce..271109fb2e2 100644 --- a/src/sage/structure/proof/all.py +++ b/src/sage/structure/proof/all.py @@ -1,4 +1,5 @@ # sage_setup: distribution = sagemath-objects +from sage.structure.proof.proof import WithProof def arithmetic(t=None): @@ -240,6 +241,3 @@ def all(t=None): return _proof_prefs._require_proof.copy() for s in _proof_prefs._require_proof: _proof_prefs._require_proof[s] = bool(t) - - -from sage.structure.proof.proof import WithProof diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index c8c2df4cafe..b6b7d8b0509 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -225,7 +225,8 @@ def get_flag(t=None, subsystem=None): False """ if t is None: - if subsystem in ["arithmetic", "elliptic_curve", "linear_algebra", "number_field","polynomial"]: + if subsystem in ["arithmetic", "elliptic_curve", + "linear_algebra", "number_field", "polynomial"]: return _proof_prefs._require_proof[subsystem] else: return _proof_prefs._require_proof["other"] diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index cc9fcedadfe..6f1ee1dc02f 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -70,7 +70,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - +from sage.misc.persist import register_unpickle_override import sage.structure.sage_object import sage.structure.coerce @@ -239,7 +239,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non # start the pairwise coercion for i in range(len(x) - 1): try: - x[i], x[i+1] = sage.structure.element.canonical_coercion(x[i],x[i+1]) + x[i], x[i+1] = sage.structure.element.canonical_coercion(x[i], x[i+1]) except TypeError: from sage.categories.objects import Objects universe = Objects() @@ -257,7 +257,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non except ImportError: pass else: - if isinstance(universe, MPolynomialRing_base) or isinstance(universe, BooleanMonomialMonoid) or (isinstance(universe, QuotientRing_nc) and isinstance(universe.cover_ring(), MPolynomialRing_base)): + if isinstance(universe, (MPolynomialRing_base, BooleanMonomialMonoid)) or (isinstance(universe, QuotientRing_nc) and isinstance(universe.cover_ring(), MPolynomialRing_base)): return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) @@ -515,16 +515,16 @@ def __getitem__(self, n): check=False, immutable=False, cr=self.__cr) - else: - return list.__getitem__(self,n) + + return list.__getitem__(self, n) # We have to define the *slice functions as long as Sage uses Python 2.* # otherwise the inherited *slice functions from list are called def __getslice__(self, i, j): - return self.__getitem__(slice(i,j)) + return self.__getitem__(slice(i, j)) def __setslice__(self, i, j, value): - return self.__setitem__(slice(i,j), value) + return self.__setitem__(slice(i, j), value) def append(self, x): """ @@ -863,26 +863,25 @@ def __getattr__(self, name): sage: hash(S) 34 """ - if name == "_Sequence_generic__cr" and hasattr(self,"_Sequence__cr"): + if name == "_Sequence_generic__cr" and hasattr(self, "_Sequence__cr"): self.__cr = self._Sequence__cr return self.__cr - elif name == "_Sequence_generic__cr_str" and hasattr(self,"_Sequence__cr_str"): + if name == "_Sequence_generic__cr_str" and hasattr(self, "_Sequence__cr_str"): self.__cr_str = self._Sequence__cr_str return self.__cr_str - elif name == "_Sequence_generic__immutable" and hasattr(self,"_Sequence__immutable"): + if name == "_Sequence_generic__immutable" and hasattr(self, "_Sequence__immutable"): self.__immutable = self._Sequence__immutable return self.__immutable - elif name == "_Sequence_generic__universe" and hasattr(self,"_Sequence__universe"): + if name == "_Sequence_generic__universe" and hasattr(self, "_Sequence__universe"): self.__universe = self._Sequence__universe return self.__universe - elif name == "_Sequence_generic__hash" and hasattr(self,"_Sequence__hash"): + if name == "_Sequence_generic__hash" and hasattr(self, "_Sequence__hash"): self.__hash = self._Sequence__hash return self.__hash - else: - raise AttributeError("'Sequence_generic' object has no attribute '%s'" % name) + + raise AttributeError("'Sequence_generic' object has no attribute '%s'" % name) seq = Sequence -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.structure.sequence', 'Sequence', Sequence_generic) diff --git a/src/sage/structure/set_factories.py b/src/sage/structure/set_factories.py index c65a31089e8..ca46a413d7a 100644 --- a/src/sage/structure/set_factories.py +++ b/src/sage/structure/set_factories.py @@ -306,12 +306,12 @@ - Florent Hivert (2011-2012): initial revision """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject @@ -846,7 +846,8 @@ def element_constructor_attributes(self, constraints): sage: pol.element_constructor_attributes(()) {'_element_constructor_': <... 'tuple'>, '_parent_for': None} """ - return {'_element_constructor_' : self._constructor, '_parent_for' : None} + return {'_element_constructor_': self._constructor, + '_parent_for': None} def _repr_(self): r""" @@ -1107,7 +1108,7 @@ def __contains__(self, x): False """ if (isinstance(x, self.element_class) and - x.parent() == self._parent_for): # TODO: is_parent_of ??? + x.parent() == self._parent_for): # TODO: is_parent_of ??? try: self.check_element(x, True) except ValueError: @@ -1140,7 +1141,7 @@ def __call__(self, *args, **keywords): # Ensure idempotence of element construction if (len(args) == 1 and isinstance(args[0], self.element_class) and - args[0].parent() == self._parent_for): + args[0].parent() == self._parent_for): check = keywords.get("check", True) if check: self.check_element(args[0], check) diff --git a/src/sage/structure/set_factories_example.py b/src/sage/structure/set_factories_example.py index df4db63ef89..ba7d0f782e4 100644 --- a/src/sage/structure/set_factories_example.py +++ b/src/sage/structure/set_factories_example.py @@ -25,12 +25,12 @@ S_a^b := \{(x,y) \in S \mid x = a, y = b\}. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper @@ -99,8 +99,8 @@ def __call__(self, x=None, y=None, policy=None): if isinstance(y, (Integer, int)): return SingletonPair(x, y, policy) return PairsX_(x, policy) - elif isinstance(y, (Integer, int)): - return Pairs_Y(y, policy) + if isinstance(y, (Integer, int)): + return Pairs_Y(y, policy) return AllPairs(policy) def add_constraints(self, cons, args_opts): diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index 707feb0d409..216c0d6d3d9 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -3,7 +3,7 @@ Test of the :mod:`~sage.structure.factory` module """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Robert Bradshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -15,8 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.structure.factory import UniqueFactory diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 5f647228564..1390c524300 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -214,70 +214,31 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): return result -def giac_integrator(expression, v, a=None, b=None): - r""" - Integration using Giac. - - EXAMPLES:: - - sage: from sage.symbolic.integration.external import giac_integrator - sage: giac_integrator(sin(x), x) - -cos(x) - sage: giac_integrator(1/(x^2+6), x, -oo, oo) - 1/6*sqrt(6)*pi - - TESTS:: - - sage: giac_integrator(e^(-x^2)*log(x), x) - integrate(e^(-x^2)*log(x), x) - - Check that :issue:`30133` is fixed:: - - sage: ee = SR.var('e') - sage: giac_integrator(ee^x, x) - e^x/log(e) - sage: y = SR.var('π') - sage: giac_integrator(cos(y), y) - sin(π) - - Check that :issue:`29966` is fixed:: - - sage: giac_integrator(sqrt(x + sqrt(x)), x) - 1/12*(2*sqrt(x)*(4*sqrt(x) + 1) - 3)*sqrt(x + sqrt(x))... - """ - ex = expression._giac_() - if a is None: - result = ex.integrate(v._giac_()) - else: - result = ex.integrate(v._giac_(), a._giac_(), b._giac_()) - if 'integrate' in format(result) or 'integration' in format(result): - return expression.integrate(v, a, b, hold=True) - return result._sage_() - - def libgiac_integrator(expression, v, a=None, b=None): r""" Integration using libgiac. EXAMPLES:: + sage: # needs sage.libs.giac sage: import sage.libs.giac ... sage: from sage.symbolic.integration.external import libgiac_integrator sage: libgiac_integrator(sin(x), x) -cos(x) sage: libgiac_integrator(1/(x^2+6), x, -oo, oo) - No checks were made for singular points of antiderivative... 1/6*sqrt(6)*pi TESTS:: + sage: # needs sage.libs.giac sage: libgiac_integrator(e^(-x^2)*log(x), x) integrate(e^(-x^2)*log(x), x) The following integral fails with the Giac Pexpect interface, but works with libgiac (:issue:`31873`):: + sage: # needs sage.libs.giac sage: a, x = var('a,x') sage: f = sec(2*a*x) sage: F = libgiac_integrator(f, x) @@ -295,10 +256,9 @@ def libgiac_integrator(expression, v, a=None, b=None): return expression.integrate(v, a, b, hold=True) from sage.libs.giac.giac import Pygen - # We call Pygen on first argument because otherwise some expressions - # involving derivatives result in doctest failures in interfaces/sympy.py - # -- related to the fixme note in sage.libs.giac.giac.GiacFunction.__call__ - # regarding conversion of lists. + # We call Pygen on first argument because otherwise some + # expressions involving derivatives result in doctest failures in + # sage/interfaces/sympy.py if a is None: result = libgiac.integrate(Pygen(expression), v) else: diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 0877d132030..4a70d373516 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -28,7 +28,7 @@ available_integrators['sympy'] = external.sympy_integrator available_integrators['mathematica_free'] = external.mma_free_integrator available_integrators['fricas'] = external.fricas_integrator -available_integrators['giac'] = external.giac_integrator +available_integrators['giac'] = external.libgiac_integrator available_integrators['libgiac'] = external.libgiac_integrator ###################################################### @@ -59,9 +59,10 @@ def __init__(self): Check for :issue:`28913`:: + sage: # needs sage.libs.giac sage: Ex = (1-2*x^(1/3))^(3/4)/x sage: integrate(Ex, x, algorithm='giac') # long time - 4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log((-2*x^(1/3) + 1)^(1/4) + 1) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1)) + 4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log(abs((-2*x^(1/3) + 1)^(1/4) + 1)) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1)) Check for :issue:`29833`:: @@ -207,10 +208,13 @@ def __init__(self): Check for :issue:`32354`:: + sage: # needs sage.libs.giac sage: ex = 1/max_symbolic(x, 1)**2 sage: integral(ex, x, 0, 2, algorithm='giac') 3/2 - sage: integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac') + sage: result = integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac') + ... + sage: result 2 """ # The automatic evaluation routine will try these integrators @@ -474,9 +478,9 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): - ``'fricas'`` -- use FriCAS (the optional fricas spkg has to be installed) - - ``'giac'`` -- use Giac + - ``'giac'`` -- use libgiac - - ``'libgiac'`` -- use libgiac + - ``'libgiac'`` -- use libgiac (alias for ``'giac'``) To prevent automatic evaluation, use the ``hold`` argument. @@ -695,9 +699,15 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: integrate(f(x), x, 1, 2, algorithm='sympy') # needs sympy -1/2*pi + arctan(8) + arctan(5) + arctan(2) + arctan(1/2) - Using Giac to integrate the absolute value of a trigonometric expression:: + Using Giac to integrate the absolute value of a trigonometric + expression. If Giac is installed, this will be attempted + automatically in the event that Maxima is unable to integrate the + expression:: - sage: integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac') + sage: # needs sage.libs.giac + sage: result = integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac') + ... + sage: result 4 sage: result = integrate(abs(cos(x)), x, 0, 2*pi) ... diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 967ff18d020..fcd084cea81 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -40,7 +40,6 @@ from sage.arith.functions import lcm from sage.cpython.string cimport str_to_bytes, char_to_str from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.all cimport * -from sage.libs.gsl.types cimport * from sage.libs.gsl.complex cimport * from sage.libs.gsl.gamma cimport gsl_sf_lngamma_complex_e from sage.libs.mpmath import utils as mpmath_utils diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 9a4e44f0f12..9b8aeb7eeb5 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1302,7 +1302,7 @@ def __init__( self._dual_exterior_powers = {} # Set of all modules (tensor powers, exterior powers) # that depend on self's bases: - self._all_modules = set([self]) + self._all_modules = {self} # List of known bases on the free module: self._known_bases = [] self._def_basis = None # default basis diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index f882b88e300..ca3116f2648 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -500,7 +500,7 @@ def __init__(self, basis, symbol, latex_symbol=None, indices=None, Basis_abstract.__init__(self, basis._fmodule, symbol, latex_symbol, indices, latex_indices) # The individual linear forms: - vl = list() + vl = [] fmodule = self._fmodule ring_one = fmodule._ring.one() for i in fmodule.irange(): @@ -719,7 +719,7 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, # The basis is added to the module list of bases fmodule._known_bases.append(self) # The individual vectors: - vl = list() + vl = [] ring_one = fmodule._ring.one() for i in fmodule.irange(): v = fmodule.element_class(fmodule) diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 974feac8510..7387dde2f94 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -455,7 +455,7 @@ def __eq__(self, other): def __ne__(self, other): """ - This returns the negation of `__eq__`. + This returns the negation of ``__eq__``. EXAMPLES:: diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 367a00413b7..5f0a4f2d228 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -123,7 +123,7 @@ def __eq__(self, other) -> bool: def __ne__(self, other) -> bool: """ - Return the negation of `__eq__`. + Return the negation of ``__eq__``. EXAMPLES:: diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index bc64866ed01..950bb2ea392 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -685,8 +685,8 @@ def __add__(self, Nelt): if self._baseline is not None and Nelt._baseline is not None: # left treatement - for line in self._matrix: - new_matrix.append(line + " " * (self._l - len(line))) + new_matrix.extend(line + " " * (self._l - len(line)) + for line in self._matrix) if new_h > self._h: # | new_h > self._h @@ -695,8 +695,9 @@ def __add__(self, Nelt): # | } :: Nelt._baseline - self._baseline # | } if new_baseline > self._baseline: - for k in range(new_baseline - self._baseline): - new_matrix.append(" " * self._l) + l_space = " " * self._l + new_matrix.extend(l_space + for k in range(new_baseline - self._baseline)) # | } new_h > self._h # | } new_h - new_baseline > self._h - self._baseline # ||<-- baseline number of white lines at the top @@ -722,8 +723,8 @@ def __add__(self, Nelt): for j in range(Nelt._h): new_matrix[i + j] += Nelt._matrix[j] else: - for line in self._matrix: - new_matrix.append(line + " " * (self._l - len(line))) + new_matrix.extend(line + " " * (self._l - len(line)) + for line in self._matrix) for i, line_i in enumerate(Nelt._matrix): if i == len(new_matrix): new_matrix.append(" " * self._l + line_i) diff --git a/src/sage/version.py b/src/sage/version.py index d05ce0beb53..37c771ba0f2 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.5.rc0' -date = '2024-11-16' -banner = 'SageMath version 10.5.rc0, Release Date: 2024-11-16' +version = '10.6.beta0' +date = '2024-12-08' +banner = 'SageMath version 10.6.beta0, Release Date: 2024-12-08' diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 18ce9f7663e..d90c2eb2dd1 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -954,16 +954,17 @@ class SagecodeTransform(SphinxTransform): def apply(self): if self.app.builder.tags.has('html') or self.app.builder.tags.has('inventory'): - for node in self.document.findall(nodes.literal_block): + for node in list(self.document.findall(nodes.literal_block)): if node.get('language') is None and node.astext().startswith('sage:'): from docutils.nodes import container as Container, label as Label, literal_block as LiteralBlock, Text from sphinx_inline_tabs._impl import TabContainer parent = node.parent index = parent.index(node) prev_node = node.previous_sibling() - if isinstance(node.previous_sibling(), TabContainer): + if isinstance(prev_node, TabContainer): # Make sure not to merge inline tabs for adjacent literal blocks - parent.insert(index, Text('')) + parent.insert(index, nodes.paragraph()) + prev_node = parent[index] index += 1 parent.remove(node) # Tab for Sage code diff --git a/src/sage_setup/command/sage_build_ext_minimal.py b/src/sage_setup/command/sage_build_ext_minimal.py index 34ac31f8a87..25cab109ff8 100644 --- a/src/sage_setup/command/sage_build_ext_minimal.py +++ b/src/sage_setup/command/sage_build_ext_minimal.py @@ -20,7 +20,7 @@ def get_default_number_build_jobs() -> int: Get number of parallel build jobs used by default, i.e. unless explicitly set by the --parallel command line argument of setup.py. - First, the environment variable `SAGE_NUM_THREADS` is checked. + First, the environment variable ``SAGE_NUM_THREADS`` is checked. If that is unset, return the number of processors on the system, with a maximum of 10 (to prevent overloading the system if there a lot of CPUs). diff --git a/src/tox.ini b/src/tox.ini index b6548bc55a4..a88e9c7f879 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -180,7 +180,7 @@ description = # W605: invalid escape sequence ‘x’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E275,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E275,E302,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} pycodestyle --select E111,E271,E301,E302,E303,E305,E306,E401,E502,E703,E712,E713,E714,E72,W29,W391,W605, --filename *.pyx {posargs:{toxinidir}/sage/} [pycodestyle] @@ -314,7 +314,7 @@ passenv = RUFF_OUTPUT_FORMAT # 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable # 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values # -commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,PLW0602,PLW0642,PLR1711,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208,PLC0206 {posargs:{toxinidir}/sage/} [flake8] rst-roles =