diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69bb8f6d12f..8f2ef46a778 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -442,8 +442,11 @@ jobs: if: (success() || failure()) && steps.container.outcome == 'success' uses: actions/upload-artifact@v4 with: + # The path .coverage is a directory that contains the combined coverage + # data file .coverage, which is a hidden file because of the leading dot name: coverage-${{ steps.copy-coverage.outputs.tests_id }} path: .coverage + include-hidden-files: true coverage-report: runs-on: ubuntu-latest @@ -530,11 +533,11 @@ jobs: # Combining - name: Download coverage artifacts + if: (success() || failure()) && steps.container.outcome == 'success' uses: actions/download-artifact@v4 with: path: .coverage pattern: coverage-* - if: (success() || failure()) && steps.container.outcome == 'success' - name: Coverage report if: (success() || failure()) && steps.container.outcome == 'success' diff --git a/CITATION.cff b/CITATION.cff index 0576a00c2be..b156494bc1f 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.beta4 +version: 10.5.beta5 doi: 10.5281/zenodo.8042260 -date-released: 2024-09-15 +date-released: 2024-09-22 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index 76a54840a85..807904984ea 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.5.beta4, Release Date: 2024-09-15 +SageMath version 10.5.beta5, Release Date: 2024-09-22 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 3f4c1eecd6d..c8b727287db 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=d2f8c0bc6c40a0e3e8f7cb0deebee5e7bc7da501 -sha256=cde422cec1dc104f4f4b1369167a17cc77519186180bfc14322d078881581c50 +sha1=2cdffd348b8a4de62b51e1f6c37a7d414004c09e +sha256=273c37842eedefc3575e34bb14819ab3738a32c39ae634f2342bb50baa740c60 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index d3929445739..1a9207183f8 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -27fce1faa78ef19b8c43287016f0acbdf0fa169a +9b58ceaa68960b38142f27fdfc04373301da4e46 diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index f9a29f411e0..25272458c17 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.5b4 +sage-conf ~= 10.5b5 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index 8c69b2c724f..e8dd641aa39 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.5b4 +sage-docbuild ~= 10.5b5 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index 1dcac493c5d..091da0c76fb 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.5b4 +sage-setup ~= 10.5b5 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index da184780274..9a1ba7768dc 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.5b4 +sage-sws2rst ~= 10.5b5 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 6e3bb64c65c..f6d0da68b13 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.5b4 +sagemath-standard ~= 10.5b5 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index c6fb0e82600..dbd86a12a95 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.5b4 +sagemath-bliss ~= 10.5b5 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 66dbe5766e0..c30c3a62bf5 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.5b4 +sagemath-categories ~= 10.5b5 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index a955c0b9902..79213005646 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.5b4 +sagemath-coxeter3 ~= 10.5b5 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 480e8285f3b..8e9950a8f14 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.5b4 +sagemath-environment ~= 10.5b5 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index ad9c0830686..7c3689d9abd 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.5b4 +sagemath-mcqd ~= 10.5b5 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index 0782881aee0..71c6b9b1d5a 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.5b4 +sagemath-meataxe ~= 10.5b5 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index a652cfa09f5..82160528219 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.5b4 +sagemath-objects ~= 10.5b5 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index e73e1ae8031..6ac416a104a 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.5b4 +sagemath-repl ~= 10.5b5 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index d6d6f3820de..631d42ff56d 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.5b4 +sagemath-sirocco ~= 10.5b5 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index e0801e2814c..f42b1677327 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.5b4 +sagemath-tdlib ~= 10.5b5 diff --git a/m4/pyproject_toml_metadata.m4 b/m4/pyproject_toml_metadata.m4 index 6a731e36c6a..5f39bd00077 100644 --- a/m4/pyproject_toml_metadata.m4 +++ b/m4/pyproject_toml_metadata.m4 @@ -17,10 +17,12 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering :: Mathematics", ] -urls = {download = "https://doc.sagemath.org/html/en/installation/index.html", - "release notes" = "https://github.com/sagemath/sage/releases", - source = "https://github.com/sagemath/sage", - documentation = "https://doc.sagemath.org", - homepage = "https://www.sagemath.org", - tracker = "https://github.com/sagemath/sage/issues"} requires-python = ">=3.9, <3.13" + +[project.urls] +download = "https://doc.sagemath.org/html/en/installation/index.html" +"release notes" = "https://github.com/sagemath/sage/releases" +source = "https://github.com/sagemath/sage" +documentation = "https://doc.sagemath.org" +homepage = "https://www.sagemath.org" +tracker = "https://github.com/sagemath/sage/issues" diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/src/VERSION.txt b/src/VERSION.txt index da4a0151f8b..c0a995cdc9b 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.5.beta4 +10.5.beta5 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 1c3e104e271..d63c6b34aec 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.beta4' -SAGE_RELEASE_DATE='2024-09-15' -SAGE_VERSION_BANNER='SageMath version 10.5.beta4, Release Date: 2024-09-15' +SAGE_VERSION='10.5.beta5' +SAGE_RELEASE_DATE='2024-09-22' +SAGE_VERSION_BANNER='SageMath version 10.5.beta5, Release Date: 2024-09-22' diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index aaaf7a410c0..59b28d9e9be 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1443,6 +1443,11 @@ REFERENCES: for closed Riemannian manifolds*, Ann. of Math. (2) 45 (1944), 747–752. +.. [CHNP2020] Kieran Clancy, Michael Haythorpe, Alex Newcombe and Ed Pegg Jr, + *There Are No Cubic Graphs on 26 Vertices with Crossing Number 10 + or 11*, Graphs and Combinatorics 36, pages: 1713 -- 1721, (2020), + :doi:`10.1007/s00373-020-02204-6`. + .. [CP2023] \M. Cati and D.V. Pasechnik. *Implementing Hadamard Matrices in SageMath*. Preprint, :arxiv:`2306.16812`, (2023). @@ -1700,6 +1705,10 @@ REFERENCES: bi-matrix games*. http://vknight.org/unpeudemath/code/2015/06/25/on_testing_degeneracy_of_games/ (2015) +.. [CKWL2019] Marcelo H. de Carvalho, Nishad Kothari, Xiumei Wang and Yixun + Linc. *Birkhoff-von Neumann graphs that are PM-compact*. 2019. + :doi:`10.48550/arXiv.1807.07339`. + .. [CL1996] Chartrand, G. and Lesniak, L.: *Graphs and Digraphs*. Chapman and Hall/CRC, 1996. @@ -1716,12 +1725,20 @@ REFERENCES: Yokonuma-Hecke algebras and the HOMFLYPT polynomial*. (2015) :arxiv:`1204.1871v4`. +.. [CL2023] Xavier Caruso and Antoine Leudière. + *Algorithms for computing norms and characteristic polynomials on general Drinfeld modules*, (2023) :arxiv:`2307.02879`. + .. [Cle1872] Alfred Clebsch, *Theorie der binären algebraischen Formen*, Teubner, 1872. .. [CLG1997] Frank Celler and C. R. Leedham-Green, *Calculating the Order of an Invertible Matrix*, 1997 +.. [CLM2006] Marcelo H. de Carvalho, Cláudio L. Lucchesi and U.S.R. Murty, + *How to build a brick*, Discrete Mathematics, Volume 306, + Issues 19--20, Pages 2383--2410,ISSN 0012--365X, (2006), + :doi:`10.1016/j.disc.2005.12.032`. + .. [CLRS2001] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein, *Section 22.4: Topological sort*, Introduction to Algorithms (2nd ed.), MIT Press and @@ -2618,6 +2635,11 @@ REFERENCES: Wehler K3 Surfaces over finite fields*. New Zealand Journal of Mathematics 45 (2015), 19–31. +.. [FiLi2001] Ilse Fischer and Charles H.C. Little, *A Characterisation of + Pfaffian Near Bipartite Graphs*, Journal of Combinatorial Theory, + Series B, vol. 82, issue 2, (2001), pages: 175 -- 222, ISSN: + 0095 -- 8956, :doi:`10.1006/jctb.2000.2025`. + .. [Fil2017] Ivana Filipan, *An Invitation to Combinatorial Tropical Geometry*. Conference: 1st Croatian Combinatorial Days. 2017. :doi:`10.5592/CO/CCD.2016.05`. @@ -2814,6 +2836,10 @@ REFERENCES: .. [Gek1991] \E.-U. Gekeler. On finite Drinfeld modules. Journal of algebra, 1(141):187–203, 1991. +.. [Gek2008] \E.-U. Gekeler. Frobenius Distributions of Drinfeld Modules over + Finite Fields. Transactions of the American Mathematical Society, + Volume 360 (2008), no. 4. + .. [Gek2017] \E.-U. Gekeler. On Drinfeld modular forms of higher rank. Journal de théorie des nombres de Bordeaux, Volume 29 (2017) no. 3, pp. 875-902. :doi:`10.5802/jtnb.1005` @@ -3936,6 +3962,10 @@ REFERENCES: 47:95-104, 1997. :doi:`10.1023/A:1022444205860` +.. [KM2015] Nishad Kothari and U.S.R. Murty. *K4-free and C6¯-free Planar + Matching Covered Graphs.* Journal of Graph Theory. 82. (2015) + :doi:`10.1002/jgt.21882`. + .. [KMAUTOM2000] Masayuki Kanda, Shiho Moriai, Kazumaro Aoki, Hiroki Ueda, Youichi Takashima, Kazuo Ohta, and Tsutomu Matsumoto, *E2 - a new 128-bit block cipher*; in IEICE Transactions on @@ -4477,6 +4507,11 @@ REFERENCES: IEEE Trans. Inf. Th. 25(1979), 1-7. :doi:`10.1109/TIT.1979.1055985`. +.. [Lov1983] László Lovász, + *Ear-decompositions of matching-covered graphs*, + Combinatorica 3, 105--117 (1983) + :doi:`10.1007/BF02579346`. + .. [LP2007] \G. Leander and A. Poschmann, *On the Classification of 4 Bit S-boxes*; in WAIFI, (2007), pp. 159-176. @@ -5157,6 +5192,10 @@ REFERENCES: :doi:`10.1007/s00453-006-1225-y`, http://www.cs.uoi.gr/~stavros/C-Papers/C-2004-SODA.pdf +.. [NT2007] Serguei Norine and Robin Thomas. *Minimally Non-Pfaffian Graphs*. + Combinatorica, vol. 27, no. 5, pages: 587 -- 600, Springer. 2007. + :doi:`10.1016/j.jctb.2007.12.005`. + .. [Nur2004] K. Nurmela. *Upper bounds for covering arrays by tabu search*. Discrete Applied Math., 138 (2004), 143-152. @@ -5668,6 +5707,11 @@ REFERENCES: .. [RS2012] G. Rudolph and M. Schmidt, "Differential Geometry and Mathematical Physics. Part I. Manifolds, Lie Groups and Hamiltonian Systems", Springer, 2012. +.. [RST2019] Neil Robertson, Paul Seymour and Robin Thomas, *Excluded minors in + cubic graphs*, Journal of Combinatorial Theory, Series B, vol. 138, + (2019), pages: 219 -- 285, ISSN: 0095 -- 8956, + :doi:`10.1016/j.jctb.2019.02.002`. + .. [RSW2011] Victor Reiner, Franco Saliola, Volkmar Welker. *Spectra of Symmetrized Shuffling Operators*. :arxiv:`1102.2460v2`. diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 042b9365ecb..a101064eb0e 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -355,6 +355,7 @@ # **************************************************************************** from copy import copy +from typing import Any from sage.arith.misc import binomial from sage.categories.homset import Hom @@ -562,7 +563,7 @@ def homogeneous_components(self) -> dict: """ deg_matrix = block_matrix([[identity_matrix(self.parent().rank()), -self.parent().b_matrix()]]) - components = {} + components: dict[tuple, Any] = {} x = self.lift() monomials = x.monomials() for m in monomials: @@ -1432,11 +1433,11 @@ def _repr_(self) -> str: and coefficients y0, y1 over Integer Ring """ var_names = self.initial_cluster_variable_names() - var_names = (" " if len(var_names) == 1 else "s ") + ", ".join(var_names) + var_names_str = (" " if len(var_names) == 1 else "s ") + ", ".join(var_names) coeff_names = self.coefficient_names() coeff_prefix = " and" + (" " if len(coeff_names) > 0 else " no ") + "coefficient" coeff = coeff_prefix + (" " if len(coeff_names) == 1 else "s ") + ", ".join(coeff_names) + (" " if len(coeff_names) > 0 else "") - return "A Cluster Algebra with cluster variable" + var_names + coeff + "over " + repr(self.scalars()) + return "A Cluster Algebra with cluster variable" + var_names_str + coeff + "over " + repr(self.scalars()) def _an_element_(self): r""" diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx index 44c9e5b3910..2e04549ec7f 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx @@ -399,7 +399,7 @@ cdef list compute_gb(factory, tuple args): cdef MPolynomialRing_libsingular R = PolynomialRing(factory._FR.field(), len(sorted_vars), 'a', order=term_order) # Zip tuples into R and compute Groebner basis - cdef idx_map = {old : new for new, old in enumerate(sorted_vars)} + cdef idx_map = {old: new for new, old in enumerate(sorted_vars)} nvars = len(sorted_vars) F = factory.field() cdef list polys = list() diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index b4dc71825af..48796fbd605 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1255,7 +1255,7 @@ def __init__(self, algebra, prefix=None): # This **must** match the name of the class in order for # specialize_to() to work - _basis_name = None + _basis_name = 'B' def _repr_term(self, t): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/examples.py b/src/sage/algebras/lie_conformal_algebras/examples.py index 3d520e449db..1db194445be 100644 --- a/src/sage/algebras/lie_conformal_algebras/examples.py +++ b/src/sage/algebras/lie_conformal_algebras/examples.py @@ -20,15 +20,15 @@ - Reimundo Heluani (2020-06-15): Initial implementation. """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2020 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .abelian_lie_conformal_algebra import AbelianLieConformalAlgebra as Abelian from .affine_lie_conformal_algebra import AffineLieConformalAlgebra as Affine @@ -40,14 +40,3 @@ from .neveu_schwarz_lie_conformal_algebra import NeveuSchwarzLieConformalAlgebra as NeveuSchwarz from .virasoro_lie_conformal_algebra import VirasoroLieConformalAlgebra as Virasoro from .weyl_lie_conformal_algebra import WeylLieConformalAlgebra as Weyl - -assert Abelian -assert Affine -assert BosonicGhosts -assert FermionicGhosts -assert FreeBosons -assert FreeFermions -assert N2 -assert NeveuSchwarz -assert Virasoro -assert Weyl diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index 05e4e1b6982..931ee211ff1 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -838,7 +838,7 @@ def counit(self, elt): constant = R(str(ext_rep.pop(2 * i))) # Pop the coefficient break # To reconstruct, we need the following - F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) + F = self._libgap.FamilyObj().ElementsFamily() elt = F.ObjByExtRep(ext_rep) co = self._libgap.CounitMap() return R(str(co(elt))) + constant @@ -2330,7 +2330,7 @@ def _construct_monomial(self, k): sage: B._construct_monomial((3,0,1)) F[a1]^(3)*F[a2] """ - F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) + F = self._libgap.FamilyObj().ElementsFamily() one = self._libgap_base.One() data = [] for i, val in enumerate(k): @@ -2684,7 +2684,7 @@ def _unpickle_generic_element(parent, data): sage: loads(dumps(x)) == x # indirect doctest True """ - F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(parent._libgap)) + F = parent._libgap.FamilyObj().ElementsFamily() ret = [] # We need to multiply by this to get the right type in GAP one = parent._libgap_base.One() diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 48dad835671..d17f5a14e90 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -1357,14 +1357,10 @@ def desolve_rk4_inner(de, dvar): XMAX = XMIN YMAX = YMIN for s, t in sol: - if s > XMAX: - XMAX = s - if s < XMIN: - XMIN = s - if t > YMAX: - YMAX = t - if t < YMIN: - YMIN = t + XMAX = max(s, XMAX) + XMIN = min(s, XMIN) + YMAX = max(t, YMAX) + YMIN = min(t, YMIN) return plot_slope_field(de, (ivar, XMIN, XMAX), (dvar, YMIN, YMAX)) + R if not (isinstance(dvar, Expression) and dvar.is_symbol()): diff --git a/src/sage/categories/bimodules.py b/src/sage/categories/bimodules.py index eab8a1ad43d..5658cd5e514 100644 --- a/src/sage/categories/bimodules.py +++ b/src/sage/categories/bimodules.py @@ -102,7 +102,7 @@ def _make_named_class_key(self, name): sage: Bimodules(Fields(), Rings())._make_named_class_key('element_class') (Category of fields, Category of rings) """ - return (self._left_base_ring if isinstance(self._left_base_ring, Category) else self._left_base_ring.category(), + return (self._left_base_ring if isinstance(self._left_base_ring, Category) else self._left_base_ring.category(), self._right_base_ring if isinstance(self._right_base_ring, Category) else self._right_base_ring.category()) @classmethod diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index c037ed0c6a1..f8dddc6e398 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -49,7 +49,7 @@ def super_categories(self): """ return [Modules(self.base_ring())] - WithBasis = LazyImport('sage.categories.coalgebras_with_basis', 'CoalgebrasWithBasis') + WithBasis = LazyImport('sage.categories.coalgebras_with_basis', 'CoalgebrasWithBasis') Graded = LazyImport('sage.categories.graded_coalgebras', 'GradedCoalgebras') class ParentMethods: diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index dedad2c47d5..5d3fcc5ed9f 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -189,7 +189,8 @@ def __init__(self): self.n = 2 self._cartan_type = CartanType(['A', 2]) self.G = DiGraph(5) - self.G.add_edges([ [0,1,1], [1,2,1], [2,3,1], [3,5,1], [0,4,2], [4,5,2] ]) + self.G.add_edges([[0, 1, 1], [1, 2, 1], [2, 3, 1], + [3, 5, 1], [0, 4, 2], [4, 5, 2]]) self.module_generators = [self(0)] def __repr__(self): diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index 04eff9e9205..37369269cf2 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -1479,8 +1479,7 @@ def rowmotion_orbits_plots(self): max_orbit_size = 0 for orb in self.rowmotion_orbits(): orb_plots = [] - if len(orb) > max_orbit_size: - max_orbit_size = len(orb) + max_orbit_size = max(len(orb), max_orbit_size) for oi in orb: oiplot = self.order_ideal_plot(oi) orb_plots.append(oiplot) @@ -1565,8 +1564,7 @@ def toggling_orbits_plots(self, vs): max_orbit_size = 0 for orb in self.toggling_orbits(vs): orb_plots = [] - if len(orb) > max_orbit_size: - max_orbit_size = len(orb) + max_orbit_size = max(len(orb), max_orbit_size) for oi in orb: oiplot = self.order_ideal_plot(oi) orb_plots.append(oiplot) diff --git a/src/sage/coding/codecan/codecan.pyx b/src/sage/coding/codecan/codecan.pyx index c66a93a0f7d..79898ee30ce 100644 --- a/src/sage/coding/codecan/codecan.pyx +++ b/src/sage/coding/codecan/codecan.pyx @@ -916,8 +916,8 @@ cdef class PartitionRefinementLinearCode(PartitionRefinement_generic): if self._inner_group.rank < 2: return True - lower = iter(self._matrix[ : self._inner_group.rank].columns()) - upper = iter(self._matrix[self._inner_group.rank : ].columns()) + lower = iter(self._matrix[:self._inner_group.rank].columns()) + upper = iter(self._matrix[self._inner_group.rank:].columns()) for i in range(self._n): l = next(lower) diff --git a/src/sage/combinat/designs/designs_pyx.pyx b/src/sage/combinat/designs/designs_pyx.pyx index 20839d9c8aa..c862821330e 100644 --- a/src/sage/combinat/designs/designs_pyx.pyx +++ b/src/sage/combinat/designs/designs_pyx.pyx @@ -289,14 +289,14 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O for R in OA: if len(R) != k: if verbose: - print({"OA" : "Some row does not have length "+str(k), - "MOLS" : "The number of squares is not "+str(k-2)}[terminology]) + print({"OA": "Some row does not have length "+str(k), + "MOLS": "The number of squares is not "+str(k-2)}[terminology]) return False if len(OA) != n2: if verbose: - print({"OA" : "The number of rows is {} instead of {}^2={}".format(len(OA),n,n2), - "MOLS" : "All squares do not have dimension n^2={}^2".format(n)}[terminology]) + print({"OA": "The number of rows is {} instead of {}^2={}".format(len(OA),n,n2), + "MOLS": "All squares do not have dimension n^2={}^2".format(n)}[terminology]) return False if n == 0: @@ -319,8 +319,8 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O for j,x in enumerate(R): if x < 0 or x >= n: if verbose: - print({"OA" : "{} is not in the interval [0..{}]".format(x,n-1), - "MOLS" : "Entry {} was expected to be in the interval [0..{}]".format(x,n-1)}[terminology]) + print({"OA": "{} is not in the interval [0..{}]".format(x,n-1), + "MOLS": "Entry {} was expected to be in the interval [0..{}]".format(x,n-1)}[terminology]) sig_free(OAc) return False OAc[j*n2+i] = x @@ -341,8 +341,8 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O sig_free(OAc) bitset_free(seen) if verbose: - print({"OA" : "Columns {} and {} are not orthogonal".format(i,j), - "MOLS" : "Squares {} and {} are not orthogonal".format(i,j)}[terminology]) + print({"OA": "Columns {} and {} are not orthogonal".format(i,j), + "MOLS": "Squares {} and {} are not orthogonal".format(i,j)}[terminology]) return False sig_free(OAc) diff --git a/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx b/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx index 2fa1c414e91..f7f3502548b 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +++ b/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx @@ -145,7 +145,7 @@ cpdef find_product_decomposition(int k,int n): sage: _ = f(*args) """ cdef int n1,n2 - for n1 in range(2,n): + for n1 in range(2, n): n2 = n/n1 # n2 is decreasing along the loop if n2 < n1: break @@ -194,15 +194,13 @@ cpdef find_wilson_decomposition_with_one_truncated_group(int k,int n): if u == 0 or (u>1 and k >= u+2): continue - m = n/r + m = n // r # If there exists a TD(k,m) then k= m+2: break - if (is_available(k ,m ) and - is_available(k ,m+1) and - is_available(k+1,r ) and - is_available(k ,u )): + if (is_available(k, m) and is_available(k, m + 1) and + is_available(k + 1, r) and is_available(k, u)): from sage.combinat.designs.orthogonal_arrays import wilson_construction return wilson_construction, (None,k,r,m,(u,),False) @@ -294,22 +292,20 @@ cpdef find_construction_3_3(int k,int n): sage: find_construction_3_3(12,11) """ cdef int mm,nn,i - for mm in range(k-1,n/2+1): - if (not is_available(k ,mm ) or - not is_available(k ,mm+1)): + for mm in range(k-1, n//2+1): + if not(is_available(k, mm) and is_available(k, mm + 1)): continue - for nn in range(2,n/mm+1): + for nn in range(2, n//mm+1): i = n-nn*mm - if i<=0: + if i <= 0: continue - if (is_available(k+i, nn ) and - is_available(k , mm+i)): + if is_available(k + i, nn) and is_available(k, mm + i): from sage.combinat.designs.orthogonal_arrays_build_recursive import construction_3_3 - return construction_3_3, (k,nn,mm,i) + return construction_3_3, (k, nn, mm, i) -cpdef find_construction_3_4(int k,int n): +cpdef find_construction_3_4(int k, int n): r""" Find a decomposition for construction 3.4 from [AC07]_. @@ -339,20 +335,20 @@ cpdef find_construction_3_4(int k,int n): not is_available(k,mm+2)): continue - for nn in range(2,n/mm+1): + for nn in range(2, n//mm+1): i = n-nn*mm if i<=0: continue for s in range(1,min(i,nn)): r = i-s - if (is_available(k+r+1,nn) and - is_available(k , s) and - (is_available(k,mm+r) or is_available(k,mm+r+1))): + if (is_available(k + r + 1, nn) and + is_available(k, s) and + (is_available(k, mm + r) or is_available(k, mm + r + 1))): from sage.combinat.designs.orthogonal_arrays_build_recursive import construction_3_4 - return construction_3_4, (k,nn,mm,r,s) + return construction_3_4, (k, nn, mm, r, s) -cpdef find_construction_3_5(int k,int n): +cpdef find_construction_3_5(int k, int n): r""" Find a decomposition for construction 3.5 from [AC07]_. @@ -376,14 +372,14 @@ cpdef find_construction_3_5(int k,int n): sage: find_construction_3_5(9,24) """ cdef int mm,i,nn,r,s,t - for mm in range(2,n/2+1): + for mm in range(2, n//2+1): if (mm+3 >= n or not is_available(k,mm+1) or not is_available(k,mm+2) or not is_available(k,mm+3)): continue - for nn in range(2,n/mm+1): + for nn in range(2, n//mm+1): i = n-nn*mm if i<=0: continue @@ -433,7 +429,7 @@ cpdef find_construction_3_6(int k,int n): not is_available(k,mm+2)): continue - for nn in range(2,n/mm+1): + for nn in range(2, n//mm+1): i = n-nn*mm if i<=0: continue @@ -913,7 +909,7 @@ cpdef find_brouwer_van_rees_with_one_truncated_column(int k,int n): cdef tuple values # We write n=rm+remainder - for m in range(2,n//2): + for m in range(2, n//2): if not is_available(k,m): continue @@ -935,7 +931,7 @@ cpdef find_brouwer_van_rees_with_one_truncated_column(int k,int n): continue max_multiplier = max(available_multipliers) - for r in range(2,n//m+1): + for r in range(2, n//m+1): remainder = n-r*m if (remainder > r*max_multiplier or not is_available(k+1,r) or diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index e2d818e9480..66952952854 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -1212,8 +1212,7 @@ def disjoint_mate_dlxcpp_rows_and_map(self, allow_subtrade): dlx_rows.append([c_OFFSET, r_OFFSET, xy_OFFSET]) - if max_column_nr < max(c_OFFSET, r_OFFSET, xy_OFFSET): - max_column_nr = max(c_OFFSET, r_OFFSET, xy_OFFSET) + max_column_nr = max(max_column_nr, max(c_OFFSET, r_OFFSET, xy_OFFSET)) # We will have missed some columns. We # have to add 'dummy' rows so that the C++ DLX solver will find diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 26b029810cd..39d1769f0b6 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -2039,7 +2039,7 @@ def on_basis(comp, i): return P.zero() else: return x[i-1]**comp[-1] * on_basis(comp[:-1], i-1) + \ - on_basis(comp, i-1) + on_basis(comp, i-1) return M._apply_module_morphism(self, lambda comp: on_basis(comp,n), codomain=P) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index defa29342dc..6b6a7edfa4c 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -8229,8 +8229,7 @@ def _fast_iterator(self, n, max_part): yield [] return - if n < max_part: - max_part = n + max_part = min(n, max_part) bdry = self._ell - 1 for i in reversed(range(1, max_part + 1)): @@ -8421,8 +8420,7 @@ def _fast_iterator(self, n, max_part, depth=0): yield [n] return - if n < max_part: - max_part = n + max_part = min(n, max_part) bdry = self._ell - 1 for i in reversed(range(1, max_part + 1)): @@ -9066,8 +9064,7 @@ def _fast_iterator(self, n, max_part): yield [] return - if n < max_part: - max_part = n + max_part = min(n, max_part) for i in range(max_part, 0, -1): for p in self._fast_iterator(n-i, i): diff --git a/src/sage/combinat/posets/hasse_cython_flint.pyx b/src/sage/combinat/posets/hasse_cython_flint.pyx index e2b4589b238..28f3f026430 100644 --- a/src/sage/combinat/posets/hasse_cython_flint.pyx +++ b/src/sage/combinat/posets/hasse_cython_flint.pyx @@ -20,6 +20,53 @@ from sage.libs.flint.fmpz_mat cimport * from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import ZZ +from sage.libs.flint.fmpz_poly_sage cimport Fmpz_poly + + +cpdef Fmpz_poly chain_poly(list positions): + r""" + Return the chain polynomial of a poset. + + INPUT: + + - ``positions`` -- a list of sets of integers describing the poset, as + given by the lazy attribute ``_leq_storage`` of Hasse diagrams + + OUTPUT: a Flint polynomial in one variable over `\ZZ`. + + EXAMPLES:: + + sage: from sage.combinat.posets.hasse_cython_flint import chain_poly + sage: D = [{0, 1}, {1}] + sage: chain_poly(D) + 3 1 2 1 + sage: P = posets.TamariLattice(5) + sage: H = P._hasse_diagram + sage: D = H._leq_storage + sage: chain_poly(D) + 12 1 42 357 1385 3133 4635 4758 3468 1778 612 127 12 + """ + cdef Py_ssize_t n = len(positions) + cdef Py_ssize_t i, j + + q = Fmpz_poly([0, 1]) + zero = Fmpz_poly(0) + one = Fmpz_poly(1) + + cdef list chain_polys = [zero] * n + + # chain_polys[i] will be the generating function for the + # chains with lowest vertex i (in the labelling of the + # Hasse diagram). + for i in range(n - 1, -1, -1): + cpi = q + for j in positions[i]: + cpi += q * chain_polys[j] + chain_polys[i] = cpi + total = one + for i in range(n): + total += chain_polys[i] + return total cpdef Matrix_integer_dense moebius_matrix_fast(list positions): diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 0056ad37eed..56b51e96371 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -27,7 +27,8 @@ from sage.rings.integer_ring import ZZ lazy_import('sage.combinat.posets.hasse_cython_flint', - ['moebius_matrix_fast', 'coxeter_matrix_fast']) + ['moebius_matrix_fast', 'coxeter_matrix_fast', + 'chain_poly']) lazy_import('sage.matrix.constructor', 'matrix') lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') @@ -2413,6 +2414,23 @@ def chains(self, element_class=list, exclude=None, conversion=None): """ return IncreasingChains(self._leq_storage, element_class, exclude, conversion) + def chain_polynomial(self): + """ + Return the chain polynomial of the poset. + + The coefficient of `q^k` is the number of chains of `k` + elements in the poset. List of coefficients of this polynomial + is also called a *f-vector* of the poset. + + EXAMPLES:: + + sage: P = posets.ChainPoset(3) + sage: H = P._hasse_diagram + sage: t = H.chain_polynomial(); t + q^3 + 3*q^2 + 3*q + 1 + """ + return chain_poly(self._leq_storage)._sage_('q') # noqa: F821 + def is_linear_interval(self, t_min, t_max) -> bool: """ Return whether the interval ``[t_min, t_max]`` is linear. diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index a111609b4b0..6471163fe00 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -7682,18 +7682,7 @@ def chain_polynomial(self): sage: R.chain_polynomial() q + 1 """ - hasse = self._hasse_diagram - q = polygen(ZZ, 'q') - one = q.parent().one() - hasse_size = hasse.cardinality() - chain_polys = [0] * hasse_size - # chain_polys[i] will be the generating function for the - # chains with topmost vertex i (in the labelling of the - # Hasse diagram). - for i in range(hasse_size): - chain_polys[i] = q + sum(q * chain_polys[j] - for j in hasse.principal_order_ideal(i)) - return one + sum(chain_polys) + return self._hasse_diagram.chain_polynomial() def order_polynomial(self): r""" diff --git a/src/sage/combinat/rigged_configurations/bij_type_D.py b/src/sage/combinat/rigged_configurations/bij_type_D.py index e1d84d29e4b..a6a5c8316a7 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D.py @@ -238,8 +238,7 @@ def next_state(self, val): if tableau_height <= n - 2: max_width2 = self.ret_rig_con[n - 2].insert_cell(max_width) max_width = self.ret_rig_con[n - 1].insert_cell(max_width) - if max_width2 < max_width: - max_width = max_width2 + max_width = min(max_width2, max_width) elif pos_val <= self.cur_dims[0][0]: # Special case when the height will become n max_width = self.ret_rig_con[self.cur_dims[0][0] - 1].insert_cell(max_width) @@ -603,8 +602,7 @@ def next_state(self, height): temp_size = self.cur_partitions[n - 2][ell[n - 2]] if ell[n - 1] is not None: last_size = self.cur_partitions[n - 1][ell[n - 1]] - if temp_size > last_size: - last_size = temp_size + last_size = max(temp_size, last_size) else: b = n else: diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index c3151013ed7..c8e665fcaa2 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -963,7 +963,7 @@ def coxeter_matrix(self): sage: ct.cartan_matrix().coxeter_matrix() == ct.coxeter_matrix() True """ - scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} + scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix I = self.index_set() n = len(I) diff --git a/src/sage/combinat/root_system/coxeter_group.py b/src/sage/combinat/root_system/coxeter_group.py index 0f8fd84fdea..656c933c3e5 100644 --- a/src/sage/combinat/root_system/coxeter_group.py +++ b/src/sage/combinat/root_system/coxeter_group.py @@ -157,4 +157,4 @@ def CoxeterGroup(data, implementation='reflection', base_ring=None, index_set=No from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.coxeter_group', 'CoxeterGroupAsPermutationGroup', ReflectionGroup) +register_unpickle_override('sage.combinat.root_system.coxeter_group', 'CoxeterGroupAsPermutationGroup', ReflectionGroup) diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index 76411c66158..b190601f0bf 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -834,7 +834,7 @@ def coxeter_diagram(self): True """ from sage.rings.infinity import infinity - scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} + scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} from sage.graphs.graph import Graph coxeter_diagram = Graph(multiedges=False) I = self.index_set() diff --git a/src/sage/combinat/root_system/type_A.py b/src/sage/combinat/root_system/type_A.py index 26c6154a5bd..91907976f8c 100644 --- a/src/sage/combinat/root_system/type_A.py +++ b/src/sage/combinat/root_system/type_A.py @@ -336,11 +336,12 @@ def ascii_art(self, label=None, node=None): label = lambda i: i if node is None: node = self._ascii_art_node - ret = "---".join(node(label(i)) for i in range(1,n+1)) + "\n" - ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) + ret = "---".join(node(label(i)) for i in range(1, n + 1)) + "\n" + ret += "".join("{!s:4}".format(label(i)) for i in range(1, n + 1)) return ret # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_A', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_A', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_C.py b/src/sage/combinat/root_system/type_C.py index ff0288d5780..d7c6b67194f 100644 --- a/src/sage/combinat/root_system/type_C.py +++ b/src/sage/combinat/root_system/type_C.py @@ -306,10 +306,11 @@ def _default_folded_cartan_type(self): """ from sage.combinat.root_system.type_folded import CartanTypeFolded n = self.n - return CartanTypeFolded(self, ['A', 2*n-1], - [[i, 2*n-i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2*n - 1], + [[i, 2*n - i] for i in range(1, n)] + [[n]]) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_C', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_C', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_D.py b/src/sage/combinat/root_system/type_D.py index 7d7988c8891..49e9d952a2f 100644 --- a/src/sage/combinat/root_system/type_D.py +++ b/src/sage/combinat/root_system/type_D.py @@ -10,6 +10,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from . import ambient_space +from sage.misc.persist import register_unpickle_override class AmbientSpace(ambient_space.AmbientSpace): @@ -116,9 +117,6 @@ def fundamental_weight(self, i): return self.sum(self.monomial(j) for j in range(i)) -from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_A', 'ambient_space', AmbientSpace) - from sage.misc.cachefunc import cached_method from .cartan_type import CartanType_standard_finite, CartanType_simply_laced, CartanType_simple @@ -349,10 +347,10 @@ def ascii_art(self, label=None, node=None): ret = (4*(n-3))*" "+"{} {}\n".format(node(label(n)), label(n)) ret += ((4*(n-3))*" " + "|\n")*2 ret += "---".join(node(label(i)) for i in range(1, n)) + "\n" - ret += "".join("{!s:4}".format(label(i)) for i in range(1,n)) + ret += "".join("{!s:4}".format(label(i)) for i in range(1, n)) return ret # For unpickling backward compatibility (Sage <= 4.1) -from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_D', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_D', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 5ac0041d5ca..a7fbb8aeb39 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -636,4 +636,5 @@ def ascii_art(self, label=None, node=None): # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_E', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_E', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index 744de2679a4..9a13a2e7a23 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -365,7 +365,7 @@ def dual(self): 4 3 2 1 F4 relabelled by {1: 4, 2: 3, 3: 2, 4: 1} """ - return self.relabel({1:4, 2:3, 3:2, 4:1}) + return self.relabel({1: 4, 2: 3, 3: 2, 4: 1}) def _default_folded_cartan_type(self): """ @@ -382,4 +382,5 @@ def _default_folded_cartan_type(self): # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_F', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_F', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_G.py b/src/sage/combinat/root_system/type_G.py index 1ae705e5bec..057d8d17bd1 100644 --- a/src/sage/combinat/root_system/type_G.py +++ b/src/sage/combinat/root_system/type_G.py @@ -271,7 +271,7 @@ def dual(self): 2 1 G2 relabelled by {1: 2, 2: 1} """ - return self.relabel({1:2, 2:1}) + return self.relabel({1: 2, 2: 1}) def _default_folded_cartan_type(self): """ @@ -288,4 +288,5 @@ def _default_folded_cartan_type(self): # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_G', 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_G', + 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index ff039ebd863..5feb90c385b 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -988,4 +988,6 @@ def _repr_(self): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.dual', 'SymmetricFunctionAlgebraElement_dual', SymmetricFunctionAlgebra_dual.Element) +register_unpickle_override('sage.combinat.sf.dual', + 'SymmetricFunctionAlgebraElement_dual', + SymmetricFunctionAlgebra_dual.Element) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index f2905d818bd..675c02604fd 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -521,4 +521,6 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.elementary', 'SymmetricFunctionAlgebraElement_elementary', SymmetricFunctionAlgebra_elementary.Element) +register_unpickle_override('sage.combinat.sf.elementary', + 'SymmetricFunctionAlgebraElement_elementary', + SymmetricFunctionAlgebra_elementary.Element) diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index fffc4a1873c..e6bc361f3b0 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -435,4 +435,6 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.homogeneous', 'SymmetricFunctionAlgebraElement_homogeneous', SymmetricFunctionAlgebra_homogeneous.Element) +register_unpickle_override('sage.combinat.sf.homogeneous', + 'SymmetricFunctionAlgebraElement_homogeneous', + SymmetricFunctionAlgebra_homogeneous.Element) diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index c301e295721..d0a0a040672 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -764,5 +764,5 @@ class Element(LLT_generic.Element): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.llt', 'LLTElement_spin', LLT_spin.Element) -register_unpickle_override('sage.combinat.sf.llt', 'LLTElement_cospin', LLT_cospin.Element) +register_unpickle_override('sage.combinat.sf.llt', 'LLTElement_spin', LLT_spin.Element) +register_unpickle_override('sage.combinat.sf.llt', 'LLTElement_cospin', LLT_cospin.Element) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 423329b76c6..395906bada4 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1998,16 +1998,16 @@ def qt_kostka(lam, mu): for p2 in parts: res = s(H(p2)) for p1 in parts: - _qt_kostka_cache[(p1,p2)] = QQqt(res.coefficient(p1).numerator()) + _qt_kostka_cache[(p1, p2)] = QQqt(res.coefficient(p1).numerator()) - return _qt_kostka_cache[(lam,mu)] + return _qt_kostka_cache[(lam, mu)] # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_h', MacdonaldPolynomials_h.Element) +register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_h', MacdonaldPolynomials_h.Element) register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_ht', MacdonaldPolynomials_ht.Element) -register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_j', MacdonaldPolynomials_j.Element) -register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_p', MacdonaldPolynomials_p.Element) -register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_q', MacdonaldPolynomials_q.Element) -register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_s', MacdonaldPolynomials_s.Element) +register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_j', MacdonaldPolynomials_j.Element) +register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_p', MacdonaldPolynomials_p.Element) +register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_q', MacdonaldPolynomials_q.Element) +register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_s', MacdonaldPolynomials_s.Element) diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index 9a4378a859f..926213f7c0e 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -348,4 +348,4 @@ def _apply_functor(self, R): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.orthotriang', 'SymmetricFunctionAlgebraElement_orthotriang', SymmetricFunctionAlgebra_orthotriang.Element) +register_unpickle_override('sage.combinat.sf.orthotriang', 'SymmetricFunctionAlgebraElement_orthotriang', SymmetricFunctionAlgebra_orthotriang.Element) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 961e7553450..ce64edef000 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -325,9 +325,9 @@ def scalar(self, x, zee=None): parent = self.parent() x = parent(x) if zee is None: - f = lambda part1, part2: sfa.zee(part1) + f = lambda part1, part2: sfa.zee(part1) else: - f = lambda part1, part2: zee(part1) + f = lambda part1, part2: zee(part1) return parent._apply_multi_module_morphism(self, x, f, orthogonal=True) def _derivative(self, part): @@ -933,4 +933,6 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.powersum', 'SymmetricFunctionAlgebraElement_power', SymmetricFunctionAlgebra_power.Element) +register_unpickle_override('sage.combinat.sf.powersum', + 'SymmetricFunctionAlgebraElement_power', + SymmetricFunctionAlgebra_power.Element) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index fb170a25370..6d68365f270 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -843,4 +843,6 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.schur', 'SymmetricFunctionAlgebraElement_schur', SymmetricFunctionAlgebra_schur.Element) +register_unpickle_override('sage.combinat.sf.schur', + 'SymmetricFunctionAlgebraElement_schur', + SymmetricFunctionAlgebra_schur.Element) diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index 7e35baa2976..08897c8b6da 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -6794,8 +6794,7 @@ def _powerful_numbers_in_range(self, n, m): # This is naive -- too slow; too much overhead # return [i for i in range(self._n, self._n+how_many) if self.is_powerful(i)] - if n < 4: - n = 4 + n = max(n, 4) # Use PARI directly -- much faster. from sage.libs.pari.all import pari L = pari('v=listcreate(); for(i=%s,%s,if(vecmin(factor(i)[,2])>1,listput(v,i))); v' % (n, m)) @@ -8315,8 +8314,7 @@ def _eval(self, n): continue # d is odd divisor k = min(d, 2 * n // d) - if k > m: - m = k + m = max(k, m) return ZZ(m) diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index 12a9b2c8f70..04211b19d0c 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -41,7 +41,10 @@ def change_support(perm, support, change_perm=None): (3,4,5) """ if change_perm is None: - change_perm = prod([PermutationGroupElement((i+1,support[i])) for i in range(len(support)) if i+1 != support[i]], PermutationGroupElement([], SymmetricGroup(support))) + change_perm = prod([PermutationGroupElement((i+1, support[i])) + for i in range(len(support)) + if i+1 != support[i]], + PermutationGroupElement([], SymmetricGroup(support))) if isinstance(perm, PermutationGroup_generic): return PermutationGroup([change_support(g, support, change_perm) for g in perm.gens()]) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index c754b029692..23e02ad61fb 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -1110,8 +1110,7 @@ def good_suffix_table(self): res = [l - p[-1]]*(l+1) for i in range(1, l+1): j = l - p[i - 1] - if res[j] > (i - p[i-1]): - res[j] = i - p[i-1] + res[j] = min(res[j], i - p[i-1]) return res @cached_method @@ -3455,8 +3454,7 @@ def critical_exponent(self): current_pos = k-j+l-1 pft[current_pos] = m current_exp = QQ((current_pos+1, current_pos+1-m)) - if current_exp > best_exp: - best_exp = current_exp + best_exp = max(current_exp, best_exp) for ((i, j), u) in st._transition_function[v].items(): if j is None: j = self.length() @@ -6319,8 +6317,7 @@ def delta(self): for s in self: if s == ss: c += 1 - if c > max_c: - max_c = c + max_c = max(c, max_c) else: v.append(c) ss = s diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 79c00b5c20e..a17331b7b82 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -1801,10 +1801,8 @@ def height_vector(self): y_min = y y_max = y else: - if y > y_max: - y_max = y - if y < y_min: - y_min = y + y_max = max(y, y_max) + y_min = min(y, y_min) h_vec.append(y_max - y_min) return h_vec @@ -1866,10 +1864,8 @@ def width_vector(self): x_min = x x_max = x else: - if x > x_max: - x_max = x - if x < x_min: - x_min = x + x_max = max(x, x_max) + x_min = min(x, x_min) w_vec.append(x_max - x_min) return w_vec diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index f33c868d636..e940582f83c 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -1227,8 +1227,7 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): TypeError: codomain (=a) must be an instance of FiniteWords """ n = self.alphabet().cardinality() - if min_length < 0: - min_length = 0 + min_length = max(min_length, 0) # create an iterable of compositions (all "compositions" if arg is # None, or [arg] otherwise) if arg is None: diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 0349afb2518..2639e9e2124 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1643,6 +1643,7 @@ def _init_allgens(self, ftpdata, largest_conductor=0): con.executemany("UPDATE t_curve SET gens=? WHERE curve=?", curve_data) print("Committing...") + self.commit() if largest_conductor and int(v[0]) > largest_conductor: break diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index de1c8531814..dfe57f59b0b 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -150,15 +150,13 @@ def init_sage(controller=None): sage: from sympy.printing.pretty.pretty import PrettyPrinter sage: s = sympify('+x^'.join(str(i) for i in range(30))) sage: print(PrettyPrinter(settings={'wrap_line': True}).doprint(s)) - 29 28 27 26 25 24 23 22 21 20 19 18 17 ↪ - x + x + x + x + x + x + x + x + x + x + x + x + x + ↪ + 29 28 27 26 25 24 23 22 21 20 19 18 17... + x + x + x + x + x + x + x + x + x + x + x + x + x... - ↪ 16 15 14 13 12 11 10 9 8 7 6 5 4 3 ↪ - ↪ x + x + x + x + x + x + x + x + x + x + x + x + x + x + ↪ + ... 16 15 14 13 12 11 10 9 8 7 6 5 4 3... + ...x + x + x + x + x + x + x + x + x + x + x + x + x + x... - ↪ 2 - ↪ x + x - + ... The displayhook sorts dictionary keys to simplify doctesting of dictionary output:: @@ -1944,8 +1942,7 @@ def sel_exit(): # has the messages pipe open). # Adjust deadline to read all messages: newdeadline = now + die_timeout - if w.deadline > newdeadline: - w.deadline = newdeadline + w.deadline = min(w.deadline, newdeadline) new_workers.append(w) else: # Save the result and output of the worker @@ -2042,8 +2039,7 @@ def sel_exit(): # The master pselect() call rlist = [w.rmessages for w in workers if w.rmessages is not None] tmout = min(w.deadline for w in workers) - now - if tmout > 5: # Wait at most 5 seconds - tmout = 5 + tmout = min(tmout, 5) rlist, _, _, _ = sel.pselect(rlist, timeout=tmout) # Read messages diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index c993cab86db..f6ffb67d832 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -1095,9 +1095,7 @@ def coshdelta(z): red_g = f.conjugate(M*MG) if G != pts_poly: R2 = get_bound_dynamical(G, red_g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) - if R2 < R: - # use the better bound - R = R2 + R = min(R2, R) red_g.normalize_coordinates() if red_g.global_height(prec=prec) == 0: return [red_g, M*MG] @@ -1134,8 +1132,7 @@ def coshdelta(z): if new_size == 1: # early exit return [current_min[1], current_min[4]] new_R = get_bound_dynamical(G, g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) - if new_R < R: - R = new_R + R = min(new_R, R) # add new points to check if label != 1 and min((rep+1).norm(), (rep-1).norm()) >= 1: # don't undo S diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 42f0a304436..262c063a35d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2120,8 +2120,7 @@ def green_function(self, P, v, **kwds): h = max([(Res*c).local_height_arch(vindex, prec=prec) for c in poly.coefficients()]) else: #non-archimedean h = max([c.local_height(v, prec=prec) for c in poly.coefficients()]) - if h > maxh: - maxh = h + maxh = max(h, maxh) if maxh == 0: maxh = 1 #avoid division by 0 if isinstance(v, RingHomomorphism_im_gens): #archimedean @@ -2334,8 +2333,7 @@ def canonical_height(self, P, **kwds): if err is not None: err = err / 2 N = ceil((R(Res).log().log() - R(d-1).log() - R(err).log())/(R(d).log())) - if N < 1: - N = 1 + N = max(N, 1) kwds.update({'error_bound': err}) kwds.update({'N': N}) for n in range(N): diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index eb5c6665c0d..717f0c5b763 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -123,7 +123,7 @@ sage: maxima(hypergeometric([1, 1, 1], [3, 3, 3], x)) # needs sage.symbolic hypergeometric([1,1,1],[3,3,3],_SAGE_VAR_x) - sage: hypergeometric((5, 4), (4, 4), 3)._sympy_() # needs sympy sage.symbolic + sage: hypergeometric((5,), (4,), 3)._sympy_() # needs sympy sage.symbolic hyper((5,), (4,), 3) sage: hypergeometric((5, 4), (4, 4), 3)._mathematica_init_() # needs sage.symbolic 'HypergeometricPFQ[{5,4},{4,4},3]' @@ -295,6 +295,11 @@ def __call__(self, a, b, z, **kwargs): The only simplification that is done automatically is returning 1 if ``z`` is 0. For other simplifications use the ``simplify_hypergeometric`` method. + + TESTS:: + + sage: hypergeometric([2, 3, 4], [4, 1], 1) + hypergeometric((2, 3, 4), (4, 1), 1) """ return BuiltinFunction.__call__(self, SR._force_pyobject(a), @@ -458,23 +463,21 @@ def eliminate_parameters(self, a, b, z): """ aa = list(a) # tuples are immutable bb = list(b) - p = pp = len(aa) q = qq = len(bb) i = 0 while i < qq and aa: - bbb = bb[i] - if bbb in aa: - aa.remove(bbb) - bb.remove(bbb) - pp -= 1 + bbi = bb[i] + if bbi in aa: + aa.remove(bbi) + bb.remove(bbi) qq -= 1 else: i += 1 - if (pp, qq) != (p, q): + if qq != q: return hypergeometric(aa, bb, z) return self - def is_termwise_finite(self, a, b, z): + def is_termwise_finite(self, a, b, z) -> bool: """ Determine whether all terms of ``self`` are finite. @@ -516,8 +519,6 @@ def is_termwise_finite(self, a, b, z): return 0 not in b if abs(z) == Infinity: return False - if abs(z) == Infinity: - return False for bb in b: if bb in ZZ and bb <= 0: if any((aa in ZZ) and (bb < aa <= 0) for aa in a): diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index d7e317ba615..6fa011434d8 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -147,7 +147,7 @@ def __call__(self, x): """ return self._eval(x)[0] - def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds): + def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds): """ Plot of (absolute values of) Fast Fourier Transform of the spike function with given number of samples. @@ -166,7 +166,7 @@ def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds): k = vector(RDF, [abs(z[i]) for i in range(len(z)//2)]) return k.plot(xmin=0, xmax=1, **kwds) - def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds): + def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds): """ Plot of (absolute values of) Fast Fourier Transform of the spike function with given number of samples. diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 17f58378373..9afd0e3f02f 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -1986,7 +1986,7 @@ def _some_elements_(self): """ V = self.ambient_vector_space() r_iter = iter(self._rays) - p = V(0) + p = V.zero() yield p for i in range(5): try: @@ -1995,7 +1995,7 @@ def _some_elements_(self): return yield p - def _sort_faces(self, faces): + def _sort_faces(self, faces): r""" Return sorted (if necessary) ``faces`` as a tuple. @@ -2109,7 +2109,7 @@ def adjacent(self): if superfaces: for superface in superfaces: for facet in facets: - adjacent.update(L.open_interval(facet, superface)) + adjacent.update(L.open_interval(facet, superface)) if adjacent: adjacent.remove(L(self)) return self._sort_faces(adjacent) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 67f6e74ea89..ab4146e89ca 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -1327,7 +1327,7 @@ def _repr_(self): parts.extend(["face of", str(self.ambient())]) return " ".join(parts) - def _sort_faces(self, faces): + def _sort_faces(self, faces): r""" Return sorted (if necessary) ``faces`` as a tuple. @@ -1402,7 +1402,7 @@ def adjacent(self): adjacent = set() for superface in self.facet_of(): for facet in self.facets(): - adjacent.update(L.open_interval(facet, superface)) + adjacent.update(L.open_interval(facet, superface)) adjacent.discard(self) return self._sort_faces(adjacent) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 5e7d99e7587..539e2021f88 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2074,8 +2074,7 @@ def add_cell(self, cell): raise ValueError("the cell is not face-to-face with complex") # update dim and maximal cells d = cell.dimension() - if d > self._dim: - self._dim = d + self._dim = max(d, self._dim) maximal_cells = poset.maximal_elements() # a list self._maximal_cells = cells_list_to_cells_dict(maximal_cells) # update convexity if self was known to be convex, reset otherwise. diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index f461b041bae..9b497b421ac 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -717,11 +717,11 @@ def _test_polymake_pickling(self, tester=None, other=None, **options): P = self._polymake_polytope P1 = other._polymake_polytope - tester.assertEqual(P.F_VECTOR, P1.F_VECTOR) - tester.assertEqual(P.VERTICES, P1.VERTICES) + tester.assertEqual(P.F_VECTOR, P1.F_VECTOR) + tester.assertEqual(P.VERTICES, P1.VERTICES) tester.assertEqual(P.LINEALITY_SPACE, P1.LINEALITY_SPACE) - tester.assertEqual(P.FACETS, P1.FACETS) - tester.assertEqual(P.AFFINE_HULL, P1.AFFINE_HULL) + tester.assertEqual(P.FACETS, P1.FACETS) + tester.assertEqual(P.AFFINE_HULL, P1.AFFINE_HULL) ######################################################################### class Polyhedron_QQ_polymake(Polyhedron_polymake, Polyhedron_QQ): diff --git a/src/sage/geometry/polyhedron/generating_function.py b/src/sage/geometry/polyhedron/generating_function.py index 936c761273d..16200bf6616 100644 --- a/src/sage/geometry/polyhedron/generating_function.py +++ b/src/sage/geometry/polyhedron/generating_function.py @@ -535,7 +535,7 @@ def ieqs_repr_lhs(pi): ieqs, repr_rhss = zip(*[(ieq(a, b), ieq_repr_rhs(a, b)) for a, b in zip(pi[:-1], pi[1:])]) - return Polyhedron(ieqs=ieqs), ieqs_repr_lhs(pi) + ''.join(repr_rhss) + return Polyhedron(ieqs=ieqs), ieqs_repr_lhs(pi) + ''.join(repr_rhss) split = (polyhedron_from_permutation(pi) for pi in Permutations(d)) parts = ZZ(d).factorial() diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 589be12b21d..398903fc76a 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -301,14 +301,12 @@ def adjust_options(self): for key in ["xmin", "ymin", "zmin"]: if round or sd[key] is None: sd[key] = - r - if sd[key] > - 0.5: - sd[key] = - 0.5 + sd[key] = min(sd[key], - 0.5) sd[key] = RDF(sd[key]) for key in ["xmax", "ymax", "zmax"]: if round or sd[key] is None: sd[key] = r - if sd[key] < 0.5: - sd[key] = 0.5 + sd[key] = max(sd[key], 0.5) sd[key] = RDF(sd[key]) if self.show_lattice is None: self.show_lattice = (r <= 5) if d <= 2 else r <= 3 diff --git a/src/sage/graphs/asteroidal_triples.pyx b/src/sage/graphs/asteroidal_triples.pyx index 2056aa3d32c..7c904f777f3 100644 --- a/src/sage/graphs/asteroidal_triples.pyx +++ b/src/sage/graphs/asteroidal_triples.pyx @@ -147,8 +147,7 @@ def is_asteroidal_triple_free(G, certificate=False): # module sage.graphs.base.static_sparse_graph cdef list int_to_vertex = list(G) cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef bitset_t seen bitset_init(seen, n) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 9e4983ab718..e51fc238ac5 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -425,7 +425,7 @@ cdef class StaticSparseCGraph(CGraph): cdef class StaticSparseBackend(CGraphBackend): - def __init__(self, G, loops=False, multiedges=False): + def __init__(self, G, loops=False, multiedges=False, sort=True): """ A graph :mod:`backend ` for static sparse graphs. @@ -511,10 +511,11 @@ cdef class StaticSparseBackend(CGraphBackend): True """ vertices = list(G) - try: - vertices.sort() - except TypeError: - pass + if sort: + try: + vertices.sort() + except TypeError: + pass cdef StaticSparseCGraph cg = StaticSparseCGraph(G, vertices) self._cg = cg diff --git a/src/sage/graphs/base/static_sparse_graph.pxd b/src/sage/graphs/base/static_sparse_graph.pxd index 03adfe11322..6cb9e53f17d 100644 --- a/src/sage/graphs/base/static_sparse_graph.pxd +++ b/src/sage/graphs/base/static_sparse_graph.pxd @@ -7,27 +7,19 @@ ctypedef unsigned int uint cdef extern from "stdlib.h": ctypedef void const_void "const void" - void qsort(void *base, int nmemb, int size, - int(*compar)(const_void *, const_void *)) nogil - void *bsearch(const_void *key, const_void *base, size_t nmemb, size_t size, int(*compar)(const_void *, const_void *)) nogil -cdef extern from "search.h": - void *lfind(const_void *key, const_void *base, size_t *nmemb, - size_t size, int(*compar)(const_void *, const_void *)) nogil - ctypedef struct short_digraph_s: uint32_t * edges uint32_t ** neighbors PyObject * edge_labels int m int n - bint sorted_neighbors ctypedef short_digraph_s short_digraph[1] -cdef int init_short_digraph(short_digraph g, G, edge_labelled=?, vertex_list=?, sort_neighbors=?) except -1 +cdef int init_short_digraph(short_digraph g, G, edge_labelled=?, vertex_list=?) except -1 cdef void free_short_digraph(short_digraph g) noexcept cdef int init_reverse(short_digraph dst, short_digraph src) except -1 cdef int out_degree(short_digraph g, int u) noexcept diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 3bd7c9c9285..c27f0d9a8cc 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -47,6 +47,9 @@ five fields from `0` to `n-1`) is present so that it remains easy to enumerate the neighbors of vertex `n-1` : the last of them is the element addressed by ``neighbors[n]-1``. + The arrays ``neighbors[i]`` are guaranteed to be sorted so the time + complexity for deciding if ``g`` has edge `(u, v)` is `O(\log{m})` using + binary search. - ``edge_labels`` -- list; this cython list associates a label to each edge of the graph. If a given edge is represented by ``edges[i]``, this its @@ -116,7 +119,7 @@ Cython functions :widths: 30, 70 :delim: | - ``init_short_digraph(short_digraph g, G, edge_labelled, vertex_list, sort_neighbors)`` | Initialize ``short_digraph g`` from a Sage (Di)Graph. + ``init_short_digraph(short_digraph g, G, edge_labelled, vertex_list)`` | Initialize ``short_digraph g`` from a Sage (Di)Graph. ``int n_edges(short_digraph g)`` | Return the number of edges in ``g`` ``int out_degree(short_digraph g, int i)`` | Return the out-degree of vertex `i` in ``g`` ``has_edge(short_digraph g, int u, int v)`` | Test the existence of an edge. @@ -187,10 +190,10 @@ from libc.math cimport sqrt from libcpp.vector cimport vector from cysignals.memory cimport check_allocarray, check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off +from cython.operator cimport postincrement from memory_allocator cimport MemoryAllocator from sage.data_structures.bitset_base cimport * -from sage.graphs.base.c_graph cimport CGraph from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend @@ -205,7 +208,7 @@ cdef extern from "fenv.h": cdef int init_short_digraph(short_digraph g, G, edge_labelled=False, - vertex_list=None, sort_neighbors=True) except -1: + vertex_list=None) except -1: r""" Initialize ``short_digraph g`` from a Sage (Di)Graph. @@ -223,63 +226,78 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled=False, - ``vertex_list`` -- list (default: ``None``); list of all vertices of ``G`` in some order. When given, it is used to map the vertices of the graph to consecutive integers. Otherwise, the result of ``list(G)`` is used - instead. - - - ``sort_neighbors`` -- boolean (default: ``True``); whether to ensure that - the vertices in the list of neighbors of a vertex are sorted by increasing - vertex labels. This choice may have a non-negligeable impact on the time - complexity of some methods. More precisely: - - - When set to ``True``, the time complexity for initializing ``g`` is in - `O(n + m\log{m})` for ``SparseGraph`` and `O(n^2\log{m})` for - ``DenseGraph``, and deciding if ``g`` has edge `(u, v)` can be done in - time `O(\log{m})` using binary search. - - - When set to ``False``, the time complexity for initializing ``g`` is - reduced to `O(n + m)` for ``SparseGraph`` and `O(n^2)` for - ``DenseGraph``, but the time complexity for deciding if ``g`` has - edge `(u, v)` increases to `O(m)`. - """ - g.edge_labels = NULL + instead. Beware that if ``vertex_list`` is not ``None``, it is not checked + and this function assumes that it contains a permutation of the vertices + of the graph ``G``. - if G.order() >= INT_MAX: - raise ValueError("this structure can handle at most " + str(INT_MAX) + " vertices") - else: - g.n = G.order() + COMPLEXITY: - cdef int isdigraph + The time complexity for initializing ``g`` is `O(n + m)` for ``SparseGraph`` + and `O(n^2)` for ``DenseGraph``. + TESTS: + + Indirect doctests for sorted output:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: G = graphs.CompleteGraph(5).relabel(list('abcde'), inplace=False) + sage: B = StaticSparseBackend(G, sort=False) + sage: list(B.iterator_nbrs('a')) + ['b', 'c', 'd', 'e'] + sage: G = graphs.CompleteGraph(5).relabel(list('badec'), inplace=False) + sage: B = StaticSparseBackend(G, sort=False) + sage: list(B.iterator_nbrs('a')) + ['b', 'd', 'e', 'c'] + + Same with labels:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: G = graphs.CompleteGraph(5).relabel(list('abcde'), inplace=False) + sage: for i, (u, v, _) in enumerate(G.edges()): + ....: G.set_edge_label(u, v, f'{u}{v}') + sage: B = StaticSparseBackend(G, sort=False) + sage: list(B.iterator_edges('a', True)) + [('a', 'b', 'ab'), ('a', 'c', 'ac'), ('a', 'd', 'ad'), ('a', 'e', 'ae')] + sage: G = graphs.CompleteGraph(5).relabel(list('badec'), inplace=False) + sage: for i, (u, v, _) in enumerate(G.edges()): + ....: G.set_edge_label(u, v, f'{u}{v}') + sage: B = StaticSparseBackend(G, sort=False) + sage: list(B.iterator_edges('a', True)) + [('a', 'b', 'ab'), ('a', 'd', 'ad'), ('a', 'e', 'ae'), ('a', 'c', 'ac')] + """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph - if isinstance(G, DiGraph): - isdigraph = 1 - elif isinstance(G, Graph): - isdigraph = 0 - else: - raise ValueError("The source graph must be either a DiGraph or a Graph object !") + if not isinstance(G, (Graph, DiGraph)): + raise ValueError("The source graph must be either a DiGraph or a Graph" + "object !") - cdef int i, j, v_id + if G.order() >= INT_MAX: + raise ValueError(f"short_digraph can handle at most {INT_MAX} vertices") + + g.edge_labels = NULL + g.n = G.order() + g.m = G.size() + + cdef int isdigraph = G.is_directed() + cdef uint32_t i, v_id, j cdef list vertices = vertex_list if vertex_list is not None else list(G) cdef dict v_to_id = {v: i for i, v in enumerate(vertices)} cdef list neighbor_label cdef list edge_labels - - g.m = G.size() - cdef int n_edges = g.m if isdigraph else 2*g.m + # Loops are not stored twice for undirected graphs + cdef int n_edges = g.m if isdigraph else 2*g.m - G.number_of_loops() g.edges = check_allocarray(n_edges, sizeof(uint32_t)) g.neighbors = check_allocarray(1 + g.n, sizeof(uint32_t *)) # Initializing the value of neighbors g.neighbors[0] = g.edges - cdef CGraph cg = G._backend - g.sorted_neighbors = sort_neighbors if not G.has_loops(): # Normal case - for i in range(1, (g.n) + 1): - g.neighbors[i] = g.neighbors[i - 1] + (cg.out_degree(vertices[i - 1]) if isdigraph else G.degree(vertices[i - 1])) + for i, v in enumerate(vertices): + g.neighbors[i+1] = g.neighbors[i] + (G.out_degree(v) if isdigraph else G.degree(v)) else: # In the presence of loops. For a funny reason, if a vertex v has a loop # attached to it and no other incident edge, Sage declares that it has @@ -287,55 +305,40 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled=False, # the number of edges, but then the degree of a vertex is not the number # of its neighbors anymore. One should never try to think. It never ends # well. - for i in range(1, (g.n) + 1): - g.neighbors[i] = g.neighbors[i - 1] + len(G.edges_incident(vertices[i - 1])) - - if not edge_labelled: - for u, v in G.edge_iterator(labels=False, sort_vertices=False): - i = v_to_id[u] - j = v_to_id[v] - - g.neighbors[i][0] = j - g.neighbors[i] += 1 + for i, v in enumerate(vertices): + g.neighbors[i+1] = g.neighbors[i] + len(G.edges_incident(v)) - if not isdigraph and i != j: - g.neighbors[j][0] = i - g.neighbors[j] += 1 - - # Reinitializing the value of neighbors - for i in range(g.n - 1, 0, -1): - g.neighbors[i] = g.neighbors[i - 1] - - g.neighbors[0] = g.edges - - if sort_neighbors: - # Sorting the neighbors - for i in range(g.n): - qsort(g.neighbors[i], g.neighbors[i + 1] - g.neighbors[i], sizeof(int), compare_uint32_p) - - else: - from operator import itemgetter + if edge_labelled: edge_labels = [None] * n_edges - if sort_neighbors: - for v in G: - neighbor_label = [(v_to_id[uu], l) if uu != v else (v_to_id[u], l) - for u, uu, l in G.edges_incident(v)] - neighbor_label.sort(key=itemgetter(0)) - v_id = v_to_id[v] - - for i, (j, label) in enumerate(neighbor_label): - g.neighbors[v_id][i] = j - edge_labels[(g.neighbors[v_id] + i) - g.edges] = label + + # Note that neighbors[i] will be naturally sorted by increasing id, + # because the arrays will be built by appending vertices in the same + # order as they appear in ``vertices`` + for i, v in enumerate(vertices): + if isdigraph: + edge_iterator = G.incoming_edge_iterator(v, + labels=edge_labelled) else: - for v in G: - v_id = v_to_id[v] - for i, (u, uu, label) in enumerate(G.edges_incident(v)): - if v == uu: - g.neighbors[v_id][i] = v_to_id[u] - else: - g.neighbors[v_id][i] = v_to_id[uu] - edge_labels[(g.neighbors[v_id] + i) - g.edges] = label + edge_iterator = G.edge_iterator(v, labels=edge_labelled, + sort_vertices=False) + for e in edge_iterator: + u = e[0] if v == e[1] else e[1] + j = v_to_id[u] + # Handle the edge u -> v of G (= the edge j -> i of g) + g.neighbors[j][0] = i + # Note: cannot use the dereference Cython operator here, do not + # known why but the following line does not compile + #dereference(g.neighbors[j]) = i + if edge_labelled: + edge_labels[g.neighbors[j] - g.edges] = e[2] + postincrement(g.neighbors[j]) # increment pointer to next item + + # Reinitializing the value of neighbors + for i in range(g.n-1, 0, -1): + g.neighbors[i] = g.neighbors[i-1] + g.neighbors[0] = g.edges + if edge_labelled: g.edge_labels = edge_labels cpython.Py_XINCREF(g.edge_labels) @@ -365,7 +368,6 @@ cdef int init_empty_copy(short_digraph dst, short_digraph src) except -1: """ dst.n = src.n dst.m = src.m - dst.sorted_neighbors = src.sorted_neighbors dst.edge_labels = NULL cdef list edge_labels @@ -382,6 +384,24 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: """ Initialize ``dst`` to a copy of ``src`` with all edges in the opposite direction. + + TESTS: + + Indirect doctests for sorted output:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: D = digraphs.Complete(5).relabel(list('abcde'), inplace=False) + sage: for i, (u, v, _) in enumerate(D.edges()): + ....: D.set_edge_label(u, v, f'{u}{v}') + sage: B = StaticSparseBackend(D, sort=False) + sage: list(B.iterator_in_edges('a', True)) + [('b', 'a', 'ba'), ('c', 'a', 'ca'), ('d', 'a', 'da'), ('e', 'a', 'ea')] + sage: D = digraphs.Complete(5).relabel(list('badec'), inplace=False) + sage: for i, (u, v, _) in enumerate(D.edges()): + ....: D.set_edge_label(u, v, f'{u}{v}') + sage: B = StaticSparseBackend(D, sort=False) + sage: list(B.iterator_in_edges('a', True)) + [('b', 'a', 'ba'), ('d', 'a', 'da'), ('e', 'a', 'ea'), ('c', 'a', 'ca')] """ cdef int i, j, v # Allocates memory for dst @@ -391,7 +411,7 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: if not dst.n: return 0 - # 1/4 + # 1/3 # # In a first pass, we count the in-degrees of each vertex and store it in a # vector. With this information, we can initialize dst.neighbors to its @@ -407,11 +427,14 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: dst.neighbors[i] = dst.neighbors[i - 1] + in_degree[i - 1] sig_free(in_degree) - # 2/4 + # 2/3 # # Second pass : we list the edges again, and add them in dst.edges. Doing # so, we will change the value of dst.neighbors, but that is not so bad as # we can fix it afterwards. + # Note that neighbors[i] will be naturally sorted by increasing id, + # because the arrays will be built by appending vertices in the same + # order as they appear in ``vertices`` for i in range(0, src.n): for j in range(out_degree(src, i)): v = src.neighbors[i][j] @@ -422,7 +445,7 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: dst.neighbors[v] += 1 - # 3/4 + # 3/3 # # Third step : set the correct values of dst.neighbors again. It is easy, as # the correct value of dst.neighbors[i] is actually dst.neighbors[i-1] @@ -430,20 +453,12 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: dst.neighbors[i] = dst.neighbors[i - 1] dst.neighbors[0] = dst.edges - # 4/4 - # - # Final step : if the neighbors of src are assumed to be sorted by - # increasing labels, we do the same for dst. - if src.sorted_neighbors: - for i in range(dst.n): - qsort(dst.neighbors[i], dst.neighbors[i + 1] - dst.neighbors[i], sizeof(int), compare_uint32_p) - return 0 cdef int compare_uint32_p(const_void *a, const_void *b) noexcept: """ - Comparison function needed for ``bsearch`` and ``lfind``. + Comparison function needed for ``bsearch``. """ return ( a)[0] - ( b)[0] @@ -454,17 +469,16 @@ cdef inline uint32_t * has_edge(short_digraph g, int u, int v) noexcept: Return a pointer to ``v`` in the list of neighbors of ``u`` if found and ``NULL`` otherwise. - """ - if g.sorted_neighbors: - # The neighbors of u are sorted by increasing label. We can use binary - # search to decide if g has edge (u, v) - return bsearch(&v, g.neighbors[u], g.neighbors[u + 1] - g.neighbors[u], - sizeof(uint32_t), compare_uint32_p) - # Otherwise, we use the linear time lfind method - cdef size_t nelem = g.neighbors[u + 1] - g.neighbors[u] - return lfind(&v, g.neighbors[u], &nelem, - sizeof(uint32_t), compare_uint32_p) + .. NOTE:: + + Use the fact that the array ``g.neighbors[u]`` is guaranteed to be sorted. + """ + # The neighbors of u are sorted by increasing label. We can use binary + # search to decide if g has edge (u, v) + return bsearch(&v, g.neighbors[u], + g.neighbors[u+1] - g.neighbors[u], + sizeof(uint32_t), compare_uint32_p) cdef inline object edge_label(short_digraph g, uint32_t * edge): @@ -797,7 +811,7 @@ def tarjan_strongly_connected_components(G): cdef MemoryAllocator mem = MemoryAllocator() cdef list int_to_vertex = list(G) cdef short_digraph g - init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex, sort_neighbors=False) + init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex) cdef int * scc = mem.malloc(g.n * sizeof(int)) sig_on() cdef int nscc = tarjan_strongly_connected_components_C(g, scc) @@ -914,7 +928,7 @@ def strongly_connected_components_digraph(G): cdef MemoryAllocator mem = MemoryAllocator() cdef list int_to_vertex = list(G) cdef short_digraph g, scc_g - init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex, sort_neighbors=False) + init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex) cdef int * scc = mem.malloc(g.n * sizeof(int)) cdef int i, j, nscc cdef list edges = [] @@ -979,7 +993,7 @@ def triangles_count(G): # g is a copy of G. If G is internally a static sparse graph, we use it. cdef list int_to_vertex = list(G) cdef short_digraph g - init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex, sort_neighbors=True) + init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex) cdef uint64_t * count = check_calloc(G.order(), sizeof(uint64_t)) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index b3165b69232..e249046ae70 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -178,7 +178,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, bint normalize=True): mpq_init(mpq_tmp) try: - init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex, sort_neighbors=False) + init_short_digraph(g, G, edge_labelled=False, vertex_list=int_to_vertex) init_reverse(bfs_dag, g) queue = check_allocarray(n, sizeof(uint32_t)) @@ -689,7 +689,7 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph cdef list V = list(G) - init_short_digraph(sd, G, edge_labelled=False, vertex_list=V, sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=V) cdef int n = sd.n cdef int* reachL = mem.malloc(n * sizeof(int)) cdef int* reachU @@ -939,7 +939,7 @@ def centrality_closeness_random_k(G, int k=1): # Copying the whole graph as a static_sparse_graph for fast shortest # paths computation in unweighted graph. This data structure is well # documented in module sage.graphs.base.static_sparse_graph - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) distance = mem.malloc(n * sizeof(uint32_t)) waiting_list = mem.malloc(n * sizeof(uint32_t)) bitset_init(seen, n) diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx index a51c3db0102..f292cae3eed 100644 --- a/src/sage/graphs/convexity_properties.pyx +++ b/src/sage/graphs/convexity_properties.pyx @@ -506,11 +506,9 @@ def geodetic_closure(G, S): each vertex `u \in S`, the algorithm first performs a breadth first search from `u` to get distances, and then identifies the vertices of `G` lying on a shortest path from `u` to any `v\in S` using a reversal traversal from - vertices in `S`. This algorithm has time complexity in - `O(|S|(n + m) + (n + m\log{m}))` for ``SparseGraph``, - `O(|S|(n + m) + n^2\log{m})` for ``DenseGraph`` and space complexity in - `O(n + m)` (the extra `\log` factor is due to ``init_short_digraph`` being - called with ``sort_neighbors=True``). + vertices in `S`. This algorithm has time complexity in `O(|S|(n + m))` for + ``SparseGraph``, `O(|S|(n + m) + n^2)` for ``DenseGraph`` and + space complexity in `O(n + m)`. INPUT: @@ -757,7 +755,7 @@ def is_geodetic(G): # Copy the graph as a short digraph cdef int n = G.order() cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G), sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G)) # Allocate some data structures cdef MemoryAllocator mem = MemoryAllocator() diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index 3ff37a8d918..07845559dc4 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -49,6 +49,7 @@ - Emily A. Kirkman (2006) - Michael C. Yurko (2009) - David Coudert (2012) +- Janmenjaya Panda (2024) Functions and methods --------------------- @@ -58,6 +59,7 @@ # and Emily A. Kirkman # Copyright (C) 2009 Michael C. Yurko # Copyright (C) 2012 David Coudert +# Copyright (C) 2024 Janmenjaya Panda # # 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 @@ -891,6 +893,9 @@ def Circulant(self, n, integers): r""" Return a circulant digraph on `n` vertices from a set of integers. + A circulant digraph of order `n` has an arc from vertex `i` to + vertex `i+j \pmod{n}`, for each `j` in ``integers``. + INPUT: - ``n`` -- integer; number of vertices @@ -899,18 +904,30 @@ def Circulant(self, n, integers): that there is an edge from `i` to `j` if and only if `(j-i) \pmod{n}` is an integer - EXAMPLES:: + EXAMPLES: - sage: digraphs.Circulant(13,[3,5,7]) - Circulant graph ([3, 5, 7]): Digraph on 13 vertices + Construct and show the circulant graph [3, 5, 7], a digraph on 13 + vertices:: - TESTS:: + sage: g = digraphs.Circulant(13, [3, 5, 7]) + sage: g.show() # long time # needs sage.plot + + The Koh-Tindell digraph [LM2024]_ is the circulant digraph of order 7 + with parameters `[1, 5]`. This `2`-diregular digraph is + vertex-transitive but not arc-transitive. The associated bipartite + digraph of the Koh-Tindell digraph is a Pfaffian orientation of the + Heawood graph. Construct and show the Koh-Tindell digraph:: + + sage: kohTindellDigraph = digraphs.Circulant(7, [1, 5]) + sage: kohTindellDigraph.show() # long time # needs sage.plot + + TESTS: - sage: digraphs.Circulant(13,[3,5,7,"hey"]) + sage: digraphs.Circulant(13, [3, 5, 7, "hey"]) Traceback (most recent call last): ... ValueError: the list must contain only integers - sage: digraphs.Circulant(3,[3,5,7,3.4]) + sage: digraphs.Circulant(3, [3, 5, 7, 3.4]) Traceback (most recent call last): ... ValueError: the list must contain only integers diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 63ad747ebd9..23d2e1c79d7 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -304,8 +304,7 @@ cdef inline all_pairs_shortest_path_BFS(gg, # Copying the whole graph to obtain the list of neighbors quicker than by # calling out_neighbors cdef short_digraph sd - init_short_digraph(sd, gg, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, gg, edge_labelled=False, vertex_list=int_to_vertex) c_all_pairs_shortest_path_BFS(sd, predecessors, distances, eccentricity) @@ -1057,8 +1056,7 @@ def eccentricity(G, algorithm='standard', vertex_list=None): ecc = c_eccentricity(G, vertex_list=int_to_vertex) else: - init_short_digraph(sd, G, edge_labelled=False, vertex_list=vertex_list, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=vertex_list) if algorithm == "DHV": ecc = c_eccentricity_DHV(sd) @@ -1836,8 +1834,7 @@ def diameter(G, algorithm=None, source=None): # module sage.graphs.base.static_sparse_graph cdef list int_to_vertex = list(G) cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef short_digraph rev_sd # to store copy of sd with edges reversed # and we map the source to an int in [0,n-1] @@ -1939,8 +1936,7 @@ def radius_DHV(G): cdef list int_to_vertex = list(G) cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef uint32_t source, ecc_source cdef uint32_t antipode, ecc_antipode @@ -2057,8 +2053,7 @@ def wiener_index(G): # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G), - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G)) # allocated some data structures cdef bitset_t seen @@ -2280,14 +2275,6 @@ def szeged_index(G, algorithm=None): By default (``None``), the ``'low'`` algorithm is used for graphs and the ``'high'`` algorithm for digraphs. - .. NOTE:: - As the graph is converted to a short_digraph, the complexity for the - case ``algorithm == "high"`` has an extra `O(m+n)` for ``SparseGraph`` - and `O(n^2)` for ``DenseGraph``. If ``algorithm == "low"``, the extra - complexity is `O(n + m\log{m})` for ``SparseGraph`` and `O(n^2\log{m})` - for ``DenseGraph`` (because ``init_short_digraph`` is called with - ``sort_neighbors=True``). - EXAMPLES: True for any connected graph [KRG1996]_:: @@ -2378,13 +2365,12 @@ def szeged_index(G, algorithm=None): return 0 cdef short_digraph sd + init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G)) cdef uint64_t s if algorithm == "low": - init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G), sort_neighbors=True) s = c_szeged_index_low_memory(sd) else: - init_short_digraph(sd, G, edge_labelled=False, vertex_list=list(G), sort_neighbors=False) s = c_szeged_index_high_memory(sd) free_short_digraph(sd) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index aa10d15d4d8..74e7dd01f28 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -4197,9 +4197,9 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): from sage.rings.integer_ring import ZZ from time import time - assert d > 1, 'd must be at least 2' + assert d > 1, 'd must be at least 2' assert is_even(n * (d-1)), 'n must be even or d must be odd' - assert is_prime_power(n), 'n must be a prime power' + assert is_prime_power(n), 'n must be a prime power' t = time() # build L, L_i and the design @@ -4741,4 +4741,4 @@ def TruncatedBiwheelGraph(n): G.add_path(list(range(2*n - 2))) G.add_edges(edges) - return G \ No newline at end of file + return G diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 79753f418fd..d490eda7830 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -7,6 +7,7 @@ # Copyright (C) 2006 Robert L. Miller # and Emily A. Kirkman # Copyright (C) 2009 Michael C. Yurko +# Copyright (C) 2024 Janmenjaya Panda # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -1898,6 +1899,168 @@ def CoxeterGraph(): return g +def CubeplexGraph(embedding='LM'): + r""" + Return the Cubeplex graph. + + The Cubeplex graph is the cubic hamiltonian graph of order 12 that + corresponds to the graph labeled as `\Gamma_1` in Fischer and Little + [FiLi2001]_. It has LCF notation `[-6, -5, -3, -6, 3, 5, -6, -3, 5, -6, -5, + 3]`. + + The Fischer-Little Theorem [FiLi2001]_ may be stated as follows [LM2024]_: + + A near-bipartite graph is non-Pfaffian if and only if it contains one of + the graphs `K_{3, 3}`, `\Gamma_1` and `\Gamma_2` as an `S`-minor. + + Norine and Thomas [NT2007]_ use the term ``Cubeplex`` to describe one of + the 12-vertex cubic graphs, `\Gamma_1` and `\Gamma_2`, as defined by + Fischer and Little [FiLi2001]_. However, the figure in their paper that + supposedly provides embeddings for the graphs labeled Cubeplex and Twinplex + actually shows both embeddings corresponding to Fischer and Little's + `\Gamma_1`, which is the Cubeplex graph. Followingly, for + ``embedding='NT'``, we present only the embedding that is shown by the + labeling ``Cubeplex`` in the paper of Norine and Thomas [NT2007]_. + + PLOTTING: + + Upon construction, the position dictionary is filled to override + the spring-layout algorithm. For different values of the parameter + ``embedding``, the Cubeplex graph is displayed as it is mentioned in the + respective paper/ book. + + INPUT: + + - ``embedding`` -- string (default: ``'LM'``) + + - ``'LM'`` displays the embedding as shown for `\Gamma_1` by Lucchesi and + Murty [LM2024]_ + + - ``'FL'`` displays the embedding as shown for `\Gamma_1` by Fischer and + Little [FiLi2001]_ + + - ``'NT'`` displays the embedding as shown for the ``Cubeplex`` by Norine + and Thomas [NT2007]_ + + OUTPUT: + + - ``G`` -- the Cubeplex graph; note that a :class:`ValueError` is returned + if ``embedding`` is none of ``'FT'``, ``'NT'`` or ``'LM'`` + + EXAMPLES: + + Construct and show the Cubeplex graph:: + + sage: g = graphs.CubeplexGraph() + sage: g.name() + 'Cubeplex Graph' + sage: g.order() + 12 + sage: g.size() + 18 + sage: g.girth() + 4 + sage: g.diameter() + 3 + sage: g.is_hamiltonian() + True + sage: g.crossing_number() + 1 + sage: g.show() # long time # needs sage.plot + + TESTS: + + Note that all three embeddings refer to the same graph, the Cubeplex graph, + aka `\Gamma_1`:: + + sage: fl = graphs.CubeplexGraph(embedding='FL') + sage: nt = graphs.CubeplexGraph(embedding='NT') + sage: lm = graphs.CubeplexGraph(embedding='LM') + sage: fl.is_isomorphic(nt) and fl.is_isomorphic(lm) + True + + The input parameter must be one of 'FL', 'NT' or 'LM':: + + sage: g = graphs.CubeplexGraph(embedding='embedding') + Traceback (most recent call last): + ... + ValueError: parameter 'embedding' must be 'FL', 'NT' or 'LM' + + .. SEEALSO:: + + :meth:`~sage.graphs.graph_generators.GraphGenerators.TwinplexGraph` + + AUTHORS: + + - Janmenjaya Panda (2024-08-03) + """ + if embedding == 'FL': + from math import pi + + G = Graph(12, name='Cubeplex Graph') + G.add_cycle(list(range(12))) + + G.add_edges([ + (0, 3), (1, 6), (2, 8), + (4, 9), (5, 11), (7, 10) + ]) + + G._circle_embedding(list(range(12)), angle=2*pi/3) + + elif embedding == 'NT': + pos_dict = { + 0: (1, 2), + 1: (3, 2), + 2: (0, 1), + 3: (1, 1), + 4: (2, 1), + 5: (3, 1), + 6: (4, 1), + 7: (0, -1), + 8: (1, 0), + 9: (2, 0), + 10: (3, 0), + 11: (4, -1), + } + + G = Graph(12, pos=pos_dict, name='Cubeplex Graph') + G.add_edges([ + (0, 2), (0, 4), (0, 6), + (1, 3), (1, 5), (1, 6), + (2, 7), (2, 8), (3, 7), + (3, 8), (4, 9), (4, 10), + (5, 9), (5, 10), (6, 11), + (7, 11), (8, 9), (10, 11) + ]) + + elif embedding == 'LM': + from math import pi + + pos_dict = { + 8: (0, 1), + 9: (1, 0), + 10: (-3*cos(pi/16), -3*sin(pi/16)), + 11: (3*cos(pi/16), -3*sin(pi/16)) + } + + for v in range(8): + t = pi * (v+2)/4 + pos_dict[v] = (-2*cos(t), 2*sin(t)) + + G = Graph(12, pos=pos_dict, name='Cubeplex Graph') + + G.add_cycle(list(range(8))) + G.add_edges([ + (0, 8), (1, 11), (2, 9), (3, 11), (4, 8), + (5, 10), (6, 9), (7, 10), (8, 9), (10, 11) + ]) + + else: + raise ValueError("parameter 'embedding' must be 'FL', 'NT' or 'LM'") + + return G + + def DejterGraph(): r""" Return the Dejter graph. @@ -3813,6 +3976,88 @@ def MoserSpindle(): return Graph(edge_dict, pos=pos_dict, name="Moser spindle") +def MurtyGraph(): + r""" + Return the Murty graph. + + Consider the complete bipartite graph `K_{3, 3}`. There is a set of three + black vertices and a set of three white vertices. Now, consider splicing + the complete graph `K_4` with one of the black vertices, this generates the + graph `K_4 \odot K_{3, 3}`. The Murty graph is obtained from + `K_4 \odot K_{3, 3}` with the addition of an edge joining the remaining two + black vertices. The Murty graph is free of conformal bicycles; in + other words, the Murty graph is an example of a graph that is Birkhoff-von + Neumann as well as PM-compact. + + This is the smallest brick that is Birkhoff-von Neumann, aka a solid + brick, but is not odd-intercyclic. It is in this context that + Prof. U.S.R. Murty first stumbled upon this graph, and it also appears in + the work of Carvalho, Lucchesi, and Murty [CLM2006]_. + + PLOTTING: + + Upon construction, the position dictionary is filled to override + the spring-layout algorithm. By convention, the Murty graph is + displayed as mentioned in the paper [CKWL2019]_, with the first two + (noncubic) vertices on the top row, the second three vertices (that form a + stable set) in the middle row, and the remaining three vertices (that form + a triangle) at the bottom. + + OUTPUT: + + - ``G`` -- the Murty graph + + EXAMPLES: + + Construct and show the Murty graph:: + + sage: g = graphs.MurtyGraph() + sage: g.name() + 'Murty Graph' + sage: g.order() + 8 + sage: g.size() + 13 + sage: g.girth() + 3 + sage: g.diameter() + 2 + sage: g.is_hamiltonian() + True + sage: g.show() # long time # needs sage.plot + + REFERENCES: + + - [CKWL2019]_ + - [CLM2006]_ + - [LM2024]_ + + AUTHORS: + + - Janmenjaya Panda (2024-08-03) + """ + pos_dict = { + 0: (-0.5, sqrt(3)/2), + 1: (0.5, sqrt(3)/2), + 2: (-1, 0), + 3: (0, 0), + 4: (1, 0), + 5: (-0.5, -1 - sqrt(3)/2), + 6: (0, -1), + 7: (0.5, -1 - sqrt(3)/2) + } + + G = Graph(8, pos=pos_dict, name="Murty Graph") + + G.add_edge(0, 1) + for v in range(2, 5): + G.add_edges([(0, v), (1, v), (v, v+3)]) + + G.add_edges([(5, 6), (5, 7), (6, 7)]) + + return G + + def NauruGraph(embedding=2): """ Return the Nauru Graph. @@ -4372,6 +4617,102 @@ def TietzeGraph(): return g +def TricornGraph(): + r""" + Return the Tricorn graph. + + The Tricorn graph is obtained by splicing a complete graph `K_4` with the + the triangular circular ladder graph `\overline{C_6}`. (Note that this + generates a unqiue graph as both of the graphs `K_4` and `\overline{C_6}` + are vertex-transitive). It is a nonsolid brick. This matching covered graph + is one of the ten extremal cubic bricks. (A matching covered graph `G` is + *extremal* if `\Phi(G) = dim(\mathcal{Lin}(G))`, where `\Phi(G)` denotes + the number of perfect matchings of `G`, and `dim(\mathcal{Lin}(G))` stands + for the dimension of the linear space of `G`). + + The Tricorn graph has no removable doubletons and has precisely three + removable edges. The wheel graph `W_5` and the complete graph `K_4` are + matching minors of the Tricorn graph. + + As per a theorem of Lovász [Lov1983]_, each non bipartite matching covered + graph has a conformal subgraph which is either a bi-subdivision of `K_4` or + of `\overline{C_6}` or both. In their paper, Kothari and Murty [KM2015]_ + characterized those planar bricks that are free of `\overline{C_6}` (that + is, the planar bricks that do not contain a bi-subdivision of + `\overline{C_6}` as a conformal subgraph). Besides two infinite families of + matching covered graphs (odd wheel graphs and staircase graphs of order + *4k*), the Tricorn graph is the only exception brick that is simple, planar + and free of `\overline{C_6}`. + + PLOTTING: + + Upon construction, the position dictionary is filled to override + the spring-layout algorithm. By convention, the Tricorn graph is + displayed as mentioned in the book [LM2024]_, with the central vertex being + the `0`-th one. Rest of the nine vertices are shown in groups of three, + one on the top, rest two on the bottom left and on the bottom right + corners respectively. + + OUTPUT: + + - ``G`` -- the Tricorn graph + + EXAMPLES: + + Construct and show the Tricorn graph; note that the edges `(2, 3)`, + `(5, 6)` and `(8, 9)` are the only removable edges of the Tricorn + graph:: + + sage: g = graphs.TricornGraph() + sage: g.name() + 'Tricorn Graph' + sage: g.order() + 10 + sage: g.size() + 15 + sage: g.girth() + 3 + sage: g.diameter() + 3 + sage: g.is_hamiltonian() + True + sage: g.show() # long time # needs sage.plot + + REFERENCES: + + - [KM2015]_ + - [LM2024]_ + - [Lov1983]_ + + AUTHORS: + + - Janmenjaya Panda (2024-08-02) + """ + pos_dict = { + 0: (0, 0), + 1: (0, 1), + 2: (1/2, 1 + sqrt(3)/2), + 3: (-1/2, 1 + sqrt(3)/2), + 4: (-sqrt(3)/2, -1/2), + 5: (-sqrt(3)/2 - 1, -1/2), + 6: (-sqrt(3)/2 - 1/2, -1/2 - sqrt(3)/2), + 7: (sqrt(3)/2, -1/2), + 8: (sqrt(3)/2 + 1/2, -1/2 - sqrt(3)/2), + 9: (sqrt(3)/2 + 1, -1/2) + } + + G = Graph(10, pos=pos_dict, name="Tricorn Graph") + + for v in range(1, 8, 3): + G.add_edges([ + (0, v), (v, v+1), + (v, v+2), (v+1, v+2), + (v+2, int((-v**2 + 7*v + 4)/2)) + ]) + + return G + + def TruncatedIcosidodecahedralGraph(): r""" Return the truncated icosidodecahedron. @@ -4571,6 +4912,204 @@ def TutteGraph(): return g +def TwinplexGraph(embedding='LM'): + r""" + Return the Twinplex graph. + + The Twinplex graph is a cubic hamiltonian graph of order 12 with the graph + crossing number 2 and has a girth 5 (that is the maximal girth among all + cubic graphs on 12 vertices [CHNP2020]_). It corresponds to the graph + labeled as `\Gamma_2` by Fischer and Little [FiLi2001]_. The Twinplex graph + has LCF notation `[-5, -4, 4, -4, 4, 5, -4, 5, -4, 4, -5, 4]`. + + The Fischer-Little Theorem [FiLi2001]_ may be stated as follows [LM2024]_: + + A near-bipartite graph is non-Pfaffian if and only if it contains one of + the graphs `K_{3, 3}`, `\Gamma_1` and `\Gamma_2` as an `S`-minor. + + Norine and Thomas [NT2007]_ use the term ``Twinplex`` to describe one of + the 12-vertex cubic graphs, `\Gamma_1` and `\Gamma_2`, as defined by + Fischer and Little [FiLi2001]_. However, the figure in their paper that + supposedly provides embeddings for the graphs labeled Cubeplex and Twinplex + actually shows both embeddings corresponding to Fischer and Little's + `\Gamma_1`, which is the Cubeplex graph. Followingly, for + ``embedding='NT'``, we present a correct version of the Twinplex graph + with a slight modification of the embedding that is labeled as ``Twinplex`` + in the paper of Norine and Thomas [NT2007]_. + + PLOTTING: + + Upon construction, the position dictionary is filled to override + the spring-layout algorithm. For different values of the parameter + ``embedding``, the Twinplex graph is displayed as it is mentioned in the + respective paper/ book. Note that for ``embedding='NT'``, a correct + embedding of the Twinplex graph is displayed with a minor modification to + the (incorrect) embedding shown in the paper [NT2007]_. + + INPUT: + + - ``embedding`` -- string (default: ``'LM'``) + + - ``'LM'`` displays the embedding as shown for `\Gamma_2` by Lucchesi and + Murty [LM2024]_ + + - ``'FL'`` displays the embedding as shown for `\Gamma_2` by Fischer and + Little [FiLi2001]_ + + - ``'NT'`` displays the correct embedding with a minor modification to + the one shown as the (incorrect) ``Twinplex`` by Norine and Thomas + [NT2007]_ + + - ``'RST'`` displays the embedding as shown for the ``Twinplex`` by + Robertson, Seymour and Thomas [RST2019]_ + + OUTPUT: + + - ``G`` -- the Twinplex graph; note that a :class:`ValueError` is returned + if ``embedding`` is none of ``'FT'``, ``'NT'``, ``'RST'`` or ``'LM'`` + + EXAMPLES: + + Construct and show the Twinplex graph:: + + sage: g = graphs.TwinplexGraph() + sage: g.name() + 'Twinplex Graph' + sage: g.order() + 12 + sage: g.size() + 18 + sage: g.girth() + 5 + sage: g.diameter() + 3 + sage: g.is_hamiltonian() + True + sage: g.crossing_number() + 2 + sage: g.show() # long time # needs sage.plot + + TESTS: + + Note that all four embeddings refer to the same graph, the Twinplex graph, + aka `\Gamma_2`:: + + sage: fl = graphs.TwinplexGraph(embedding='FL') + sage: nt = graphs.TwinplexGraph(embedding='NT') + sage: rst = graphs.TwinplexGraph(embedding='RST') + sage: lm = graphs.TwinplexGraph(embedding='LM') + sage: all(fl.is_isomorphic(g) for g in (nt, rst, lm)) + True + + The input parameter must be one of 'FL', 'NT', 'RST' or 'LM':: + + sage: g = graphs.TwinplexGraph(embedding='embedding') + Traceback (most recent call last): + ... + ValueError: parameter 'embedding' must be 'FL', 'NT', 'LM' or 'RST' + + .. SEEALSO:: + + :meth:`~sage.graphs.graph_generators.GraphGenerators.CubeplexGraph` + + AUTHORS: + + - Janmenjaya Panda (2024-08-03) + """ + if embedding == 'FL': + from math import pi + + G = Graph(12, name='Twinplex Graph') + G.add_cycle(list(range(12))) + + G.add_edges([ + (0, 8), (1, 5), (2, 9), + (3, 7), (4, 11), (6, 10) + ]) + + G._circle_embedding(list(range(12)), angle=5*pi/12) + + elif embedding == 'NT': + pos_dict = { + 0: (1, 2), + 1: (3, 2), + 2: (0, 1), + 3: (1, 1), + 4: (2, 1), + 5: (3, 1), + 6: (4, 1), + 7: (0, -1), + 8: (1, 0), + 9: (2, 0), + 10: (3, 0), + 11: (4, -1), + } + + G = Graph(12, pos=pos_dict, name='Twinplex Graph') + G.add_edges([ + (0, 2), (0, 4), (0, 6), + (1, 3), (1, 5), (1, 6), + (2, 7), (2, 9), (3, 7), + (3, 8), (4, 8), (4, 10), + (5, 9), (5, 10), (6, 11), + (7, 11), (8, 9), (10, 11) + ]) + + elif embedding == 'RST': + pos_dict = { + 0: (-1, 3), + 1: (1, 3), + 2: (3, 1), + 3: (3, -1), + 4: (1, -3), + 5: (-1, -3), + 6: (-3, -1), + 7: (-3, 1), + 8: (-1, 1), + 9: (1, 1), + 10: (1, -1), + 11: (-1, -1) + } + + G = Graph(12, pos=pos_dict, name='Twinplex Graph') + + G.add_cycle(list(range(8))) + G.add_edges([ + (0, 4), (1, 8), (2, 10), + (3, 9), (5, 10), (6, 8), + (7, 11), (8, 9), (9, 11), + (10, 11) + ]) + + elif embedding == 'LM': + from math import pi + + pos_dict = { + 8: (0, 1), + 9: (1, 0), + 10: (-3*cos(pi/16), -3*sin(pi/16)), + 11: (3*cos(pi/16), -3*sin(pi/16)) + } + + for v in range(8): + t = pi * (v+2)/4 + pos_dict[v] = (-2*cos(t), 2*sin(t)) + + G = Graph(12, pos=pos_dict, name='Twinplex Graph') + + G.add_cycle(list(range(8))) + G.add_edges([ + (0, 8), (1, 11), (2, 9), (3, 10), (4, 8), + (5, 11), (6, 9), (7, 10), (8, 9), (10, 11) + ]) + + else: + raise ValueError("parameter 'embedding' must be 'FL', 'NT'," + " 'LM' or 'RST'") + + return G + + def WagnerGraph(): """ Return the Wagner Graph. diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index c9969845710..a350ceeba86 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -1374,8 +1374,7 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, # static copy of the graph for more efficient operations cdef list int_to_vertex = list(G) cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=True) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef short_digraph rev_sd cdef bint reverse = False if directed: diff --git a/src/sage/graphs/graph_decompositions/clique_separators.pyx b/src/sage/graphs/graph_decompositions/clique_separators.pyx index 0bd02e3b5db..3cb10805b8a 100644 --- a/src/sage/graphs/graph_decompositions/clique_separators.pyx +++ b/src/sage/graphs/graph_decompositions/clique_separators.pyx @@ -172,12 +172,6 @@ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=Fal :meth:`~sage.graphs.traversals.maximum_cardinality_search_M` graph traversal and has time complexity in `O(|V|\cdot|E|)`. - .. NOTE:: - As the graph is converted to a short_digraph (with - ``sort_neighbors=True``), the complexity has an extra - `O(|V|+|E|\log{|E|})` for ``SparseGraph`` and `O(|V|^2\log{|E|})` for - ``DenseGraph``. - If the graph is not connected, we insert empty separators between the lists of separators of each connected components. See the examples below for more details. @@ -464,8 +458,7 @@ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=Fal # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=True) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) # variables for the manipulation of the short digraph cdef uint32_t** p_vertices = sd.neighbors diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index f0b6c4472ed..812a16e8b4d 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -114,6 +114,7 @@ def wrap_name(x): "cocliques_HoffmannSingleton", "ConwaySmith_for_3S7", "CoxeterGraph", + "CubeplexGraph", "DesarguesGraph", "DejterGraph", "distance_3_doubly_truncated_Golay_code_graph", @@ -173,6 +174,7 @@ def wrap_name(x): "MeredithGraph", "MoebiusKantorGraph", "MoserSpindle", + "MurtyGraph", "NauruGraph", "PappusGraph", "PoussinGraph", @@ -189,12 +191,14 @@ def wrap_name(x): "SzekeresSnarkGraph", "ThomsenGraph", "TietzeGraph", + "TricornGraph", "TruncatedIcosidodecahedralGraph", "TruncatedTetrahedralGraph", "TruncatedWittGraph", "Tutte12Cage", "TutteCoxeterGraph", "TutteGraph", + "TwinplexGraph", "U42Graph216", "U42Graph540", "WagnerGraph", @@ -2543,6 +2547,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None cocliques_HoffmannSingleton = staticmethod(distance_regular.cocliques_HoffmannSingleton) ConwaySmith_for_3S7 = staticmethod(distance_regular.ConwaySmith_for_3S7) CoxeterGraph = staticmethod(smallgraphs.CoxeterGraph) + CubeplexGraph = staticmethod(smallgraphs.CubeplexGraph) DejterGraph = staticmethod(smallgraphs.DejterGraph) DesarguesGraph = staticmethod(smallgraphs.DesarguesGraph) distance_3_doubly_truncated_Golay_code_graph = staticmethod(distance_regular.distance_3_doubly_truncated_Golay_code_graph) @@ -2603,6 +2608,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None MeredithGraph = staticmethod(smallgraphs.MeredithGraph) MoebiusKantorGraph = staticmethod(smallgraphs.MoebiusKantorGraph) MoserSpindle = staticmethod(smallgraphs.MoserSpindle) + MurtyGraph = staticmethod(smallgraphs.MurtyGraph) NauruGraph = staticmethod(smallgraphs.NauruGraph) PappusGraph = staticmethod(smallgraphs.PappusGraph) PoussinGraph = staticmethod(smallgraphs.PoussinGraph) @@ -2619,12 +2625,14 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None SzekeresSnarkGraph = staticmethod(smallgraphs.SzekeresSnarkGraph) ThomsenGraph = staticmethod(smallgraphs.ThomsenGraph) TietzeGraph = staticmethod(smallgraphs.TietzeGraph) + TricornGraph = staticmethod(smallgraphs.TricornGraph) Tutte12Cage = staticmethod(smallgraphs.Tutte12Cage) TruncatedIcosidodecahedralGraph = staticmethod(smallgraphs.TruncatedIcosidodecahedralGraph) TruncatedTetrahedralGraph = staticmethod(smallgraphs.TruncatedTetrahedralGraph) TruncatedWittGraph = staticmethod(distance_regular.TruncatedWittGraph) TutteCoxeterGraph = staticmethod(smallgraphs.TutteCoxeterGraph) TutteGraph = staticmethod(smallgraphs.TutteGraph) + TwinplexGraph = staticmethod(smallgraphs.TwinplexGraph) U42Graph216 = staticmethod(smallgraphs.U42Graph216) U42Graph540 = staticmethod(smallgraphs.U42Graph540) WagnerGraph = staticmethod(smallgraphs.WagnerGraph) diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index c24c8d3334f..bf24e7d3d97 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -418,8 +418,7 @@ cdef inline distances_and_far_apart_pairs(gg, # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph cdef short_digraph sd - init_short_digraph(sd, gg, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, gg, edge_labelled=False, vertex_list=int_to_vertex) cdef uint32_t** p_vertices = sd.neighbors cdef uint32_t* p_tmp cdef uint32_t* end diff --git a/src/sage/graphs/isoperimetric_inequalities.pyx b/src/sage/graphs/isoperimetric_inequalities.pyx index 5fd13cade15..731cfc00040 100644 --- a/src/sage/graphs/isoperimetric_inequalities.pyx +++ b/src/sage/graphs/isoperimetric_inequalities.pyx @@ -110,8 +110,7 @@ def cheeger_constant(g): cdef unsigned long vmin = 1 # value of the volume for the min cdef int i - init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g), - sort_neighbors=False) + init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g)) subgraph = check_malloc(sd.n * sizeof(int)) bitsubgraph = check_malloc(sd.n * sizeof(int)) @@ -245,8 +244,7 @@ def edge_isoperimetric_number(g): cdef int u = 0 # current vertex cdef int i - init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g), - sort_neighbors=False) + init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g)) cdef unsigned long bmin = sd.neighbors[1] - sd.neighbors[0] # value of boundary for the min cdef unsigned long vmin = 1 # value of the volume for the min diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index c1b0f883578..0ce87c3ad11 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -1145,8 +1145,7 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): int_to_v[0], int_to_v[i] = int_to_v[i], int_to_v[0] cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_v, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_v) cdef uint32_t* p_tmp cdef uint32_t* p_end @@ -1409,8 +1408,7 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None raise ValueError("vertex ({0}) is not a vertex of the graph".format(initial_vertex)) cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef uint32_t** p_vertices = sd.neighbors cdef uint32_t* p_tmp cdef uint32_t* p_end @@ -1784,8 +1782,7 @@ def maximum_cardinality_search_M(G, initial_vertex=None): # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex, - sort_neighbors=False) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef MemoryAllocator mem = MemoryAllocator() cdef int* alpha = mem.calloc(N, sizeof(int)) diff --git a/src/sage/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index c60fae5d6a6..37961e273e5 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -213,8 +213,7 @@ def is_long_hole_free(g, certificate=False): cdef int n = g.order() cdef list id_label = list(g) cdef short_digraph sd - init_short_digraph(sd, g, edge_labelled=False, vertex_list=id_label, - sort_neighbors=False) + init_short_digraph(sd, g, edge_labelled=False, vertex_list=id_label) # Make a dense copy of the graph for quick adjacency tests cdef bitset_t dense_graph @@ -528,9 +527,9 @@ def is_weakly_chordal(g, certificate=False): contain an induced cycle of length at least 5. Using is_long_hole_free() and is_long_antihole_free() yields a run time - of `O(n+m^2)` for ``SparseGraph`` and `O(n^2\log{m} + m^2)` for - ``DenseGraph`` (where `n` is the number of vertices and `m` is the number of - edges of the graph). + of `O(n+m^2)` for ``SparseGraph`` and `O(n^2 + m^2)` for ``DenseGraph`` + (where `n` is the number of vertices and `m` is the number of edges of the + graph). EXAMPLES: diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index 645b5cc8448..75488f0772d 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -708,8 +708,7 @@ def _expand_basis_pgroup(p, alphas, vals, beta, h, rel): q = rel[i].p_primary_part(p) alphas[i] *= rel[i] // q rel[i] = q - if q < min_r: - min_r = q + min_r = min(q, min_r) if min_r == float('inf'): raise ValueError('rel must have at least one nonzero entry') val_rlast = rel[-1].valuation(p) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 61db70925e1..93b52433c35 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -1200,7 +1200,7 @@ def create_sympl_realization(self, m): def transvec2mat(v, bas=bas, bform=bform, fact=1): t = [x + fact*(x * bform * v) * v for x in bas] - return matrix(bform.base_ring(), t) + return matrix(bform.base_ring(), t) # ------------------------------------------------------------------------------ # setting the centralizing matrix for the case of projective group realization diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index a4e60e771f9..1d3b0bab92c 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -2974,20 +2974,21 @@ def semidirect_product(self, N, mapping, check=True): raise ValueError(msg) # create a parallel list of the automorphisms of N in GAP - libgap.eval('N := Group({})'.format(list(N.gens()))) - gens_string = ",".join(str(x) for x in N.gens()) - homomorphism_cmd = 'alpha := GroupHomomorphismByImages(N, N, [{0}],[{1}])' - libgap.eval('morphisms := []') + N_gap = libgap.eval(f'Group({list(N.gens())})') + morphisms = libgap.eval('[]') + libgap_gens = N_gap.GeneratorsOfGroup() for alpha in mapping[1]: - images_string = ",".join(str(alpha(n)) for n in N.gens()) - libgap.eval(homomorphism_cmd.format(gens_string, images_string)) - libgap.eval('Add(morphisms, alpha)') + images = [alpha(g) for g in N.gens()] + alpha_gap = N_gap.GroupHomomorphismByImages(N_gap, + libgap_gens, images) + morphisms.Add(alpha_gap) # create the necessary homomorphism from self into the # automorphism group of N in GAP - libgap.eval('H := Group({0})'.format(mapping[0])) - libgap.eval('phi := GroupHomomorphismByImages(H, AutomorphismGroup(N),{},morphisms)'.format(mapping[0])) - libgap.eval('sdp := SemidirectProduct(H, phi, N)') - return PermutationGroup(gap_group='sdp') + H = libgap.eval(f'Group({mapping[0]})') + phi = H.GroupHomomorphismByImages(N_gap.AutomorphismGroup(), + H.GeneratorsOfGroup(), morphisms) + sdp = H.SemidirectProduct(phi, N_gap) + return PermutationGroup(gap_group=sdp) def holomorph(self): r""" @@ -3047,11 +3048,11 @@ def holomorph(self): - Kevin Halasz (2012-08-14) """ - libgap.eval('G := Group({})'.format(list(self.gens()))) - libgap.eval('aut := AutomorphismGroup(G)') - libgap.eval('alpha := InverseGeneralMapping(NiceMonomorphism(aut))') - libgap.eval('product := SemidirectProduct(NiceObject(aut),alpha,G)') - return PermutationGroup(gap_group='product') + G = libgap.eval(f'Group({list(self.gens())})') + aut = G.AutomorphismGroup() + alpha = aut.NiceMonomorphism().InverseGeneralMapping() + product = aut.NiceObject().SemidirectProduct(alpha, G) + return PermutationGroup(gap_group=product) def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canonicalize=True, check=True): """ diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 9aadaa9060c..64d3186fea7 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -444,7 +444,7 @@ def _test_duality(self, **options): tester = self._tester(**options) dual = self.dual() dims = [a[0] for a in self._indices] - for dim in range(max(max(dims), tester._max_runs) + 1): + for dim in range(max(max(dims), tester._max_runs) + 1): n = len(self.basis(dim)) m = matrix(n, n, [a.eval(b) for a in self.basis(dim) for b in dual.basis(dim)]) tester.assertEqual(m, 1, f"error in dimension {dim}") diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index a3da2cdc403..cb25539a028 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -1486,7 +1486,7 @@ def riemann_sum( ["$i$", "$[x_{i-1},x_i]$", r"$\eta_i$", r"$f(\eta_i)$", "$x_{i}-x_{i-1}$"] ] + [ [i+1,[division[i],division[i+1]],xs[i],ys[i],delka_intervalu[i]] for i in range(n) - ], header_row=True)) + ], header_row=True)) html(r'Riemann sum: $\displaystyle\sum_{i=1}^{%s} f(\eta_i)(x_i-x_{i-1})=%s$ ' % (latex(n),latex(sum([ys[i]*delka_intervalu[i] for i in range(n)])))) diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 5454cb868c7..7d1ac74b7c1 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -273,7 +273,7 @@ def interact(self): 65: 850000000, 70: 2900000000} - def _B1_table_value(self, factor_digits, min=15, max=70): + def _B1_table_value(self, factor_digits, min_val=15, max_val=70): """ Return key in ``_recommended_B1_list``. @@ -290,9 +290,8 @@ def _B1_table_value(self, factor_digits, min=15, max=70): sage: ecm._B1_table_value(33) 35 """ - if factor_digits < min: - factor_digits = min - if factor_digits > max: + factor_digits = max(factor_digits, min_val) + if factor_digits > max_val: raise ValueError('too many digits') step = 5 return ((factor_digits + step - 1) // step) * step diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 7a1034243ad..6776a9cc512 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -516,13 +516,13 @@ def _magic3x3(self): """ from sage.matrix.constructor import matrix return matrix(ZZ, 7, 9, - [[1, 1, 1, -1, -1, -1, 0, 0, 0], - [1, 1, 1, 0, 0, 0, -1, -1, -1], - [0, 1, 1, -1, 0, 0, -1, 0, 0], - [1, 0, 1, 0, -1, 0, 0, -1, 0], - [1, 1, 0, 0, 0, -1, 0, 0, -1], - [0, 1, 1, 0, -1, 0, 0, 0, -1], - [1, 1, 0, 0, -1, 0, -1, 0, 0]]) + [[1, 1, 1, -1, -1, -1, 0, 0, 0], + [1, 1, 1, 0, 0, 0, -1, -1, -1], + [0, 1, 1, -1, 0, 0, -1, 0, 0], + [1, 0, 1, 0, -1, 0, 0, -1, 0], + [1, 1, 0, 0, 0, -1, 0, 0, -1], + [0, 1, 1, 0, -1, 0, 0, 0, -1], + [1, 1, 0, 0, -1, 0, -1, 0, 0]]) # The instance that should be used outside this file. diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index d20340717a5..3ec584931cc 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -2906,8 +2906,7 @@ def write(self, s): pol_curr, col_curr = map(int, match.groups()) if pol_curr != 0: - if self.max_deg < self.curr_deg: - self.max_deg = self.curr_deg + self.max_deg = max(self.max_deg, self.curr_deg) if style == "sage" and verbosity >= 1: print("Leading term degree: %2d. Critical pairs: %d." % diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 3bb7d49aaf5..ed883b07105 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -2614,8 +2614,7 @@ def write(self, s): if verbosity >= 1: print("Leading term degree: %2d." % int(token)) self.curr_deg = int(token) - if self.max_deg < self.curr_deg: - self.max_deg = self.curr_deg + self.max_deg = max(self.max_deg, self.curr_deg) elif re.match(SingularGBLogPrettyPrinter.red_para, token) and verbosity >= 3: m, n = re.match(SingularGBLogPrettyPrinter.red_para, token).groups() diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index bcd43194ee7..e6b3cbafa6b 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -415,7 +415,7 @@ def __gt__(self, other): True """ if self.__class__ is other.__class__: - tups = (not self.is_knot(), self.crossing_number(), self.value) + tups = (not self.is_knot(), self.crossing_number(), self.value) tupo = (not other.is_knot(), other.crossing_number(), other.value) return tups > tupo return NotImplemented @@ -1400,7 +1400,7 @@ def kauffman_polynomial(self, var1='a', var2='z', original=False): return R.one() a, z = R.gens() - lc = {'a': a, 'z': z} + lc = {'a': a, 'z': z} return R(eval_knotinfo(kauffman_polynomial, locals=lc)) @cached_method @@ -1573,24 +1573,24 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False R = SR if not jones_polynomial and self.crossing_number() == 0: - return R(1) + return R.one() t = R(variab) if skein_normalization: if self.is_knot(): - lc = {'t': t**4} + lc = {'t': t**4} else: - lc = {'x': t**2} + lc = {'x': t**2} else: if self.is_knot(): - lc = {'t': t} + lc = {'t': t} elif puiseux: - lc = {'x': t**(1/2)} + lc = {'x': t**(1/2)} elif use_sqrt: from sage.misc.functional import sqrt - lc = {'x': sqrt(t)} + lc = {'x': sqrt(t)} else: - lc = {'x': t} + lc = {'x': t} return R(eval_knotinfo(jones_polynomial, locals=lc)) @@ -1676,7 +1676,7 @@ def alexander_polynomial(self, var='t', original=False, laurent_poly=False): return R.one() t, = R.gens() - lc = {'t': t} + lc = {'t': t} ap = R(eval_knotinfo(alexander_polynomial, locals=lc)) if not laurent_poly or ap.is_constant(): return ap @@ -1747,7 +1747,7 @@ def conway_polynomial(self, var='t', original=False): return R.one() t, = R.gens() - lc = {'z': t} + lc = {'z': t} return R(eval_knotinfo(conway_polynomial, locals=lc)) @cached_method diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index ed6a638eedc..0b0dfd6dd47 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -4003,8 +4003,7 @@ def _knotinfo_matching_list(self): # set the limits for the KnotInfoSeries if cr > 11 and co > 1: cr = 11 - if cr > 13: - cr = 13 + cr = min(cr, 13) Hp = self.homfly_polynomial(normalization='vz') diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index f461690728d..cc06d96c503 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -34,7 +34,6 @@ from sage.structure.sage_object import SageObject from sage.rings.complex_mpfr import ComplexField from sage.rings.integer import Integer -from sage.misc.sage_eval import sage_eval from sage.misc.verbose import verbose import sage.interfaces.gp from sage.env import SAGE_EXTCODE @@ -478,10 +477,6 @@ def repl(m): self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs) - def __to_CC(self, s): - s = s.replace('.E', '.0E').replace(' ', '') - return self.__CC(sage_eval(s, locals={'I': self.__CC.gen(0)})) - def _clear_value_cache(self): del self.__values @@ -515,6 +510,7 @@ def __call__(self, s, c=None): except KeyError: pass z = self._gp_call_inst('L', s) + CC = self.__CC if 'pole' in z: print(z) raise ArithmeticError @@ -525,10 +521,10 @@ def __call__(self, s, c=None): i = z.rfind('\n') msg = z[:i].replace('digits', 'decimal digits') verbose(msg, level=-1) - ans = self.__to_CC(z[i + 1:]) + ans = CC(z[i + 1:]) self.__values[s] = ans return ans - ans = self.__to_CC(z) + ans = CC(z) self.__values[s] = ans return ans diff --git a/src/sage/libs/flint/fmpz_poly_sage.pyx b/src/sage/libs/flint/fmpz_poly_sage.pyx index 5b8e9276732..3904e397e27 100644 --- a/src/sage/libs/flint/fmpz_poly_sage.pyx +++ b/src/sage/libs/flint/fmpz_poly_sage.pyx @@ -87,9 +87,9 @@ cdef class Fmpz_poly(SageObject): sage: f[2] == 10**100000 True """ - if isinstance(value, Integer) : + if isinstance(value, Integer): fmpz_poly_set_coeff_mpz(self.poly, i, (value).value) - else : + else: fmpz_poly_set_coeff_si(self.poly, i, value) def __getitem__(self, i): @@ -336,7 +336,7 @@ cdef class Fmpz_poly(SageObject): fmpz_poly_divrem(Q.poly, R.poly, self.poly, other.poly) return Q, R - def left_shift(self, unsigned long n) : + def left_shift(self, unsigned long n): """ Left shift ``self`` by `n`. @@ -353,7 +353,7 @@ cdef class Fmpz_poly(SageObject): return res - def right_shift(self, unsigned long n) : + def right_shift(self, unsigned long n): """ Right shift ``self`` by `n`. @@ -383,7 +383,7 @@ cdef class Fmpz_poly(SageObject): fmpz_poly_pseudo_divrem(Q.poly, R.poly, &d, self.poly, other.poly) return Q, R, d - def derivative(self) : + def derivative(self): """ Return the derivative of ``self``. diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index ca835f85b90..30e6fdd56ed 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -170,15 +170,8 @@ from sage.interfaces.giac import giac # Python3 compatibility ############################ -def decstring23(s): - return s.decode() - - def encstring23(s): return bytes(s, 'UTF-8') - - -listrange = list, range # End of Python3 compatibility ##################### @@ -797,7 +790,7 @@ cdef class Pygen(GiacMethods_base): #NB: the != here gives problems with the __richcmp__ function #if (s!=None): # so it's better to use isinstance - if (isinstance(s,None.__class__)): + if (isinstance(s, None.__class__)): # Do NOT replace with: self=GIACNULL (cf the doctest in __repr__ sig_on() self.gptr = new gen ((GIACNULL).gptr[0]) @@ -848,7 +841,7 @@ cdef class Pygen(GiacMethods_base): self.gptr = new gen((s).gptr[0]) sig_off() - elif isinstance(s, listrange): + elif isinstance(s, (list, range)): sig_on() self.gptr = new gen(_wrap_pylist(s),0) sig_off() @@ -866,7 +859,7 @@ cdef class Pygen(GiacMethods_base): s = s._giac_init_() except AttributeError: s = SRexpressiontoGiac(s) - if not(isinstance(s, str)): #modif python3 + if not isinstance(s, str): s = s.__str__() sig_on() self.gptr = new gen(encstring23(s),context_ptr) @@ -880,14 +873,14 @@ cdef class Pygen(GiacMethods_base): sig_on() t=GIAC_taille(self.gptr[0], 6000) sig_off() - if (t<6000) : + if t < 6000: sig_on() - result=decstring23(GIAC_print(self.gptr[0], context_ptr).c_str()) #python3 + result = GIAC_print(self.gptr[0], context_ptr).c_str().decode() sig_off() return result else: sig_on() - result=str(self.type)+"\nResult is too big for Display. If you really want to see it use print" + result = str(self.type) + "\nResult is too big for Display. If you really want to see it use print" sig_off() return result @@ -895,7 +888,7 @@ cdef class Pygen(GiacMethods_base): #if self.gptr == NULL: # return '' sig_on() - result=decstring23(GIAC_print(self.gptr[0], context_ptr).c_str()) #python3 + result = GIAC_print(self.gptr[0], context_ptr).c_str().decode() sig_off() return result @@ -926,7 +919,7 @@ cdef class Pygen(GiacMethods_base): TESTS:: sage: from sage.libs.giac.giac import libgiac - sage: l=libgiac(list(range(10^6)));l[5] #python3 + sage: l=libgiac(list(range(10^6)));l[5] 5 sage: l[35:50:7] [35,42,49] @@ -960,19 +953,19 @@ cdef class Pygen(GiacMethods_base): if(i<0): i=i+n sig_on() - result=self.gptr[0][i] + result = self.gptr[0][i] sig_off() return _wrap_gen(result) else: raise IndexError('list index %s out of range'%(i)) else: - if isinstance(i,slice): + if isinstance(i, slice): sig_on() - result=gen(_getgiacslice(self,i),self._subtype) + result = gen(_getgiacslice(self,i),self._subtype) sig_off() return _wrap_gen(result) # add support for multi indexes - elif isinstance(i,tuple): + elif isinstance(i, tuple): if(len(i)==2): return self[i[0]][i[1]] elif(len(i)==1): @@ -1065,7 +1058,7 @@ cdef class Pygen(GiacMethods_base): def eval(self): cdef gen result sig_on() - result=GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) + result = GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) sig_off() return _wrap_gen(result) @@ -1078,7 +1071,7 @@ cdef class Pygen(GiacMethods_base): if not isinstance(self, Pygen): self=Pygen(self) sig_on() - result= (self).gptr[0] + (right).gptr[0] + result = (self).gptr[0] + (right).gptr[0] sig_off() return _wrap_gen(result) @@ -1128,7 +1121,7 @@ cdef class Pygen(GiacMethods_base): if not isinstance(self, Pygen): self=Pygen(self) sig_on() - result= (self).gptr[0] - (right).gptr[0] + result = (self).gptr[0] - (right).gptr[0] sig_off() return _wrap_gen(result) @@ -1144,19 +1137,19 @@ cdef class Pygen(GiacMethods_base): """ cdef gen result if not isinstance(right, Pygen): - right=Pygen(right) + right = Pygen(right) if not isinstance(self, Pygen): - self=Pygen(self) - #result= (self).gptr[0] * (right).gptr[0] + self = Pygen(self) + #result = (self).gptr[0] * (right).gptr[0] #NB: with the natural previous method, the following error generated by #giac causes python to quit instead of an error message. #l=Pygen([1,2]);l.transpose()*l; sig_on() - result= GIAC_giacmul((self).gptr[0] , (right).gptr[0],context_ptr) + result = GIAC_giacmul((self).gptr[0], (right).gptr[0],context_ptr) sig_off() return _wrap_gen(result) -#PB / in python3 is truediv + # PB / in python3 is truediv def __div__(self, right): """ TESTS:: @@ -1169,57 +1162,57 @@ cdef class Pygen(GiacMethods_base): """ cdef gen result if not isinstance(right, Pygen): - right=Pygen(right) + right = Pygen(right) if not isinstance(self, Pygen): - self=Pygen(self) + self = Pygen(self) sig_on() - result= GIAC_giacdiv((self).gptr[0] , (right).gptr[0],context_ptr) + result = GIAC_giacdiv((self).gptr[0], (right).gptr[0],context_ptr) sig_off() return _wrap_gen(result) def __truediv__(self, right): cdef gen result if not isinstance(right, Pygen): - right=Pygen(right) + right = Pygen(right) if not isinstance(self, Pygen): - self=Pygen(self) + self = Pygen(self) sig_on() - result= (self).gptr[0] / (right).gptr[0] + result = (self).gptr[0] / (right).gptr[0] sig_off() return _wrap_gen(result) - def __pow__(self, right ,ignored): + def __pow__(self, right, ignored): cdef gen result if not isinstance(right, Pygen): - right=Pygen(right) + right = Pygen(right) if not isinstance(self, Pygen): - self=Pygen(self) + self = Pygen(self) sig_on() - result= GIAC_pow((self).gptr[0],(right).gptr[0], context_ptr ) + result = GIAC_pow((self).gptr[0], (right).gptr[0], context_ptr ) sig_off() return _wrap_gen(result) def __mod__(self, right): cdef gen result if not isinstance(right, Pygen): - right=Pygen(right) + right = Pygen(right) if not isinstance(self, Pygen): - self=Pygen(self) - #result= gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) + self = Pygen(self) + #result = gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) #to have an integer output: - #result= GIAC_smod(result,context_ptr) + #result = GIAC_smod(result,context_ptr) #we give a modular output: sig_on() - result= GIAC_giacmod((self).gptr[0],(right).gptr[0],context_ptr) + result = GIAC_giacmod((self).gptr[0], (right).gptr[0],context_ptr) sig_off() return _wrap_gen(result) def __neg__(self): cdef gen result if not isinstance(self, Pygen): - self=Pygen(self) + self = Pygen(self) sig_on() - result= GIAC_neg((self).gptr[0]) + result = GIAC_neg((self).gptr[0]) sig_off() return _wrap_gen(result) @@ -1232,12 +1225,12 @@ cdef class Pygen(GiacMethods_base): def savegen(self, str filename): """ - Archive a Pygen element to a file in giac compressed format. + Archive a Pygen element to a file in giac compressed format. - Use the loadgiacgen command to get back the Pygen from the file. - In C++ these files can be opened with ``giac::unarchive``. + Use the loadgiacgen command to get back the Pygen from the file. + In C++ these files can be opened with ``giac::unarchive``. - EXAMPLES:: + EXAMPLES:: sage: from sage.libs.giac.giac import * sage: f=libgiac('(x+y+z+2)**10'); g=f.normal() @@ -1296,8 +1289,8 @@ cdef class Pygen(GiacMethods_base): # if (not lang in ['en', 'fr', 'el']): # lang='en' # try: - # url=decstring23(browser_help(self.gptr[0],l[lang])) #python3 - # giacbasedir=decstring23(GIAC_giac_aide_dir()) # python3 + # url=browser_help(self.gptr[0],l[lang]).decode() + # giacbasedir=GIAC_giac_aide_dir().decode() # except: # raise RuntimeError('giac docs dir not found') # print(url) @@ -1338,7 +1331,7 @@ cdef class Pygen(GiacMethods_base): \frac{...x^{4}...-...y...}{...y^{2}-3...x...} """ sig_on() - result=decstring23(GIAC_gen2tex(self.gptr[0], context_ptr).c_str()) #python3 + result = GIAC_gen2tex(self.gptr[0], context_ptr).c_str().decode() sig_off() return result @@ -1473,15 +1466,15 @@ cdef class Pygen(GiacMethods_base): """ typ = self._type - if (typ != 7) : + if typ != 7: # self is not a list - if ( typ == 0 or typ == 2): + if typ == 0 or typ == 2: return ZZ(self) - elif (typ == 10): + elif typ == 10: return QQ(self) - elif (typ == 15): + elif typ == 15: # modular integer sig_on() a = _wrap_gen( (self.gptr.ref_MODptr())[0]) @@ -1490,10 +1483,10 @@ cdef class Pygen(GiacMethods_base): sig_off() return result - elif (typ == 12): + elif typ == 12: # string sig_on() - result=eval(self.__str__()) + result = eval(self.__str__()) sig_off() return result @@ -1503,7 +1496,7 @@ cdef class Pygen(GiacMethods_base): else: # self is a list sig_on() - result=[entry.sage() for entry in self] + result = [entry.sage() for entry in self] sig_off() return result @@ -1533,7 +1526,7 @@ cdef class Pygen(GiacMethods_base): sage: libgiac.integrate(cos(y), y).sage() sin(π) """ - if isinstance(R,SR.__class__): + if isinstance(R, SR.__class__): # Try to convert some functions names to the symbolic ring lsymbols = symbol_table['giac'].copy() #lsymbols.update(locals) @@ -1547,7 +1540,7 @@ cdef class Pygen(GiacMethods_base): raise NotImplementedError("Unable to parse Giac output: %s" % self.__repr__()) else: try: - result=R(self.__str__()) + result = R(self.__str__()) return result except Exception: @@ -1601,7 +1594,7 @@ cdef class Pygen(GiacMethods_base): sage: vector(v+v/3,QQ) (0, 4/3, 8/3, 4, 16/3, 20/3, 8, 28/3, 32/3, 12) """ - if(isinstance(R, None.__class__)): + if isinstance(R, None.__class__): R=ZZ v = self.dim() @@ -1668,7 +1661,7 @@ cdef class Pygen(GiacMethods_base): if not isinstance(self, Pygen): self = Pygen(self) sig_on() - result= giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) + result = giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) sig_off() return result == 1 @@ -1686,7 +1679,7 @@ cdef class Pygen(GiacMethods_base): property _subtype: def __get__(self): sig_on() - result=self.gptr.subtype + result = self.gptr.subtype sig_off() return result @@ -1787,9 +1780,9 @@ cdef vecteur _wrap_pylist(L) except +: cdef vecteur * V cdef int i - if (isinstance(L, tuple) or isinstance(L, listrange)): - n=len(L) - V=new vecteur() + if isinstance(L, (tuple, list, range)): + n = len(L) + V = new vecteur() sig_on() for i in range(n): @@ -1807,14 +1800,14 @@ cdef vecteur _getgiacslice(Pygen L,slice sl) except +: cdef vecteur * V cdef int u - if (L.type()=="DOM_LIST"): + if L.type()=="DOM_LIST": n=len(L) V=new vecteur() sig_on() # for u in range(n)[sl]: #pb python3 - (b,e,st)=sl.indices(n) - for u in range(b,e,st): + b, e, st = sl.indices(n) + for u in range(b, e, st): V.push_back((L.gptr[0])[u]) sig_off() return V[0] @@ -1862,7 +1855,7 @@ cdef gen pylongtogen(a) except +: #def giaceval(Pygen self): # cdef gen result # try: -# result=GIAC_protecteval(self.gptr[0],1,context_ptr) +# result = GIAC_protecteval(self.gptr[0],1,context_ptr) # return _wrap_gen(result) # except: # raise @@ -1872,7 +1865,7 @@ cdef gen pylongtogen(a) except +: # # cdef gen result # try: -# result=GIAC_factor(self.gptr[0],context_ptr) +# result = GIAC_factor(self.gptr[0],context_ptr) # return _wrap_gen(result) # except: # raise @@ -1882,7 +1875,7 @@ cdef gen pylongtogen(a) except +: #def giacfactors(Pygen self): # cdef gen result # try: -# result=GIAC_factors(self.gptr[0],context_ptr) +# result = GIAC_factors(self.gptr[0],context_ptr) # return _wrap_gen(result) # except: # raise @@ -1893,7 +1886,7 @@ cdef gen pylongtogen(a) except +: #def giacnormal(Pygen self): # cdef gen result # try: -# result=GIAC_normal(self.gptr[0],context_ptr) +# result = GIAC_normal(self.gptr[0],context_ptr) # return _wrap_gen(result) # except: # raise @@ -1902,8 +1895,8 @@ cdef gen pylongtogen(a) except +: #def giacgcd(Pygen a, Pygen b): # cdef gen result # try: -# result=gen( GIAC_makenewvecteur(a.gptr[0],b.gptr[0]) ,1) -# result=GIAC_gcd(result,context_ptr) +# result = gen( GIAC_makenewvecteur(a.gptr[0],b.gptr[0]) ,1) +# result = GIAC_gcd(result,context_ptr) # return _wrap_gen(result) # except: # raise @@ -1983,7 +1976,7 @@ for i in moremethods: GiacMethods[i] = tmp for i in mostkeywords+moremethods: - GiacMethods[i].__doc__ = eval("Pygen."+i+".__doc__") + GiacMethods[i].__doc__ = eval("Pygen." + i + ".__doc__") # To avoid conflicts we export only these few ones. Most giac keywords will be # available through: libgiac.keywordname @@ -2016,7 +2009,7 @@ def loadgiacgen(str filename): """ cdef gen result sig_on() - result=GIAC_unarchive( encstring23(filename), context_ptr) + result = GIAC_unarchive( encstring23(filename), context_ptr) sig_off() return _wrap_gen(result) diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index 69340c00f31..310bbb0006c 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -1271,7 +1271,7 @@ cdef class ntl_mat_ZZ(): rank = int(mat_ZZ_LLL(&det2,&self.x,int(a),int(b),int(verbose))) return rank, make_ZZ_sig_off(det2) - def LLL_FP(self, delta=0.75 , return_U=False, verbose=False): + def LLL_FP(self, delta=0.75, return_U=False, verbose=False): r""" Perform approximate LLL reduction of \code{self} (puts \code{self} in an LLL form) subject to the following diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index ef91e60a2a4..f770cc483a5 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -293,12 +293,14 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: if isinstance(base_ring, RationalField): characteristic = 0 - _ring = rDefault( characteristic ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault(characteristic, nvars, _names, nblcks, + _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, FractionField_generic) and isinstance(base_ring.base(), (MPolynomialRing_libsingular, PolynomialRing_field)) and isinstance(base_ring.base().base_ring(), RationalField): characteristic = 1 k = PolynomialRing(RationalField(), - names=base_ring.variable_names(), order='lex', implementation='singular') + names=base_ring.variable_names(), order='lex', + implementation='singular') ngens = len(k.gens()) @@ -317,7 +319,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: if (_cf is NULL): raise RuntimeError("Failed to allocate _cf ring.") - _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, FractionField_generic) and isinstance(base_ring.base(), (MPolynomialRing_libsingular, PolynomialRing_field)) and isinstance(base_ring.base().base_ring(), FiniteField_generic): if not base_ring.base_ring().is_prime_field(): @@ -343,7 +345,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: if (_cf is NULL): raise RuntimeError("Failed to allocate _cf ring.") - _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, NumberField) and base_ring.is_absolute(): characteristic = 1 @@ -369,11 +371,11 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: if (_cf is NULL): raise RuntimeError("Failed to allocate _cf ring.") - _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, IntegerRing_class): _cf = nInitChar( n_Z, NULL) # integer coefficient ring - _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif (isinstance(base_ring, FiniteField_generic) and base_ring.is_prime_field()): if base_ring.characteristic() <= 2147483647: @@ -384,7 +386,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: # example for simpler ring creation interface without monomial orderings: #_ring = rDefault(characteristic, nvars, _names) - _ring = rDefault( characteristic , nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault(characteristic, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, FiniteField_generic): if base_ring.characteristic() <= 2147483647: @@ -418,7 +420,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: if (_cf is NULL): raise RuntimeError("Failed to allocate _cf ring.") - _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, sage.rings.abc.IntegerModRing): @@ -472,12 +474,12 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: mpz_init_set_ui(_info.base, characteristic) _info.exp = 1 _cf = nInitChar( n_Zn, &_info ) - _ring = rDefault( _cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + _ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) else: raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular") - if (_ring is NULL): + if _ring is NULL: raise ValueError("Failed to allocate Singular ring.") _ring.ShortOut = 0 diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 6a848a405e0..b51c08b8506 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -1321,11 +1321,11 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring) noexcept: a = _ring.cf.cfParameter(j+1, _ring.cf) for k in range(ex): aux1 = naCoeff - naCoeff = _ring.cf.cfMult(aux1, a ,_ring.cf) + naCoeff = _ring.cf.cfMult(aux1, a, _ring.cf) _ring.cf.cfDelete(&aux1, _ring.cf) _ring.cf.cfDelete(&a, _ring.cf) aux2 = numerator - numerator = _ring.cf.cfAdd(aux2, naCoeff,_ring.cf) + numerator = _ring.cf.cfAdd(aux2, naCoeff, _ring.cf) _ring.cf.cfDelete(&naCoeff, _ring.cf) _ring.cf.cfDelete(&aux2, _ring.cf) @@ -1338,7 +1338,7 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring) noexcept: a = _ring.cf.cfParameter(j+1, _ring.cf) for k in range(ex): aux1 = naCoeff - naCoeff = _ring.cf.cfMult(aux1, a ,_ring.cf) + naCoeff = _ring.cf.cfMult(aux1, a, _ring.cf) _ring.cf.cfDelete(&aux1, _ring.cf) _ring.cf.cfDelete(&a, _ring.cf) aux2 = denominator @@ -1425,11 +1425,11 @@ cdef number *sa2si_NF(object elem, ring *_ring) noexcept: rComplete(qqr,1) qqr.ShortOut = 0 - nMapFuncPtr = naSetMap( qqr.cf , _ring.cf ) # choose correct mapping function + nMapFuncPtr = naSetMap(qqr.cf, _ring.cf) # choose correct mapping function cdef poly *_p for i from 0 <= i < len(elem): nlCoeff = nlInit2gmp( mpq_numref((elem[i]).value), mpq_denref((elem[i]).value), qqr.cf ) - naCoeff = nMapFuncPtr(nlCoeff, qqr.cf , _ring.cf ) + naCoeff = nMapFuncPtr(nlCoeff, qqr.cf, _ring.cf) nlDelete(&nlCoeff, _ring.cf) # faster would be to assign the coefficient directly @@ -1548,9 +1548,9 @@ cdef inline number *sa2si_ZZmod(IntegerMod_abstract d, ring *_ring) noexcept: _name = omStrDup("a") _ext_names = omAlloc0(sizeof(char*)) _ext_names[0] = omStrDup(_name) - _cf = nInitChar( n_Z, NULL) # integer coefficient ring - ZZr = rDefault (_cf ,1, _ext_names) - rComplete(ZZr,1) + _cf = nInitChar(n_Z, NULL) # integer coefficient ring + ZZr = rDefault (_cf, 1, _ext_names) + rComplete(ZZr, 1) ZZr.ShortOut = 0 nn = nrzInit(0, ZZr.cf) diff --git a/src/sage/logic/boolformula.py b/src/sage/logic/boolformula.py index 817132fb8f8..d22c0443461 100644 --- a/src/sage/logic/boolformula.py +++ b/src/sage/logic/boolformula.py @@ -565,15 +565,12 @@ def truthtable(self, start=0, end=-1): exponential time function requiring `O(2^n)` time, where `n` is the number of variables in the expression. """ - max = 2 ** len(self.__vars_order) + maximum = 2 ** len(self.__vars_order) if end < 0: - end = max - if end > max: - end = max - if start < 0: - start = 0 - if start > max: - start = max + end = maximum + end = min(end, maximum) + start = max(start, 0) + start = min(start, maximum) keys, table = [], [] vars = {} for var in self.__vars_order: diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index e4a217bbbab..a4888559c0f 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -172,7 +172,7 @@ class CalculusMethod(SageObject): """ _default = 'SR' # default calculus method _methods = ('SR', 'sympy') # implemented methods - _tranf = {'SR': _Sympy_to_SR, 'sympy': _SR_to_Sympy} # translators + _tranf = {'SR': _Sympy_to_SR, 'sympy': _SR_to_Sympy} # translators def __init__(self, current=None, base_field_type='real'): r""" diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 3edb9ead54d..0940710150e 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -670,7 +670,7 @@ cdef class Matrix(Matrix0): entries = [[sib(v, 2) for v in row] for row in self.rows()] return sib.name('matrix')(self.base_ring(), entries) - def numpy(self, dtype=None): + def numpy(self, dtype=None, copy=True): """ Return the Numpy matrix associated to this matrix. @@ -680,6 +680,10 @@ cdef class Matrix(Matrix0): then the type will be determined as the minimum type required to hold the objects in the sequence. + - ``copy`` -- if `self` is already an `ndarray`, then this flag + determines whether the data is copied (the default), or whether + a view is constructed. + EXAMPLES:: sage: # needs numpy @@ -731,7 +735,7 @@ cdef class Matrix(Matrix0): (3, 4) """ import numpy - A = numpy.matrix(self.list(), dtype=dtype) + A = numpy.matrix(self.list(), dtype=dtype, copy=copy) return numpy.resize(A,(self.nrows(), self.ncols())) # Define the magic "__array__" function so that numpy.array(m) can convert diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index b0de42539a0..f26078bde7e 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -171,19 +171,19 @@ cdef class Matrix_dense(matrix.Matrix): [4|1] [3|0] """ - (nc, nr) = (self.ncols(), self.nrows()) + nc, nr = self.ncols(), self.nrows() cdef Matrix_dense atrans - atrans = self.new_matrix(nrows = nc, ncols = nr, + atrans = self.new_matrix(nrows=nc, ncols=nr, copy=False, coerce=False) - cdef Py_ssize_t i,j - cdef Py_ssize_t ri,rj # reversed i and j + cdef Py_ssize_t i, j + cdef Py_ssize_t ri, rj # reversed i and j rj = nc for j from 0 <= j < nc: ri = nr - rj = rj-1 + rj -= 1 for i from 0 <= i < nr: - ri = ri-1 - atrans.set_unsafe(j , i, self.get_unsafe(ri,rj)) + ri -= 1 + atrans.set_unsafe(j, i, self.get_unsafe(ri, rj)) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() @@ -256,8 +256,8 @@ cdef class Matrix_dense(matrix.Matrix): prod = self.new_matrix(nr, nc, copy=False, coerce=False) for r in range(nr): for c in range(nc): - entry = self.get_unsafe(r,c)*other.get_unsafe(r,c) - prod.set_unsafe(r,c,entry) + entry = self.get_unsafe(r, c)*other.get_unsafe(r, c) + prod.set_unsafe(r, c, entry) return prod def _derivative(self, var=None, R=None): diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index b5158d4deb2..d3fcde93fec 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -537,7 +537,7 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): p = -numpy.inf elif p == 'frob': p = 'fro' - elif p == 'sv' : + elif p == 'sv': p = None else: try: diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index e561c459e4a..b6a832c38d9 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -5137,7 +5137,7 @@ cdef class Matrix_integer_dense(Matrix_dense): T_i_i = T_rows[i][i] T_j_i = T_rows[j][i] - d = ai.c_xgcd_int(T_i_i , T_j_i, &u, &v) + d = ai.c_xgcd_int(T_i_i, T_j_i, &u, &v) if d != T_i_i: for k from i <= k < ncols: B[k] = ((u)*T_rows[i][k] + (v)*T_rows[j][k])%R @@ -5697,12 +5697,12 @@ cdef class Matrix_integer_dense(Matrix_dense): [4|1] [3|0] """ - nr , nc = (self._nrows, self._ncols) + nr, nc = self._nrows, self._ncols cdef Matrix_integer_dense A A = self._new(nc,nr) - cdef Py_ssize_t i,j - cdef Py_ssize_t ri,rj # reversed i and j + cdef Py_ssize_t i, j + cdef Py_ssize_t ri, rj # reversed i and j sig_on() ri = nr for i from 0 <= i < nr: @@ -5710,7 +5710,8 @@ cdef class Matrix_integer_dense(Matrix_dense): ri = ri-1 for j from 0 <= j < nc: rj = rj-1 - fmpz_init_set(fmpz_mat_entry(A._matrix,rj,ri),fmpz_mat_entry(self._matrix,i,j)) + fmpz_init_set(fmpz_mat_entry(A._matrix, rj, ri), + fmpz_mat_entry(self._matrix, i, j)) sig_off() if self._subdivisions is not None: diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 66462800f30..a85918a003f 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -386,12 +386,12 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): nr,nc = self.nrows(),self.ncols() F = self.base_ring().base_ring() - cdef Matrix d = matrix(F,nr,nc) + cdef Matrix d = matrix(F, nr, nc) start_row = 0 for r from 0 <= r < nr: for c from 0 <= c < nc: - p = self.get_unsafe(r,c) + p = self.get_unsafe(r, c) if p.is_constant(): d.set_unsafe(r, c, p.constant_coefficient()) @@ -402,13 +402,13 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): r = rc break if r!=-1: - a_inverse = ~self.get_unsafe(r,c) - self.rescale_row_c(r, a_inverse , c) + a_inverse = ~self.get_unsafe(r, c) + self.rescale_row_c(r, a_inverse, c) self.swap_rows_c(r, start_row) for i from 0 <= i < nr: if i != start_row: - minus_b = -self.get_unsafe(i,c) + minus_b = -self.get_unsafe(i, c) self.add_multiple_of_row(i, start_row, minus_b, 0) start_row +=1 @@ -416,10 +416,10 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): d = d._parent(0) for i from start_row <= i < nr: for j from c+1 <= j < nc: - if self.get_unsafe(i,j).is_constant(): - d.set_unsafe(i,j, self.get_unsafe(i,j).constant_coefficient()) + if self.get_unsafe(i, j).is_constant(): + d.set_unsafe(i, j, self.get_unsafe(i, j).constant_coefficient()) - self.cache('in_echelon_form_row_reduction',True) + self.cache('in_echelon_form_row_reduction', True) def swapped_columns(self): """ diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 421ba420347..89943f90b3b 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -576,8 +576,7 @@ def _name_maker(self, names): width = 0 for e in self._elts: estr = repr(e) - if len(estr) > width: - width = len(estr) + width = max(len(estr), width) name_list.append(estr) elif isinstance(names, list): if len(names) != self._n: @@ -588,8 +587,7 @@ def _name_maker(self, names): if not isinstance(name, str): raise ValueError( 'list of element names must only contain strings, not %s' % name) - if len(name) > width: - width = len(name) + width = max(len(name), width) name_list.append(name) else: raise ValueError( diff --git a/src/sage/matrix/strassen.pyx b/src/sage/matrix/strassen.pyx index 00807e39c4d..978773e3a27 100644 --- a/src/sage/matrix/strassen.pyx +++ b/src/sage/matrix/strassen.pyx @@ -98,9 +98,9 @@ cdef strassen_window_multiply_c(MatrixWindow C, MatrixWindow A, # "Memory efficient scheduling of Strassen-Winograd's matrix multiplication algorithm", # Table 1). - cdef MatrixWindow S0, S1, S2, S3, T0, T1 ,T2, T3, P0, P1, P2, P3, P4, P5, P6, U0, U1, U2, U3, U4, U5, U6 + cdef MatrixWindow S0, S1, S2, S3, T0, T1, T2, T3, P0, P1, P2, P3, P4, P5, P6, U0, U1, U2, U3, U4, U5, U6 cdef MatrixWindow X, Y - X = A.new_empty_window(A_sub_nrows, max(A_sub_ncols,B_sub_ncols)) + X = A.new_empty_window(A_sub_nrows, max(A_sub_ncols, B_sub_ncols)) Y = B.new_empty_window(A_sub_ncols, B_sub_ncols) # 1 S2 = A00-A10 in X @@ -112,7 +112,7 @@ cdef strassen_window_multiply_c(MatrixWindow C, MatrixWindow A, T2.set_to_diff(B11, B01) # 3 P6 = S2*T2 in C10 - P6 = C.matrix_window(A_sub_nrows, 0, A_sub_nrows, B_sub_ncols) + P6 = C.matrix_window(A_sub_nrows, 0, A_sub_nrows, B_sub_ncols) if have_cutoff: P6.set_to_prod(S2, T2) else: diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 7545f1b0dc9..f78b390e031 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -2096,7 +2096,7 @@ cdef class CachedMethodCaller(CachedFunction): pass try: if inst._cached_methods is None: - inst._cached_methods = {self._cachedmethod._cachedfunc.__name__ : Caller} + inst._cached_methods = {self._cachedmethod._cachedfunc.__name__: Caller} else: (inst._cached_methods)[self._cachedmethod._cachedfunc.__name__] = Caller except AttributeError: @@ -2471,7 +2471,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): pass try: if inst._cached_methods is None: - inst._cached_methods = {self.__name__ : Caller} + inst._cached_methods = {self.__name__: Caller} else: (inst._cached_methods)[self.__name__] = Caller except AttributeError: @@ -2852,7 +2852,7 @@ cdef class CachedMethod(): pass try: if inst._cached_methods is None: - inst._cached_methods = {name : Caller} + inst._cached_methods = {name: Caller} else: (inst._cached_methods)[name] = Caller except AttributeError: diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index b3d8f3492b0..80f1fd3e7c4 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -41,6 +41,7 @@ from sage.categories.modular_abelian_varieties import ModularAbelianVarieties from sage.matrix.constructor import matrix from sage.matrix.special import block_diagonal_matrix, identity_matrix +from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modular.arithgroup.congroup_gamma0 import Gamma0_class @@ -69,8 +70,7 @@ ['cremona_letter_code', 'CremonaDatabase']) -from . import homspace -from . import lseries +from sage.modular.abvar import homspace, lseries from .morphism import HeckeOperator, Morphism, DegeneracyMap from .torsion_subgroup import RationalTorsionSubgroup, QQbarTorsionSubgroup from .finite_subgroup import (FiniteSubgroup_lattice, FiniteSubgroup, @@ -1728,6 +1728,7 @@ def ambient_morphism(self): self.__ambient_morphism = phi return phi + @cached_method def is_ambient(self) -> bool: """ Return ``True`` if ``self`` equals the ambient product Jacobian. @@ -1746,13 +1747,8 @@ def is_ambient(self) -> bool: sage: (A+B+C).is_ambient() True """ - try: - return self.__is_ambient - except AttributeError: - pass L = self.lattice() - self.__is_ambient = (self.lattice() == ZZ**L.degree()) - return self.__is_ambient + return self.lattice() == ZZ**L.degree() def dimension(self): """ @@ -1890,6 +1886,7 @@ def sturm_bound(self): self.__sturm_bound = B return B + @cached_method def is_hecke_stable(self) -> bool: """ Return ``True`` if ``self`` is stable under the Hecke operators of its @@ -1908,11 +1905,6 @@ def is_hecke_stable(self) -> bool: sage: (J0(33)[0] + J0(33)[1]).is_hecke_stable() True """ - try: - return self._is_hecke_stable - except AttributeError: - pass - # b = self.modular_symbols().sturm_bound() b = max([m.sturm_bound() for m in self._ambient_modular_symbols_spaces()]) @@ -1924,10 +1916,8 @@ def is_hecke_stable(self) -> bool: Tn_matrix = J.hecke_operator(n).matrix() for v in B: if v * Tn_matrix not in L: - self._is_hecke_stable = False return False - self._is_hecke_stable = True return True def is_subvariety(self, other) -> bool: @@ -2467,7 +2457,7 @@ def homology(self, base_ring=ZZ): sage: J0(389).homology(ZZ) Integral Homology of Abelian variety J0(389) of dimension 32 """ - from . import homology + from sage.modular.abvar import homology try: return self._homology[base_ring] except AttributeError: diff --git a/src/sage/modular/abvar/abvar_ambient_jacobian.py b/src/sage/modular/abvar/abvar_ambient_jacobian.py index a25d82d5b8c..1a7c1e82370 100644 --- a/src/sage/modular/abvar/abvar_ambient_jacobian.py +++ b/src/sage/modular/abvar/abvar_ambient_jacobian.py @@ -20,7 +20,7 @@ from sage.modular.modsym.modsym import ModularSymbols from sage.modular.modform.constructor import Newforms from sage.modular.arithgroup.all import Gamma0_class, Gamma1_class -from . import morphism +from sage.modular.abvar import morphism _cache = {} diff --git a/src/sage/modular/abvar/abvar_newform.py b/src/sage/modular/abvar/abvar_newform.py index 1159de73894..9568e5481cc 100644 --- a/src/sage/modular/abvar/abvar_newform.py +++ b/src/sage/modular/abvar/abvar_newform.py @@ -22,7 +22,7 @@ from sage.modular.arithgroup.all import Gamma0_class, Gamma1_class, GammaH_class from .abvar import ModularAbelianVariety_modsym_abstract -from . import homspace +from sage.modular.abvar import homspace lazy_import('sage.databases.cremona', 'cremona_letter_code') diff --git a/src/sage/modular/abvar/constructor.py b/src/sage/modular/abvar/constructor.py index a39f7819393..78e160edfe6 100644 --- a/src/sage/modular/abvar/constructor.py +++ b/src/sage/modular/abvar/constructor.py @@ -19,7 +19,7 @@ from sage.modular.modsym.space import ModularSymbolsSpace from .abvar_newform import ModularAbelianVariety_newform import sage.modular.modform.element -from . import abvar +from sage.modular.abvar import abvar _cache = {} diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 2333bbacd00..30ad76f3601 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -187,7 +187,7 @@ from sage.misc.lazy_attribute import lazy_attribute -from . import morphism +from sage.modular.abvar import morphism from sage.rings.infinity import Infinity diff --git a/src/sage/modular/modform/eis_series_cython.pyx b/src/sage/modular/modform/eis_series_cython.pyx index 73ffdfab324..60df3add6f0 100644 --- a/src/sage/modular/modform/eis_series_cython.pyx +++ b/src/sage/modular/modform/eis_series_cython.pyx @@ -184,7 +184,7 @@ cpdef eisenstein_series_poly(int k, int prec=10): a0 = -bernoulli(k) / (2*k) cdef long p, ppow - for p in primes(1, prec) : + for p in primes(1, prec): ppow = p mpz_set_si(mult, p) diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 9d4e9caa7f1..87d96b21356 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1300,8 +1300,7 @@ def _compute_hecke_matrix_prime(self, p, prec=None): except AttributeError: pass else: - if prec < cur: - prec = cur + prec = max(prec, cur) B = self.q_expansion_basis(prec) eps = self.character() if eps is None: diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 590a73c109d..a77d9279a6b 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -1383,8 +1383,7 @@ def _q_expansion_basis_hecke_dual(self, prec): prec = Integer(prec) if prec < 1: raise ValueError("prec (=%s) must be >= 1" % prec) - if d >= prec - 1: - d = prec - 1 + d = min(prec - 1, d) K = self.base_ring() A = VectorSpace(K, prec - 1) diff --git a/src/sage/numerical/backends/glpk_graph_backend.pyx b/src/sage/numerical/backends/glpk_graph_backend.pyx index 514e1b9676b..2a89dfe0bd1 100644 --- a/src/sage/numerical/backends/glpk_graph_backend.pyx +++ b/src/sage/numerical/backends/glpk_graph_backend.pyx @@ -484,11 +484,11 @@ cdef class GLPKGraphBackend(): cdef c_v_data * vdata = vert.data return { - "rhs" : vdata.rhs, - "pi" : vdata.pi, - "cut" : vdata.cut, - "es" : vdata.es, - "ls" : vdata.ls + "rhs": vdata.rhs, + "pi": vdata.pi, + "cut": vdata.cut, + "es": vdata.es, + "ls": vdata.ls } cpdef dict get_vertices(self, verts): diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 50d952c2ae0..2395868b43d 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -1836,7 +1836,7 @@ cdef class MixedIntegerLinearProgram(SageObject): cdef int i if obj is None: - f = {-1 : 0} + f = {-1: 0} else: # See if it is a constant R = self.base_ring() @@ -3389,7 +3389,7 @@ cdef class MIPVariable(FiniteFamily): integer=(self._vtype == self._p.__INTEGER), obj=zero, name=name) - v = self._p.linear_functions_parent()({j : 1}) + v = self._p.linear_functions_parent()({j: 1}) self._p._variables[v] = j self._dictionary[i] = v return v diff --git a/src/sage/numerical/sdp.pyx b/src/sage/numerical/sdp.pyx index 069bea9b3a4..7c08ed08e10 100644 --- a/src/sage/numerical/sdp.pyx +++ b/src/sage/numerical/sdp.pyx @@ -803,8 +803,8 @@ cdef class SemidefiniteProgram(SageObject): if obj is not None: f = obj.dict() else: - f = {-1 : 0} - d = f.pop(-1,self._backend.zero()) + f = {-1: 0} + d = f.pop(-1, self._backend.zero()) for i in range(self._backend.ncols()): values.append(f.get(i,self._backend.zero())) @@ -1256,7 +1256,7 @@ cdef class SDPVariable(Element): zero = self._p._backend.zero() name = self._name + "[" + str(i) + "]" if self._name else None j = self._p._backend.add_variable( obj=zero, name=name) - v = self._p.linear_function({j : 1}) + v = self._p.linear_function({j: 1}) self._p._variables[v] = j self._dict[i] = v return v diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index 896249d8cd1..16672405c8e 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -552,7 +552,7 @@ def graphics_array(self, ncols=3): nrows, rem = divmod(n,ncols) if rem > 0: nrows += 1 - return plot.graphics_array(frame_list, nrows, ncols) + return plot.graphics_array(frame_list, nrows, ncols) def gif(self, delay=20, savefile=None, iterations=0, show_path=False, use_ffmpeg=False): diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 387a5dc04da..3b583082a9a 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1168,8 +1168,7 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', x, y = var('x,y') sphinx_plot(plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5)) """ - if initial_depth >= max_depth: - max_depth = initial_depth + max_depth = max(max_depth, initial_depth) from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid(f, [x_range,y_range], plot_points=2) diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 1f5f8f4739a..05d6bb6e583 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -437,8 +437,10 @@ def frame3d(lower_left, upper_right, **kwds): """ x0, y0, z0 = lower_left x1, y1, z1 = upper_right - L1 = line3d([(x0, y0, z0), (x0, y1, z0), (x1, y1, z0), (x1, y0, z0), (x0, y0, z0), # top square - (x0, y0, z1), (x0, y1, z1), (x1, y1, z1), (x1, y0, z1), (x0, y0, z1)], # bottom square + L1 = line3d([(x0, y0, z0), (x0, y1, z0), (x1, y1, z0), + (x1, y0, z0), (x0, y0, z0), # top square + (x0, y0, z1), (x0, y1, z1), (x1, y1, z1), + (x1, y0, z1), (x0, y0, z1)], # bottom square **kwds) # 3 additional lines joining top to bottom v2 = line3d([(x0, y1, z0), (x0, y1, z1)], **kwds) diff --git a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py index 6e47726f08f..f688a08a546 100644 --- a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py +++ b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py @@ -281,8 +281,7 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): # Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8). modulus = norm_list[i] * norm_list[i+1] / (scale_list[i] ** 2) - if modulus > 8: - modulus = 8 + modulus = min(modulus, 8) if (modulus > 1) and (((self_chain_det_list[i] / other_chain_det_list[i]) % modulus) != 1): return False diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 4f40e7c0715..06a6f6a671a 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -135,7 +135,7 @@ def pixels(self): """ return self._pil.load() - def _repr_(self): + def _repr_(self) -> str: """ Return string representation. @@ -148,17 +148,17 @@ def _repr_(self): 16x16px 24-bit RGB image """ modestr = { - '1': '{0}x{1}px BW image', - 'L': '{0}x{1}px 8-bit BW image', - 'P': '{0}x{1}px 8-bit Color image', - 'RGB': '{0}x{1}px 24-bit RGB image', - 'RGBA': '{0}x{1}px 32-bit RGBA image', - 'CMYK': '{0}x{1}px 24-bit CMYK image', + '1': '{0}x{1}px BW image', + 'L': '{0}x{1}px 8-bit BW image', + 'P': '{0}x{1}px 8-bit Color image', + 'RGB': '{0}x{1}px 24-bit RGB image', + 'RGBA': '{0}x{1}px 32-bit RGBA image', + 'CMYK': '{0}x{1}px 24-bit CMYK image', 'YCbCr': '{0}x{1}px 24-bit YCbCr mage', - 'LAB': '{0}x{1}px 24-bit LAB image', - 'HSV': '{0}x{1}px 24-bit HSV image', - 'I': '{0}x{1}px 32-bit signed integer image', - 'F': '{0}x{1}px 32-bit float image', + 'LAB': '{0}x{1}px 24-bit LAB image', + 'HSV': '{0}x{1}px 24-bit HSV image', + 'I': '{0}x{1}px 32-bit signed integer image', + 'F': '{0}x{1}px 32-bit float image', } try: mode = modestr[self.pil.mode] @@ -285,9 +285,9 @@ def _rich_repr_(self, display_manager, **kwds): return types = display_manager.types preferred = ( - ('PNG', types.OutputImagePng), + ('PNG', types.OutputImagePng), ('JPEG', types.OutputImageJpg), - ('GIF', types.OutputImageGif), + ('GIF', types.OutputImageGif), ) from sage.repl.rich_output.buffer import OutputBuffer for format, output_container in preferred: diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 7f7c16ceb67..d6e5a7d05b1 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -2619,7 +2619,7 @@ def ComplexDoubleField(): from sage.misc.parser import Parser -cdef cdf_parser = Parser(float, float, {"I" : _CDF.gen(), "i" : _CDF.gen()}) +cdef cdf_parser = Parser(float, float, {"I": _CDF.gen(), "i": _CDF.gen()}) cdef inline double complex extract_double_complex(ComplexDoubleElement x) noexcept: """ diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 9b56a36ce9f..d6bcb664a49 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -2103,7 +2103,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): cdef MPComplexNumber z, x x = self z = x._new() - mpc_mul_2si(z.value , x.value, n, (x._parent).__rnd) + mpc_mul_2si(z.value, x.value, n, (x._parent).__rnd) return z def __rshift__(self, n): @@ -2122,7 +2122,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): cdef MPComplexNumber z, x x = self z = x._new() - mpc_div_2si(z.value , x.value, n, (x._parent).__rnd) + mpc_div_2si(z.value, x.value, n, (x._parent).__rnd) return z def nth_root(self, n, all=False): 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 15809061112..2269085539d 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 @@ -162,7 +162,7 @@ def __init__(self, gen, category): self._frobenius_trace = None self._frobenius_charpoly = None - def _frobenius_crystalline_matrix(self): + def _frobenius_matrix_crystalline(self): r""" Return the matrix representing the Frobenius endomorphism on the crystalline cohomology of the Drinfeld module. This is done up to @@ -180,7 +180,7 @@ def _frobenius_crystalline_matrix(self): sage: K. = Fq.extension(6) sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) - sage: phi._frobenius_crystalline_matrix() + sage: phi._frobenius_matrix_crystalline() [...((z2 + 3) + z12 + (4*z2 + 1)*z12^2 + (z2 + 4)*z12^3 + (z2 + 4)*z12^4 + (2*z2 + 3)*z12^5)*T^3 + (2*z2 + 2*z2*z12 + (2*z2 + 3)*z12^2 + ... + (3*z2 + 4)*z12^3 + (2*z2 + 3)*z12^4 + 3*z2*z12^5] ALGORITHM: @@ -257,7 +257,7 @@ def frobenius_endomorphism(self): deg = self.base_over_constants_field().degree_over() return self._Hom_(self, category=self.category())(t**deg) - def frobenius_charpoly(self, var='X', algorithm='crystalline'): + def frobenius_charpoly(self, var='X', algorithm=None): r""" Return the characteristic polynomial of the Frobenius endomorphism. @@ -290,10 +290,30 @@ def frobenius_charpoly(self, var='X', algorithm='crystalline'): INPUT: - - ``var`` -- (default: ``'X'``) the name of the second variable - - ``algorithm`` -- (default: ``'crystalline'``) the algorithm + - ``var`` (default: ``'X'``) -- the name of the second variable + - ``algorithm`` (default: ``None``) -- the algorithm used to compute the characteristic polynomial + .. NOTE: + + Available algorithms are: + + - ``'CSA'`` -- it exploits the fact that `K\{\tau\}` is a + central simple algebra (CSA) over `\mathbb + F_q[\text{Frob}_\phi]` (see Chapter 4 of [CL2023]_). + - ``'crystalline'`` -- it uses the action of the Frobenius + on the crystalline cohomology (see [MS2023]_). + - ``'gekeler'`` -- it tries to identify coefficients by + writing that the characteristic polynomial annihilates the + Frobenius endomorphism; this algorithm may fail is some + cases (see [Gek2008]_). + - ``'motive'`` -- it uses the action of the Frobenius on the + Anderson motive (see Chapter 2 of [CL2023]_). + + The method raises an exception if the user asks for an + unimplemented algorithm, even if the characteristic polynomial + has already been computed. + EXAMPLES:: sage: Fq = GF(25) @@ -310,7 +330,7 @@ def frobenius_charpoly(self, var='X', algorithm='crystalline'): sage: A. = Fq[] sage: K. = Fq.extension(2) sage: phi = DrinfeldModule(A, [1, 0, z6]) - sage: chi = phi.frobenius_charpoly() + sage: chi = phi.frobenius_charpoly(algorithm='crystalline') sage: chi X^2 + ((3*z3^2 + z3 + 4)*T + 4*z3^2 + 6*z3 + 3)*X + (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3 @@ -319,6 +339,9 @@ def frobenius_charpoly(self, var='X', algorithm='crystalline'): sage: frob_pol = phi.frobenius_endomorphism().ore_polynomial() sage: chi(frob_pol, phi(T)) 0 + sage: phi.frobenius_charpoly(algorithm='motive')(phi.frobenius_endomorphism()) + Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1 + Defn: 0 :: @@ -329,33 +352,99 @@ def frobenius_charpoly(self, var='X', algorithm='crystalline'): ALGORITHM: - By default, this method uses the so-called *crystalline* - algorithm which computes the characteristic polynomial of the - Frobenius acting on the crystalline cohomology of the Drinfeld - module. For further details, see [Ang1997]_. + If the user specifies an algorithm, then the characteristic + polynomial is computed according to the user's input (see + the note above), even if it had already been computed. + + If no algorithm is given, then the function either returns a + cached value, or if no cached value is available, the + function computes the Frobenius characteristic polynomial + from scratch. In that case, if the rank `r` is less than the + extension degree `n`, then the ``crystalline`` algorithm is + used, while the ``CSA`` algorithm is used otherwise. + + TESTS:: + + sage: Fq = GF(9) + sage: A. = Fq[] + sage: k. = Fq.extension(2) + sage: K. = k.extension(3) + + :: + + sage: phi = DrinfeldModule(A, [K(zk), z^8, z^7]) + sage: phi.frobenius_charpoly(algorithm='CSA') + X^2 + (2*T^3 + (2*z2 + 2)*T^2 + (z2 + 1)*T + 2*z2)*X + z2*T^6 + (2*z2 + 2)*T^3 + 2 + sage: phi.frobenius_charpoly(algorithm='crystalline') + X^2 + (2*T^3 + (2*z2 + 2)*T^2 + (z2 + 1)*T + 2*z2)*X + z2*T^6 + (2*z2 + 2)*T^3 + 2 + sage: phi.frobenius_charpoly(algorithm='gekeler') + X^2 + (2*T^3 + (2*z2 + 2)*T^2 + (z2 + 1)*T + 2*z2)*X + z2*T^6 + (2*z2 + 2)*T^3 + 2 + sage: phi.frobenius_charpoly(algorithm='motive') + X^2 + (2*T^3 + (2*z2 + 2)*T^2 + (z2 + 1)*T + 2*z2)*X + z2*T^6 + (2*z2 + 2)*T^3 + 2 + sage: phi.frobenius_charpoly()(phi.frobenius_endomorphism()).ore_polynomial() + 0 - The available options for 'algorithm' are: + :: - - ``'crystalline'`` -- computes the characteristic polynomial of the - Frobenius endomorphism on the crystalline cohomology of a Drinfeld - module. + sage: phi = DrinfeldModule(A, [K(zk), z^2, z^3, z^4]) + sage: phi.frobenius_charpoly(algorithm='CSA') + X^3 + ((z2 + 1)*T^2 + (z2 + 1)*T + z2 + 2)*X^2 + ((z2 + 2)*T^4 + 2*T^3 + z2*T^2 + T + 2*z2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='crystalline') + X^3 + ((z2 + 1)*T^2 + (z2 + 1)*T + z2 + 2)*X^2 + ((z2 + 2)*T^4 + 2*T^3 + z2*T^2 + T + 2*z2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='gekeler') + X^3 + ((z2 + 1)*T^2 + (z2 + 1)*T + z2 + 2)*X^2 + ((z2 + 2)*T^4 + 2*T^3 + z2*T^2 + T + 2*z2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='motive') + X^3 + ((z2 + 1)*T^2 + (z2 + 1)*T + z2 + 2)*X^2 + ((z2 + 2)*T^4 + 2*T^3 + z2*T^2 + T + 2*z2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly()(phi.frobenius_endomorphism()).ore_polynomial() + 0 - - ``'motive'`` -- based on computing the characteristic polynomial of - the Frobenius endomorphism on the motive of a Drinfeld module. This - instantiates the Frobenius as a morphism object and calls its - ``'characteristic_polynomial'`` method. + :: + + sage: phi = DrinfeldModule(A, [K(zk), z^8, z^7, z^20]) + sage: phi.frobenius_charpoly(algorithm='CSA') + X^3 + (z2*T^2 + z2*T + z2 + 1)*X^2 + (T^4 + (2*z2 + 1)*T^3 + (z2 + 2)*T^2 + (2*z2 + 1)*T + z2 + 2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='crystalline') + X^3 + (z2*T^2 + z2*T + z2 + 1)*X^2 + (T^4 + (2*z2 + 1)*T^3 + (z2 + 2)*T^2 + (2*z2 + 1)*T + z2 + 2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='gekeler') + X^3 + (z2*T^2 + z2*T + z2 + 1)*X^2 + (T^4 + (2*z2 + 1)*T^3 + (z2 + 2)*T^2 + (2*z2 + 1)*T + z2 + 2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly(algorithm='motive') + X^3 + (z2*T^2 + z2*T + z2 + 1)*X^2 + (T^4 + (2*z2 + 1)*T^3 + (z2 + 2)*T^2 + (2*z2 + 1)*T + z2 + 2)*X + T^6 + 2*z2*T^3 + 2*z2 + 1 + sage: phi.frobenius_charpoly()(phi.frobenius_endomorphism()).ore_polynomial() + 0 + + Check that ``var`` inputs are taken into account for cached + characteristic polynomials:: + + sage: Fq = GF(2) + sage: A. = Fq[] + sage: K. = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 1]) + sage: phi.frobenius_charpoly() + X^2 + X + T^2 + T + 1 + sage: phi.frobenius_charpoly(var='Foo') + Foo^2 + Foo + T^2 + T + 1 + sage: phi.frobenius_charpoly(var='Bar') + Bar^2 + Bar + T^2 + T + 1 """ - # Throw an error if the user asks for an unimplemented algorithm - # even if the char poly has already been computed - method_name = f'_frobenius_charpoly_{algorithm}' - if hasattr(self, method_name): + # If no algorithm is specified, return cached data (if it + # exists), or pick an algorithm: + if algorithm is None: if self._frobenius_charpoly is not None: - return self._frobenius_charpoly - self._frobenius_charpoly = getattr(self, method_name)(var) - return self._frobenius_charpoly - raise NotImplementedError(f'algorithm \"{algorithm}\" not implemented') + return self._frobenius_charpoly.change_variable_name(var) + else: + if self.rank() < self._base_degree_over_constants: + algorithm = 'crystalline' + else: + algorithm = 'CSA' + # If an algorithm is specified, do not use cached data, even + # if it is possible: + method_name = f'_frobenius_charpoly_{algorithm}' + if not hasattr(self, method_name): + raise NotImplementedError(f'algorithm "{algorithm}" not implemented') + self._frobenius_charpoly = getattr(self, method_name)() + return self._frobenius_charpoly.change_variable_name(var) - def _frobenius_charpoly_crystalline(self, var): + def _frobenius_charpoly_CSA(self): r""" Return the characteristic polynomial of the Frobenius endomorphism using Crystalline cohomology. @@ -365,11 +454,59 @@ def _frobenius_charpoly_crystalline(self, var): This method is private and should not be directly called. Instead, use :meth:`frobenius_charpoly` with the option - `algorithm='crystalline'`. + `algorithm='CSA'`. - INPUT: + EXAMPLES:: - - ``var`` -- the name of the second variable + sage: Fq = GF(5) + sage: A. = Fq[] + sage: K. = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z^i for i in range(1, 50)]) + sage: phi.frobenius_charpoly(algorithm="CSA") # indirect doctest + X^48 + 4*X^47 + 4*X^46 + X^45 + 3*X^44 + X^42 + 4*X^41 + 4*X^39 + 2*X^37 + 4*X^36 + 3*X^35 + 2*X^33 + (4*T + 2)*X^32 + (4*T + 1)*X^31 + (3*T + 1)*X^30 + 4*T*X^29 + 4*T*X^28 + 2*X^27 + X^26 + (3*T + 4)*X^25 + (4*T + 4)*X^24 + (T + 1)*X^23 + (T + 3)*X^22 + 4*T*X^21 + (2*T + 1)*X^20 + 4*X^19 + 4*T*X^18 + (T + 4)*X^17 + 4*T^2*X^16 + (T^2 + 3*T + 3)*X^15 + (4*T^2 + 3*T + 3)*X^14 + (3*T^2 + 3*T + 3)*X^13 + (3*T^2 + 4*T + 4)*X^12 + (T^2 + 2*T + 2)*X^11 + (3*T^2 + 4*T + 4)*X^10 + (3*T^2 + T + 1)*X^9 + (4*T + 4)*X^8 + (3*T + 3)*X^7 + (T^2 + 3*T + 3)*X^6 + (3*T^2 + T + 1)*X^5 + (2*T^2 + 3*T + 3)*X^4 + (2*T^2 + 3*T + 3)*X^3 + 3*T^2*X^2 + 4*T^2*X + 2*T^3 + T + 1 + + ALGORITHM: + + 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 + rank of the Drinfeld module is large compared to the degree + of the extension `K/\mathbb F_q`. See [CL2023]_. + """ + E = self._base + EZ = PolynomialRing(E, name='Z') + n = self._base_degree_over_constants + f = self.gen() # phi_T, which is updated in the subsequent loop + t = self.ore_variable() + rows = [] + for i in range(n): + m = f.degree() + 1 + row = [EZ([f[jj] for jj in range(j, m, n)]) for j in range(n)] + rows.append(row) + f = t * f + chi = Matrix(rows).charpoly() + # Format the result + K = self.base_over_constants_field() + A = self.function_ring() + n = self._base_degree_over_constants + r = self.rank() + lc = chi[0][r] + coeffs = [A([K(chi[i][j]/lc).in_base() + for i in range((r-j)*n // r + 1)]) + for j in range(r+1)] + return PolynomialRing(A, name='X')(coeffs) + + def _frobenius_charpoly_crystalline(self): + r""" + Return the characteristic polynomial of the Frobenius + endomorphism using Crystalline cohomology. + + The algorithm works for Drinfeld `\mathbb{F}_q[T]`-modules of + any rank. + + This method is private and should not be directly called. + Instead, use :meth:`frobenius_charpoly` with the option + `algorithm='crystalline'`. OUTPUT: a univariate polynomial with coefficients in the function ring @@ -413,17 +550,96 @@ def _frobenius_charpoly_crystalline(self, var): of section 6.3 in [MS2023]_. """ A = self.function_ring() - K = self.base_over_constants_field() - charpoly_K = self._frobenius_crystalline_matrix() \ - .charpoly(var).coefficients(sparse=False) + charpoly_K = self._frobenius_matrix_crystalline().charpoly().list() # The above line obtains the char poly with coefficients in K[T] # This maps them into A = Fq[T] coeffs_A = [A([x.in_base() for x in coeff]) for coeff in charpoly_K] - return PolynomialRing(A, name=var)(coeffs_A) + return PolynomialRing(A, name='X')(coeffs_A) + + def _frobenius_charpoly_gekeler(self): + r""" + Return the characteristic polynomial of the Frobenius + endomorphism using Gekeler's algorithm. + + The algorithm works for Drinfeld `\mathbb{F}_q[T]`-modules of + any rank, provided that the constant coefficient is a generator + of the base field. + + This method is private and should not be directly called. + Instead, use :meth:`frobenius_charpoly` with the option + `algorithm='gekeler'`. + + .. WARNING: + + This algorithm only works in the generic case when the + corresponding linear system is invertible. Notable cases + where this fails include Drinfeld modules whose minimal + polynomial is not equal to the characteristic polynomial, + and rank 2 Drinfeld modules where the degree 1 coefficient + of `\phi_T` is 0. In that case, an exception is raised. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A. = Fq[] + sage: K. = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z, 4, 1, z]) + sage: phi.frobenius_charpoly(algorithm='gekeler') # indirect doctest + X^3 + ((z2 + 2)*T^2 + (z2 + 2)*T + 4*z2 + 4)*X^2 + ... + (3*z2 + 2)*T^2 + (3*z2 + 3)*T + 4 + + :: + + sage: Fq = GF(125) + sage: A. = Fq[] + sage: K. = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, z]) + sage: phi.frobenius_charpoly(algorithm='gekeler') # indirect doctest + Traceback (most recent call last): + NotImplementedError: 'gekeler' algorithm failed + + ALGORITHM: - def _frobenius_charpoly_motive(self, var): + Construct a linear system based on the requirement that the + Frobenius satisfies a degree r polynomial with coefficients in + the function ring. This generalizes the procedure from + [Gek2008]_ for the rank 2 case. + """ + K = self.base_over_constants_field() + A = self.function_ring() + r, n = self.rank(), self._base_degree_over_constants + # Compute constants that determine the block structure of the + # linear system. The system is prepared such that the solution + # vector has the form [a_0, a_1, ... a_{r-1}]^T with each a_i + # corresponding to a block of length (n*(r - i))//r + 1 + shifts = [(n*(r - i))//r + 1 for i in range(r)] + rows, cols = n*r + 1, sum(shifts) + block_shifts = [0] + for i in range(r-1): + block_shifts.append(block_shifts[-1] + shifts[i]) + # Compute the images \phi_T^i for i = 0 .. n. + gen_powers = [self(A.gen()**i).coefficients(sparse=False) + for i in range(0, n + 1)] + sys, vec = Matrix(K, rows, cols), vector(K, rows) + vec[rows - 1] = -1 + for j in range(r): + for k in range(shifts[j]): + for i in range(len(gen_powers[k])): + sys[i + n*j, block_shifts[j] + k] = gen_powers[k][i] + if sys.right_nullity() != 0: + raise NotImplementedError("'gekeler' algorithm failed") + sol = list(sys.solve_right(vec)) + # The system is solved over K, but the coefficients should all + # be in Fq We project back into Fq here. + sol_Fq = [K(x).vector()[0] for x in sol] + char_poly = [] + for i in range(r): + char_poly.append([sol_Fq[block_shifts[i] + j] + for j in range(shifts[i])]) + return PolynomialRing(A, name='X')(char_poly + [1]) + + def _frobenius_charpoly_motive(self): r""" Return the characteristic polynomial of the Frobenius endomorphism using Motivic cohomology. @@ -435,10 +651,6 @@ def _frobenius_charpoly_motive(self, var): Instead, use :meth:`frobenius_charpoly` with the option `algorithm='motive'`. - INPUT: - - - ``var`` -- the name of the second variable - OUTPUT: a univariate polynomial with coefficients in the function ring @@ -470,7 +682,7 @@ def _frobenius_charpoly_motive(self, var): sage: phi.frobenius_charpoly(algorithm='motive') # indirect doctest X^11 + (z3^2 + 2*z3)*X^10 + ((z3 + 1)*T + z3)*X^9 + ((2*z3^2 + z3 + 2)*T^2 + ... + (2*z3^2 + 2*z3 + 2)*T + z3^2 """ - return self.frobenius_endomorphism().characteristic_polynomial(var) + return self.frobenius_endomorphism().characteristic_polynomial('X') def frobenius_norm(self): r""" @@ -478,9 +690,25 @@ def frobenius_norm(self): Let `C(X) = \sum_{i=0}^r a_iX^{i}` denote the characteristic polynomial of the Frobenius endomorphism. The Frobenius norm - is `(-1)^r a_{0}`. This is an element of the regular function ring - and if `n` is the degree of the base field over `\mathbb{F}_q`, - then the Frobenius norm has degree `n`. + is `a_{0}`, and given by the formula + + .. MATH:: + + a_0 = (-1)^{nr - n -r} + \mathrm{Norm}_{K/\mathbb F_q}(\Delta)^{-1} + p^{n / \mathrm{deg}(p)}, + + where `K` is the ground field, which as degree `n` over + `\mathbb F_q`, `r` is the rank of the Drinfeld module, + and `\Delta` is the leading coefficient of the generator. + This formula is given in Theorem~4.2.7 of [Pap2023]_. + + Note that the Frobenius norm computed by this method may be + different than what is computed as the isogeny norm of the + Frobenius endomorphism (see :meth:`norm` on the Frobenius + endomorphism), which is an ideal defined of the function ring + given by its monic generator; the Frobenius norm may not be + monic. EXAMPLES:: @@ -488,19 +716,28 @@ def frobenius_norm(self): sage: A. = Fq[] sage: K. = Fq.extension(2) sage: phi = DrinfeldModule(A, [1, 0, z6]) - sage: B = phi.frobenius_norm() - sage: B + sage: frobenius_norm = phi.frobenius_norm() + sage: frobenius_norm (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3 :: sage: n = 2 # Degree of the base field over Fq - sage: B.degree() == n + sage: frobenius_norm.degree() == n True :: - sage: B == phi.frobenius_charpoly()[0] + sage: frobenius_norm == phi.frobenius_charpoly()[0] + True + + :: + + sage: lc = frobenius_norm.leading_coefficient() + sage: isogeny_norm = phi.frobenius_endomorphism().norm() + sage: isogeny_norm.gen() == frobenius_norm / lc + True + sage: A.ideal(frobenius_norm) == isogeny_norm True ALGORITHM: @@ -512,12 +749,15 @@ def frobenius_norm(self): return self._frobenius_norm K = self.base_over_constants_field() n = K.degree(self._Fq) - char = self.characteristic() + r = self.rank() + p = self.characteristic() norm = K(self.coefficients()[-1]).norm() - self._frobenius_norm = ((-1)**n)*(char**(n/char.degree())) / norm + self._frobenius_norm = (-1) ** (n*r - n - r) \ + * norm**(-1) \ + * p ** (n//p.degree()) return self._frobenius_norm - def frobenius_trace(self): + def frobenius_trace(self, algorithm=None): r""" Return the Frobenius trace of the Drinfeld module. @@ -527,44 +767,145 @@ def frobenius_trace(self): and if `n` is the degree of the base field over `\mathbb{F}_q`, then the Frobenius trace has degree at most `\frac{n}{r}`. + INPUT: + + - ``algorithm`` (default: ``None``) -- the algorithm + used to compute the characteristic polynomial + + .. NOTE: + + Available algorithms are: + + - ``'CSA'`` -- it exploits the fact that `K\{\tau\}` is a + central simple algebra (CSA) over `\mathbb + F_q[\text{Frob}_\phi]` (see Chapter 4 of [CL2023]_). + - ``'crystalline'`` -- it uses the action of the Frobenius + on the crystalline cohomology (see [MS2023]_). + + The method raises an exception if the user asks for an + unimplemented algorithm, even if the characteristic has already + been computed. See :meth:`frobenius_charpoly` for more details. + EXAMPLES:: sage: Fq = GF(343) sage: A. = Fq[] sage: K. = Fq.extension(2) sage: phi = DrinfeldModule(A, [1, 0, z6]) - sage: A = phi.frobenius_trace() - sage: A + sage: frobenius_trace = phi.frobenius_trace() + sage: frobenius_trace (4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4 :: sage: n = 2 # Degree over Fq of the base codomain - sage: A.degree() <= n/2 + sage: frobenius_trace.degree() <= n/2 True :: - sage: A == -phi.frobenius_charpoly()[1] + sage: frobenius_trace == -phi.frobenius_charpoly()[1] True + One can specify an algorithm:: + + sage: psi = DrinfeldModule(A, [z6, 1, z6^3, z6 + 1]) + sage: psi.frobenius_trace(algorithm='crystalline') + z3^2 + 6*z3 + 2 + sage: psi.frobenius_trace(algorithm='CSA') + z3^2 + 6*z3 + 2 + ALGORITHM: - We extract the coefficient of `X^{r-1}` from the characteristic - polynomial if it has been previously computed, otherwise we compute - the trace of the matrix of the Frobenius acting on the crystalline - cohomology. + If the user specifies an algorithm, then the trace is + computed according to the user's input (see the note above), + even if the Frobenius trace or the Frobenius characteristic + polynomial had already been computed. + + If no algorithm is given, then the function either returns a + cached value, or if no cached value is available, the + function computes the Frobenius trace from scratch. In that + case, if the rank `r` is less than the extension degree `n`, + then the ``crystalline`` algorithm is used, while the + ``CSA`` algorithm is used otherwise. + + TESTS: + + These test values are taken from :meth:`frobenius_charpoly`:: + + sage: Fq = GF(9) + sage: A. = Fq[] + sage: k. = Fq.extension(2) + sage: K. = k.extension(3) + + :: + + sage: phi = DrinfeldModule(A, [K(zk), z^8, z^7]) + sage: phi.frobenius_trace(algorithm='CSA') + T^3 + (z2 + 1)*T^2 + (2*z2 + 2)*T + z2 + sage: phi.frobenius_trace(algorithm='crystalline') + T^3 + (z2 + 1)*T^2 + (2*z2 + 2)*T + z2 + sage: charpoly = phi.frobenius_charpoly() + sage: trace = phi.frobenius_trace() + sage: trace == -charpoly[1] + True + + :: + + sage: phi = DrinfeldModule(A, [K(zk), z^2, z^3, z^4]) + sage: phi.frobenius_trace(algorithm='CSA') + (2*z2 + 2)*T^2 + (2*z2 + 2)*T + 2*z2 + 1 + sage: phi.frobenius_trace(algorithm='crystalline') + (2*z2 + 2)*T^2 + (2*z2 + 2)*T + 2*z2 + 1 + sage: charpoly = phi.frobenius_charpoly() + sage: trace = phi.frobenius_trace() + sage: trace == -charpoly[2] + True + + :: + + sage: phi = DrinfeldModule(A, [K(zk), z^8, z^7, z^20]) + sage: phi.frobenius_trace(algorithm='CSA') + 2*z2*T^2 + 2*z2*T + 2*z2 + 2 + sage: phi.frobenius_trace(algorithm='crystalline') + 2*z2*T^2 + 2*z2*T + 2*z2 + 2 + sage: charpoly = phi.frobenius_charpoly() + sage: trace = phi.frobenius_trace() + sage: trace == -charpoly[2] + True """ - K = self.base_over_constants_field() - A = self.function_ring() - if self._frobenius_trace is not None: + if algorithm is None: + # If no algorithm is specified, return cached data (if it + # exists), or pick an algorithm: + # However, if an algorithm is specified, do not use cached + # data, even if it is possible + if self._frobenius_trace is not None: + return self._frobenius_trace + if self._frobenius_charpoly is not None: + self._frobenius_trace = -self._frobenius_charpoly \ + .coefficients(sparse=False)[-2] + return self._frobenius_trace + else: + if self.rank() < self._base_degree_over_constants: + algorithm = 'crystalline' + else: + algorithm = 'CSA' + # We first check if a matrix method is available + matrix_method_name = f'_frobenius_matrix_{algorithm}' + if hasattr(self, matrix_method_name): + matrix = getattr(self, matrix_method_name)() + trace = matrix.trace() + A = self.function_ring() + self._frobenius_trace = A([x.in_base() for x in trace]) + return self._frobenius_trace + # If it is not, we look for a charpoly method + charpoly_method_name = f'_frobenius_charpoly_{algorithm}' + if hasattr(self, charpoly_method_name): + charpoly = getattr(self, charpoly_method_name)() + self._frobenius_trace = -charpoly.list()[-2] return self._frobenius_trace - if self._frobenius_charpoly is not None: - self._frobenius_trace = -self._frobenius_charpoly \ - .coefficients(sparse=False)[-2] - self._frobenius_trace = self._frobenius_crystalline_matrix().trace() - self._frobenius_trace = A([x.in_base() for x in self._frobenius_trace]) - return self._frobenius_trace + # If all fail, we raise an error + raise NotImplementedError(f'algorithm "{algorithm}" not implemented') def invert(self, ore_pol): r""" @@ -657,7 +998,6 @@ def invert(self, ore_pol): # Write the system and solve it k = deg // r A = self._function_ring - T = A.gen() mat_rows = [[E.zero() for _ in range(k+1)] for _ in range(k+1)] mat_rows[0][0] = E.one() phiT = self.gen() diff --git a/src/sage/rings/function_field/element.pyx b/src/sage/rings/function_field/element.pyx index d198f2694a4..f64c223f18b 100644 --- a/src/sage/rings/function_field/element.pyx +++ b/src/sage/rings/function_field/element.pyx @@ -45,6 +45,8 @@ AUTHORS: - Maarten Derickx (2011-09-11): added doctests, fixed pickling - Kwankyu Lee (2017-04-30): added elements for global function fields + +- Vincent Macri (2024-09-03): added subs method """ # ***************************************************************************** # Copyright (C) 2010 William Stein @@ -57,6 +59,7 @@ AUTHORS: # 2018-2020 Travis Scrimshaw # 2019 Brent Baccala # 2021 Saher Amasha +# 2024 Vincent Macri # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -174,6 +177,260 @@ cdef class FunctionFieldElement(FieldElement): """ return self._x._latex_() + def subs(self, in_dict=None, **kwds): + r""" + Substitute the given generators with given values while not touching + other generators. + + INPUT: + + - ``in_dict`` -- (optional) dictionary of inputs + + - ``**kwds`` -- named parameters + + OUTPUT: new object if substitution is possible, otherwise ``self`` + + EXAMPLES: + + Basic substitution:: + + sage: K = GF(7) + sage: Kx. = FunctionField(K) + sage: y = polygen(Kx) + sage: f = x^6 + 3; f + x^6 + 3 + + We also substitute the generators in any base fields:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: S. = L[] + sage: M. = L.extension(t^2 - x*y) + sage: f = 7 * t + 3*x*y + sage: f.subs(t=9) + 3*x*y + 63 + sage: f.subs(x=2, y=4) + 7*t + 24 + sage: f.subs(t=1, x=2, y=3) + 25 + + Because of the possibility of extension fields, a generator to + substitute must be specified:: + + sage: K. = FunctionField(QQ) + sage: f = x + sage: f.subs(2) + Traceback (most recent call last): + ... + TypeError: in_dict must be a dict + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: f = x + y + sage: f.subs(0) + Traceback (most recent call last): + ... + TypeError: in_dict must be a dict + + We can also substitute using dictionary syntax:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: S. = L[] + sage: M. = L.extension(t^2 - x*y) + sage: f = x + y + t + sage: f.subs({x: 1, y: 3, t: 4}) + 8 + sage: f.subs({x: 1, t: 4}) + y + 5 + + TESTS: + + Check that we correctly handle extension fields:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: S. = L[] + sage: M. = L.extension(t^2 - x*y) + sage: f = t + x*y + sage: f.subs(x=1, y=3, t=5) + 8 + sage: f_sub = f.subs(x=1); f_sub + t + y + sage: f_sub.parent() == f.parent() + True + sage: f.subs(y=2) + t + 2*x + sage: f_sub = f.subs(x=1, y=1, t=1); f_sub + 2 + sage: f_sub.parent() == M + True + + Test that substitution works for rational functions:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(y^4 - 3) + sage: f = x / y + sage: f.subs(x=2) == 2 / y + True + sage: f.subs(y=3) + 9*x + sage: f.subs(t=-1) is f + True + sage: f.subs({x: 2, y: 4}) + 128/3 + + Make sure that we return the same object when there is no + substitution:: + + sage: K = GF(7) + sage: Kx. = FunctionField(K) + sage: y = polygen(Kx) + sage: f = x^6 + 3 + sage: g = f.subs(z=2) + sage: g == f + True + sage: g is f + True + + Same purpose as above but over an extension field over the rationals:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: S. = L[] + sage: M. = L.extension(t^2 - x*y) + sage: f = t + x*y + sage: f.subs() is f + True + sage: f.subs(w=7) is f + True + sage: f.subs(w=7) is f.subs(w=7) + True + sage: f.subs(y=y) is f + True + sage: f.subs({y: y}) is f + True + sage: f.subs(x=x, y=y, t=t) is f + True + + Test proper handling of not making substitutions:: + + sage: K. = FunctionField(QQ) + sage: f = x + sage: f.subs() is f + True + sage: f.subs(dict()) is f + True + sage: f.subs(w=0) is f + True + sage: R. = K[] + sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: f = 3*y + sage: f.subs(x=0) + 3*y + sage: f = 3*y + sage: f.subs(x=0, y=y) + 3*y + + Test error handling for wrong argument type:: + + sage: K. = FunctionField(QQ) + sage: f = x + sage: f.subs(0) + Traceback (most recent call last): + ... + TypeError: in_dict must be a dict + + Test error handling for dictionary with keys that don't match + generators:: + + sage: K. = FunctionField(QQ) + sage: f = x + sage: f.subs({1: 1}) + Traceback (most recent call last): + ... + TypeError: key does not match any field generators + + Test error handling with ambiguously named generators:: + + sage: K. = FunctionField(QQ) + sage: R. = K[] + sage: L. = K.extension(x^3 - x) + sage: str(L.gen()) == str(K.gen()) + True + sage: f = K.gen() - L.gen() + sage: f.subs(x=2) + Traceback (most recent call last): + ... + TypeError: multiple generators have the same name, making substitution ambiguous. Rename generators or pass substitution values in using dictionary format + sage: f.subs({K.gen(): 1}) + -x + 1 + sage: f.subs({L.gen(): 2}) + x - 2 + sage: f.subs({K.gen(): 1, L.gen(): 2}) + -1 + sage: f.subs({K.gen(): 2, L.gen(): 1}) + 1 + """ + def sub_recurse(ff_element, sub_dict): + # Helper method to recurse through base fields. + ff = ff_element.parent() + if ff.base_field() == ff: + return ff(ff_element._x.subs({ff.gen(): sub_dict[ff.gen()]})) + total = ff.zero() + for i, v in enumerate(list(ff_element._x)): + total += sub_recurse(v, sub_dict) * sub_dict[ff.gen()]**i + return ff(total) + + if in_dict is None and kwds is None: + return self + + if in_dict is not None and not isinstance(in_dict, dict): + raise TypeError('in_dict must be a dict') + + field_tower = [self.parent()] + ff = self.parent() + + while ff.base_field() != ff: + ff = ff.base_field() + field_tower.append(ff) + sub_dict = {f.gen(): f.gen() for f in field_tower} + + made_substitution = False + if in_dict is not None: + for k, v in in_dict.items(): + if k not in sub_dict: + raise TypeError('key does not match any field generators') + sub_dict[k] = v + if v != k: + made_substitution = True + else: + used_kwds = {k: False for k in kwds} + for g in sub_dict: + strg = str(g) + if strg not in kwds: + continue + v = kwds[strg] + sub_dict[g] = v + + if used_kwds[strg]: + raise TypeError('multiple generators have the ' + 'same name, making substitution ' + 'ambiguous. Rename generators ' + 'or pass substitution values in ' + 'using dictionary format') + used_kwds[strg] = True + if g != v: + made_substitution = True + + if made_substitution: + return sub_recurse(self, sub_dict) + return self + @cached_method def matrix(self, base=None): r""" @@ -248,7 +505,7 @@ cdef class FunctionFieldElement(FieldElement): # with this element; make matrix whose rows are the coefficients of the # result, and transpose V, f, t = self.parent().vector_space(base) - rows = [ t(self*f(b)) for b in V.basis() ] + rows = [t(self*f(b)) for b in V.basis()] from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(V.base_field(), V.dimension()) ret = MS(rows) @@ -326,7 +583,7 @@ cdef class FunctionFieldElement(FieldElement): sage: f.degree() 1 """ - return max(self._x.denominator().degree(),self._x.numerator().degree()) + return max(self._x.denominator().degree(), self._x.numerator().degree()) def characteristic_polynomial(self, *args, **kwds): """ @@ -681,7 +938,7 @@ cdef class FunctionFieldElement(FieldElement): v = self.valuation(place) if v > 0: return R.zero() - if v == 0: + if v == 0: return to_R(self) # v < 0 raise ValueError('has a pole at the place') diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index 74bdd6e246c..0ffac369720 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -1677,8 +1677,7 @@ def p_adic_LLL_bound(SUK, A, prec=106): Log_p_Mus = [embedding_to_Kp(a, v, local_prec) for a in Log_p_Mus] m0_Kv_new,increase_precision = p_adic_LLL_bound_one_prime(v, m0_Kv_old, Mus, Log_p_Mus, m0, c3_func(SUK, local_prec), local_prec) - if m0_Kv_old > val: - val = m0_Kv_old + val = max(m0_Kv_old, val) LLL_K0_by_finite_place.append(val) return max(LLL_K0_by_finite_place) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 5fc599d4263..bb16476980e 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8285,8 +8285,7 @@ def _coerce_from_other_number_field(self, x): log_half_root_bound = log2abs(f[0]/2)/n for i in range(1, n): bd = log2abs(f[i])/(n-i) - if bd > log_half_root_bound: - log_half_root_bound = bd + log_half_root_bound = max(bd, log_half_root_bound) # Twice the bound on the roots of f, in other words an upper # bound for the distance between two roots. log_double_root_bound = log_half_root_bound + 2.0 # 2.0 = log2(4) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 53055e1e648..27432813b2b 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1155,7 +1155,7 @@ cdef class NumberFieldElement(NumberFieldElement_base): mpfi_set_prec(a, mpfi_get_prec(v.value)) ZZX_evaluation_mpfi(a, self._numerator, v.value) mpfi_div_z(a, a, den) - mpfr_floor(&a.left ,&a.left) + mpfr_floor(&a.left, &a.left) mpfr_floor(&a.right, &a.right) ans = PY_NEW(Integer) diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index efa3a364547..8b1d4a9cfba 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -1674,8 +1674,7 @@ def reduce(self, index=0, partial=False): col[i] = col[i].reduce(prec) col[i].normalize() dval = col[i].valuation() - prec - if dval < diffval[i-index]: - diffval[i-index] = dval + diffval[i-index] = min(dval, diffval[i-index]) # We update history if self._history is not None: self._history.append(('partial reduce', index, walltime(tme))) @@ -2124,8 +2123,7 @@ def precision_lattice(self, elements=None): col = self._matrix[ref] row = [ x.value() for x in col ] valcol = min([ x.valuation() for x in col ]) - if valcol < val: - val = valcol + val = min(valcol, val) row += (n-len(row)) * [ZZ(0)] rows.append(row) from sage.matrix.constructor import matrix @@ -2719,8 +2717,7 @@ def precision_lattice(self, elements=None): col = self._matrix[ref] row = [ x.value() for x in col ] valcol = min([ x.valuation() for x in col ]) - if valcol < val: - val = valcol + val = min(valcol, val) row += (n-len(row)) * [ZZ(0)] rows.append(row) from sage.matrix.constructor import matrix diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 397dab2ed8e..58d83e40724 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -1649,8 +1649,7 @@ def _matrix_determinant(self, M): for j in range(n): prec = min(prec, S[i,j].precision_absolute()) prec -= S[i,i].valuation() - if prec < relprec: - relprec = prec + relprec = min(prec, relprec) if prec < 0: relprec_neg += prec if relprec_neg < 0: diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 4a2c61286c4..64be9291c49 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -963,8 +963,7 @@ def random_element(self, prec=None): prec = self._prec_cap_absolute x = ZZ.random_element(p**prec) relcap = x.valuation(p) + self._prec_cap_relative - if relcap < prec: - prec = relcap + prec = min(relcap, prec) return self._element_class(self, x, prec=prec) else: if prec is None: @@ -1111,8 +1110,7 @@ def random_element(self, prec=None, integral=False): p = self.prime() x = ZZ.random_element(p**prec) relcap = x.valuation(p) + self._prec_cap_relative - if relcap < prec: - prec = relcap + prec = min(relcap, prec) return self._element_class(self, x*(p**val), prec=prec) # Relaxed diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx index c97dbf9cca3..70b1b3fdcf1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx @@ -253,7 +253,7 @@ def slimgb_libsingular(I): i = sage_ideal_to_singular_ideal(I) r = currRing - if r.OrdSgn!=1 : + if r.OrdSgn != 1: id_Delete(&i, r) raise TypeError("ordering must be global for slimgb") @@ -267,11 +267,11 @@ def slimgb_libsingular(I): result = t_rep_gb(r, i, i.rank, 0) sig_off() - id_Delete(&i,r) + id_Delete(&i, r) - res = singular_ideal_to_sage_sequence(result,r,I.ring()) + res = singular_ideal_to_sage_sequence(result, r, I.ring()) - id_Delete(&result,r) + id_Delete(&result, r) return res @@ -322,19 +322,19 @@ def interred_libsingular(I): singular_options = bck # divide head by coefficients - if r.cf.type != n_Z and r.cf.type != n_Znm and r.cf.type != n_Zn and r.cf.type != n_Z2m : + if r.cf.type != n_Z and r.cf.type != n_Znm and r.cf.type != n_Zn and r.cf.type != n_Z2m: for j from 0 <= j < IDELEMS(result): p = result.m[j] if p: - n = p_GetCoeff(p,r) - n = r.cf.cfInvers(n,r.cf) + n = p_GetCoeff(p, r) + n = r.cf.cfInvers(n, r.cf) result.m[j] = pp_Mult_nn(p, n, r) - p_Delete(&p,r) - n_Delete(&n,r.cf) + p_Delete(&p, r) + n_Delete(&n, r.cf) - id_Delete(&i,r) + id_Delete(&i, r) res = sorted(singular_ideal_to_sage_sequence(result,r,I.ring()),reverse=True) - id_Delete(&result,r) + id_Delete(&result, r) return res diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 318a58e6d9c..d177889bd6e 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -899,7 +899,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if not c: continue mon = p_Init(_ring) - p_SetCoeff(mon, sa2si(c , _ring), _ring) + p_SetCoeff(mon, sa2si(c, _ring), _ring) for pos in m.nonzero_positions(): overflow_check(m[pos], _ring) p_SetExp(mon, ind_map[pos], m[pos], _ring) @@ -929,7 +929,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if not c: continue mon = p_Init(_ring) - p_SetCoeff(mon, sa2si(c , _ring), _ring) + p_SetCoeff(mon, sa2si(c, _ring), _ring) if len(m) != self.ngens(): raise TypeError("tuple key must have same length as ngens") for pos from 0 <= pos < len(m): @@ -1616,7 +1616,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): res = pMDivide(f._poly, g._poly) if coeff: if r.cf.type == n_unknown or r.cf.cfDivBy(p_GetCoeff(f._poly, r), p_GetCoeff(g._poly, r), r.cf): - n = r.cf.cfDiv( p_GetCoeff(f._poly, r) , p_GetCoeff(g._poly, r), r.cf) + n = r.cf.cfDiv(p_GetCoeff(f._poly, r), p_GetCoeff(g._poly, r), r.cf) p_SetCoeff0(res, n, r) else: raise ArithmeticError("Cannot divide these coefficients.") @@ -4158,7 +4158,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): quo = p_Add_q(quo, temp, r) p = pNext(p) return new_MP(parent, quo) - if r.cf.type == n_Znm or r.cf.type == n_Zn or r.cf.type == n_Z2m : + if r.cf.type == n_Znm or r.cf.type == n_Zn or r.cf.type == n_Z2m: raise NotImplementedError("Division of multivariate polynomials over non fields by non-monomials not implemented.") count = singular_polynomial_length_bounded(self._poly, 15) @@ -4468,23 +4468,25 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") # I make a temporary copy of the poly in self because singclap_factorize appears to modify it's parameter - ptemp = p_Copy(self._poly,_ring) + ptemp = p_Copy(self._poly, _ring) iv = NULL sig_on() - if _ring!=currRing: rChangeCurrRing(_ring) # singclap_factorize - I = singclap_factorize ( ptemp, &iv , 0, _ring) + if _ring != currRing: + rChangeCurrRing(_ring) # singclap_factorize + I = singclap_factorize(ptemp, &iv, 0, _ring) sig_off() ivv = iv.ivGetVec() - v = [(new_MP(parent, p_Copy(I.m[i],_ring)) , ivv[i]) for i in range(1,I.ncols)] - v = [(f,m) for f,m in v if f!=0] # we might have zero in there - unit = new_MP(parent, p_Copy(I.m[0],_ring)) + v = [(new_MP(parent, p_Copy(I.m[i], _ring)), ivv[i]) + for i in range(1, I.ncols)] + v = [(f, m) for f, m in v if f != 0] # we might have zero in there + unit = new_MP(parent, p_Copy(I.m[0], _ring)) - F = Factorization(v,unit) + F = Factorization(v, unit) F.sort() del iv - id_Delete(&I,_ring) + id_Delete(&I, _ring) return F @@ -4572,20 +4574,21 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): try: f = parent.coerce(f) except TypeError as msg: - id_Delete(&fI,r) - id_Delete(&_I,r) + id_Delete(&fI, r) + id_Delete(&_I, r) raise TypeError(msg) _I.m[i] = p_Copy((f)._poly, r) - i+=1 + i += 1 - fI.m[0]= p_Copy(self._poly, r) + fI.m[0] = p_Copy(self._poly, r) - if r!=currRing: rChangeCurrRing(r) # idLift + if r != currRing: + rChangeCurrRing(r) # idLift sig_on() res = idLift(_I, fI, NULL, 0, 0, 0) sig_off() - if errorreported != 0 : + if errorreported != 0: errorcode = errorreported errorreported = 0 if errorcode == 1: @@ -4602,7 +4605,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): id_Delete(&res, r) return Sequence(l, check=False, immutable=True) - def reduce(self,I): + def reduce(self, I): r""" Return a remainder of this polynomial modulo the polynomials in ``I``. @@ -4858,7 +4861,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): return right if _ring.cf.type != n_unknown: - if _ring.cf.type == n_Znm or _ring.cf.type == n_Zn or _ring.cf.type == n_Z2m : + if _ring.cf.type == n_Znm or _ring.cf.type == n_Zn or _ring.cf.type == n_Z2m: raise NotImplementedError("GCD over rings not implemented.") if n_GetChar(_ring.cf) > 1<<29: @@ -4929,7 +4932,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): if _ring!=currRing: rChangeCurrRing(_ring) if _ring.cf.type != n_unknown: - if _ring.cf.type == n_Znm or _ring.cf.type == n_Zn or _ring.cf.type == n_Z2m : + if _ring.cf.type == n_Znm or _ring.cf.type == n_Zn or _ring.cf.type == n_Z2m: raise TypeError("LCM over non-integral domains not available.") if self._parent is not g._parent: @@ -4944,7 +4947,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): + singular_polynomial_length_bounded(_g._poly,20) if count >= 20: sig_on() - if _ring!=currRing: rChangeCurrRing(_ring) # singclap_gcd + if _ring != currRing: + rChangeCurrRing(_ring) # singclap_gcd gcd = singclap_gcd(p_Copy(self._poly, _ring), p_Copy(_g._poly, _ring), _ring ) prod = pp_Mult_qq(self._poly, _g._poly, _ring) ret = p_Divide(prod, gcd, _ring) @@ -5476,12 +5480,15 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): elif not self._parent._base.is_field(): raise ValueError("Resultants require base fields or integer base ring.") - cdef int count = singular_polynomial_length_bounded(self._poly,20) \ + cdef int count = singular_polynomial_length_bounded(self._poly, 20) \ + singular_polynomial_length_bounded(other._poly,20) if count >= 20: sig_on() if _ring != currRing: rChangeCurrRing(_ring) # singclap_resultant - rt = singclap_resultant(p_Copy(self._poly, _ring), p_Copy(other._poly, _ring), p_Copy((variable)._poly , _ring ), _ring) + rt = singclap_resultant(p_Copy(self._poly, _ring), + p_Copy(other._poly, _ring), + p_Copy((variable)._poly, _ring ), + _ring) if count >= 20: sig_off() return new_MP(self._parent, rt) diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index c20666b0403..37381c084ac 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -1484,7 +1484,8 @@ def _groebner_strategy(self): g.reduction_strategy.opt_red_tail = True return g - def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, verbose=False, **kwds): + def solve(self, algorithm='polybori', n=1, + eliminate_linear_variables=True, verbose=False, **kwds): r""" Find solutions of this boolean polynomial system. diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2338bbcb34f..9470d56686c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -2938,7 +2938,7 @@ cdef class Polynomial(CommutativePolynomial): q, r = q.quo_rem(p) if r != 0: if sparse: - tmp = self.parent()({e*k : d[k]**e for k in d}) + tmp = self.parent()({e*k: d[k]**e for k in d}) else: tmp = [0] * (e * len(c) - e + 1) for i in range(len(c)): @@ -3526,7 +3526,7 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes (2006-05-25) """ - return self._parent(polynomial_fateman._mul_fateman_mul(self,right)) + return self._parent(polynomial_fateman._mul_fateman_mul(self, right)) @cython.boundscheck(False) @cython.wraparound(False) @@ -5953,7 +5953,7 @@ cdef class Polynomial(CommutativePolynomial): # sylvester_matrix() in multi_polynomial.pyx. if self._parent != right.parent(): - a, b = coercion_model.canonical_coercion(self,right) + a, b = coercion_model.canonical_coercion(self, right) variable = a.parent()(self.variables()[0]) #We add the variable to cover the case that right is a multivariate #polynomial diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 6ef9f6ab097..a30091c9cd8 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -2919,7 +2919,7 @@ def _solve_linear_de(R, N, L, a, b, f0): product = (term1 * term2).list() # todo: perhaps next loop could be made more efficient - c = b[L2 : L] + c = b[L2:L] for j in range(L2 - 1, min(L-1, len(product))): c[j - (L2-1)] = c[j - (L2-1)] + product[j] diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 0e6f2e69609..47508909c91 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -496,8 +496,7 @@ def range_by_height(self, start, end=None): if end is None: end = start start = 1 - if start < 1: - start = 1 + start = max(start, 1) for height in ZZ.range(start, end): if height == 1: yield self(0) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index a4bd1dd51d5..0eba4c662ec 100755 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -1018,8 +1018,7 @@ def degree(self): poly_numerator = poly.numerator() poly_denominator = poly.denominator() degree = max(poly_numerator.degree(), poly_denominator.degree()) - if degree > max_degree: - max_degree = degree + max_degree = max(degree, max_degree) # polynomial affine map elif poly.degree() > max_degree: max_degree = poly.degree() diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 8eff3715338..7c8cf62c5ea 100755 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1103,8 +1103,7 @@ def quadratic_transform(self): degs = [G.degree()]*len(L) for F in G.monomials(): for i in range(len(L)): - if F.degree(L[i]) < degs[i]: - degs[i] = F.degree(L[i]) + degs[i] = min(F.degree(L[i]), degs[i]) T = [] for item in G.dict().items(): tup = tuple([item[0][i] - degs[i] for i in range(len(L))]) diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index a1520670e15..25d21fbd1a2 100755 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -873,8 +873,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, # Try harder to compute the Heegner index, where it matters if heegner_index is None: - if max_height < 18: - max_height = 18 + max_height = max(max_height, 18) for D in BSD.heegner_index_upper_bound: M = BSD.heegner_index_upper_bound[D] for p in kolyvagin_primes: diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 15c9f80fde1..ba752e11c10 100755 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3433,8 +3433,7 @@ def compute_isogeny_bmss(E1, E2, l): sprec = 8 while sprec < 4 * l: assert sprec % 2 == 0 - if sprec > 2 * l: - sprec = 2 * l + sprec = min(sprec, 2 * l) # s1 => s1 + x^k s2 # 2 s1' s2' - dG/dS(x, s1) s2 = G(x, s1) - s1'2 s1 = S diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 993c25f38db..1b7a52b0ed0 100755 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -6304,8 +6304,7 @@ def point_preprocessing(free,tor): c1_LLL = -R.one() for i in range(n): tmp = R(b1_norm/(m_gram.row(i).norm())) - if tmp > c1_LLL: - c1_LLL = tmp + c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') @@ -6630,8 +6629,7 @@ def reduction_at(p): c1_LLL = -R.one() for i in range(n): tmp = R(b1_norm/(m_gram.row(i).norm())) - if tmp > c1_LLL: - c1_LLL = tmp + c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') d_L_0 = R(b1_norm**2 / c1_LLL) @@ -6978,8 +6976,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): c1_LLL = -R.one() for i in range(n): tmp = R(b1_norm/(m_gram.row(i).norm())) - if tmp > c1_LLL: - c1_LLL = tmp + c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') d_L_0 = R(b1_norm**2 / c1_LLL) diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 4721ef67951..1fcc30764b2 100755 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -629,8 +629,7 @@ def _e_bounds(self, n, prec): res = [enj] for j in range(1,prec): bino = valuation(binomial(pn,j),self._p) - if bino < enj: - enj = bino + enj = min(bino, enj) res.append(enj) return res diff --git a/src/sage/sets/real_set.py b/src/sage/sets/real_set.py index 5a23d6d18f5..f819597fcde 100644 --- a/src/sage/sets/real_set.py +++ b/src/sage/sets/real_set.py @@ -2537,11 +2537,9 @@ def convex_hull(*real_set_collection): s = RealSet(real_set) if s.n_components() > 0: lower_s = s[0]._scan_lower() - if lower_s < lower_scan: - lower_scan = lower_s + lower_scan = min(lower_s, lower_scan) upper_s = s[-1]._scan_upper() - if upper_s > upper_scan: - upper_scan = upper_s + upper_scan = max(upper_s, upper_scan) if lower_scan < upper_scan: lower, lower_closed = lower_scan[0][0], lower_scan[0][1] == 0 upper, upper_closed = upper_scan[0][0], upper_scan[0][1] > 0 diff --git a/src/sage/stats/distributions/discrete_gaussian_lattice.py b/src/sage/stats/distributions/discrete_gaussian_lattice.py index 340aa3b93eb..fe1c1b8e5d1 100644 --- a/src/sage/stats/distributions/discrete_gaussian_lattice.py +++ b/src/sage/stats/distributions/discrete_gaussian_lattice.py @@ -308,8 +308,7 @@ def f_or_hat(x): # However, this might still drift from true value for larger lattices # So optimally one should fix the TODO above BOUND = max(1, (self._RR(10**(4 / self.n)).ceil() - 1) // 2) - if BOUND > 10: - BOUND = 10 + BOUND = min(BOUND, 10) coords = itertools.product(range(-BOUND, BOUND + 1), repeat=self.n) return sum(self.f((vector(u) + base) * self.B) for u in coords) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index e62726dedf7..ca851192acb 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -2365,7 +2365,7 @@ cdef class ElementWithCachedMethod(Element): attr = getattr_from_other_class(self, self._parent.category().element_class, name) - self._cached_methods = {name : attr} + self._cached_methods = {name: attr} return attr diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 62abb4a0863..1001cbda600 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1,4 +1,4 @@ -# distutils: sources = sage/symbolic/ginac/add.cpp sage/symbolic/ginac/archive.cpp sage/symbolic/ginac/assume.cpp sage/symbolic/ginac/basic.cpp sage/symbolic/ginac/cmatcher.cpp sage/symbolic/ginac/constant.cpp sage/symbolic/ginac/context.cpp sage/symbolic/ginac/ex.cpp sage/symbolic/ginac/expair.cpp sage/symbolic/ginac/expairseq.cpp sage/symbolic/ginac/exprseq.cpp sage/symbolic/ginac/fderivative.cpp sage/symbolic/ginac/function.cpp sage/symbolic/ginac/function_info.cpp sage/symbolic/ginac/infinity.cpp sage/symbolic/ginac/infoflagbase.cpp sage/symbolic/ginac/inifcns.cpp sage/symbolic/ginac/inifcns_comb.cpp sage/symbolic/ginac/inifcns_gamma.cpp sage/symbolic/ginac/inifcns_hyperb.cpp sage/symbolic/ginac/inifcns_hyperg.cpp sage/symbolic/ginac/inifcns_nstdsums.cpp sage/symbolic/ginac/inifcns_orthopoly.cpp sage/symbolic/ginac/inifcns_trans.cpp sage/symbolic/ginac/inifcns_trig.cpp sage/symbolic/ginac/inifcns_zeta.cpp sage/symbolic/ginac/lst.cpp sage/symbolic/ginac/matrix.cpp sage/symbolic/ginac/mpoly-giac.cpp sage/symbolic/ginac/mpoly-ginac.cpp sage/symbolic/ginac/mpoly-singular.cpp sage/symbolic/ginac/mpoly.cpp sage/symbolic/ginac/mul.cpp sage/symbolic/ginac/normal.cpp sage/symbolic/ginac/numeric.cpp sage/symbolic/ginac/operators.cpp sage/symbolic/ginac/order.cpp sage/symbolic/ginac/power.cpp sage/symbolic/ginac/print.cpp sage/symbolic/ginac/pseries.cpp sage/symbolic/ginac/py_funcs.cpp sage/symbolic/ginac/registrar.cpp sage/symbolic/ginac/relational.cpp sage/symbolic/ginac/remember.cpp sage/symbolic/ginac/sum.cpp sage/symbolic/ginac/symbol.cpp sage/symbolic/ginac/templates.cpp sage/symbolic/ginac/upoly-ginac.cpp sage/symbolic/ginac/useries.cpp sage/symbolic/ginac/utils.cpp sage/symbolic/ginac/wildcard.cpp +# distutils: sources = sage/symbolic/ginac/add.cpp sage/symbolic/ginac/archive.cpp sage/symbolic/ginac/assume.cpp sage/symbolic/ginac/basic.cpp sage/symbolic/ginac/cmatcher.cpp sage/symbolic/ginac/constant.cpp sage/symbolic/ginac/context.cpp sage/symbolic/ginac/ex.cpp sage/symbolic/ginac/expair.cpp sage/symbolic/ginac/expairseq.cpp sage/symbolic/ginac/exprseq.cpp sage/symbolic/ginac/fderivative.cpp sage/symbolic/ginac/function.cpp sage/symbolic/ginac/function_info.cpp sage/symbolic/ginac/infinity.cpp sage/symbolic/ginac/infoflagbase.cpp sage/symbolic/ginac/inifcns.cpp sage/symbolic/ginac/inifcns_comb.cpp sage/symbolic/ginac/inifcns_gamma.cpp sage/symbolic/ginac/inifcns_hyperb.cpp sage/symbolic/ginac/inifcns_hyperg.cpp sage/symbolic/ginac/inifcns_nstdsums.cpp sage/symbolic/ginac/inifcns_orthopoly.cpp sage/symbolic/ginac/inifcns_trans.cpp sage/symbolic/ginac/inifcns_trig.cpp sage/symbolic/ginac/inifcns_zeta.cpp sage/symbolic/ginac/lst.cpp sage/symbolic/ginac/matrix.cpp sage/symbolic/ginac/mpoly-ginac.cpp sage/symbolic/ginac/mpoly-singular.cpp sage/symbolic/ginac/mpoly.cpp sage/symbolic/ginac/mul.cpp sage/symbolic/ginac/normal.cpp sage/symbolic/ginac/numeric.cpp sage/symbolic/ginac/operators.cpp sage/symbolic/ginac/order.cpp sage/symbolic/ginac/power.cpp sage/symbolic/ginac/print.cpp sage/symbolic/ginac/pseries.cpp sage/symbolic/ginac/py_funcs.cpp sage/symbolic/ginac/registrar.cpp sage/symbolic/ginac/relational.cpp sage/symbolic/ginac/remember.cpp sage/symbolic/ginac/sum.cpp sage/symbolic/ginac/symbol.cpp sage/symbolic/ginac/templates.cpp sage/symbolic/ginac/upoly-ginac.cpp sage/symbolic/ginac/useries.cpp sage/symbolic/ginac/utils.cpp sage/symbolic/ginac/wildcard.cpp # distutils: language = c++ # distutils: libraries = flint gmp SINGULAR_LIBRARIES # distutils: extra_compile_args = -std=c++11 SINGULAR_CFLAGS diff --git a/src/sage/symbolic/ginac/basic.h b/src/sage/symbolic/ginac/basic.h index b4d572e5c52..d7adf245b33 100644 --- a/src/sage/symbolic/ginac/basic.h +++ b/src/sage/symbolic/ginac/basic.h @@ -43,19 +43,6 @@ struct _object; typedef _object PyObject; #endif -#ifdef PYNAC_HAVE_LIBGIAC -namespace giac -{ - class gen; - template class tensor; - typedef class tensor polynome; -} -namespace GiNaC -{ -struct ex_is_less; -} -#endif - namespace GiNaC { class ex; @@ -315,9 +302,6 @@ class basic : public refcounted const basic & clearflag(unsigned f) const {flags &= ~f; return *this;} void ensure_if_modifiable() const; -#ifdef PYNAC_HAVE_LIBGIAC - const giac::polynome to_polynome(ex_int_map& map, exvector& revmap); -#endif // member variables tinfo_t tinfo_key; ///< type info diff --git a/src/sage/symbolic/ginac/ex.h b/src/sage/symbolic/ginac/ex.h index 6a164af270f..7b53b283b49 100644 --- a/src/sage/symbolic/ginac/ex.h +++ b/src/sage/symbolic/ginac/ex.h @@ -230,9 +230,6 @@ class ex { ex to_rational(lst & repl_lst) const; ex to_polynomial(exmap & repl) const; ex to_polynomial(lst & repl_lst) const; -#ifdef PYNAC_HAVE_LIBGIAC - const giac::polynome to_polynome(ex_int_map& map, exvector& revmap) const; -#endif const CanonicalForm to_canonical(ex_int_umap& map, power_ocvector_map& pomap, exvector& revmap) const; void collect_powers(power_ocvector_map& pomap) const; diff --git a/src/sage/symbolic/ginac/mpoly-giac.cpp b/src/sage/symbolic/ginac/mpoly-giac.cpp deleted file mode 100644 index e980d542c65..00000000000 --- a/src/sage/symbolic/ginac/mpoly-giac.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/** @file mpoly-giac.cpp - * - * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany - * Copyright (C) 2016 Ralf Stephan - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "pynac-config.h" - -#ifdef PYNAC_HAVE_LIBGIAC - -#include -#include -#include -#undef _POSIX_C_SOURCE -#undef _XOPEN_SOURCE - -#include "upoly.h" -#include "basic.h" -#include "ex.h" -#include "add.h" -#include "constant.h" -#include "expairseq.h" -#include "mul.h" -#include "numeric.h" -#include "power.h" -#include "operators.h" -#include "pseries.h" -#include "relational.h" -#include "symbol.h" -#include "function.h" -#include "utils.h" - -#include -#include - -namespace GiNaC { - -static unsigned int the_dimension = 7; - -static giac::context * context_ptr=nullptr; -static giac::gen giac_zero; -static giac::gen giac_one; - - -inline giac::polynome gen2pol(const giac::gen& g) { - return giac::polynome(giac::monomial(g, the_dimension)); -} - -inline giac::gen num2gen(const numeric& n) { - auto gp = n.to_giacgen(context_ptr); - if (gp != nullptr) - return std::move(*gp); - else { - std::stringstream ss; - ss << n; - return giac::gen(std::string(ss.str()), context_ptr); - } -} - -static giac::polynome replace_with_symbol(const ex& e, ex_int_map& map, exvector& revmap) -{ - // Expression already replaced? Then return the assigned symbol - auto it = map.find(e); - if (it != map.end()) { - const int index = it->second; - giac::monomial mon(giac_one, index, the_dimension); - return giac::polynome(mon); - } - - // Otherwise create new symbol and add to dict - const int index = revmap.size() + 1; - map.insert(std::make_pair(e, index)); - revmap.push_back(e); - giac::monomial mon(giac_one, index, the_dimension); - return giac::polynome(mon); -} - -const giac::polynome basic::to_polynome(ex_int_map& map, exvector& revmap) -{ - std::cerr << *this << std::endl; - throw std::runtime_error("basic::to_polynome: can't happen"); -} - -const giac::polynome num_to_polynome(const numeric& num, - ex_int_map& map, exvector& revmap) -{ - if (num.is_real()) { - if (num.is_integer() or num.is_rational()) - return gen2pol(num2gen(num)); - else - return replace_with_symbol(num, map, revmap); - } else { // complex - numeric re = num.real(); - numeric im = num.imag(); - giac::polynome re_p(the_dimension); - giac::polynome im_p(the_dimension); - if (re.is_integer() or re.is_rational()) - re_p = gen2pol(num2gen(re)); - else - re_p = replace_with_symbol(re, map, revmap); - if (im.is_integer() or im.is_rational()) - im_p = gen2pol(num2gen(im)); - else - im_p = replace_with_symbol(im, map, revmap); - giac::polynome r = re_p + im_p * replace_with_symbol(I, map, revmap); - return r; - } -} - -// Convert to giac polynomial over QQ, filling replacement dicts -// TODO: special case numeric mpz_t, int instead of string interface -const giac::polynome ex::to_polynome(ex_int_map& map, exvector& revmap) const -{ - if (is_exactly_a(*this)) - { - const add& a = ex_to(*this); - giac::polynome p = gen2pol(giac_zero); - for (const auto& termex : a.seq) { - p = p + a.recombine_pair_to_ex(termex).to_polynome(map, revmap); - } - p = p + num_to_polynome(a.overall_coeff, map, revmap); - return p; - } - else if (is_exactly_a(*this)) - { - return num_to_polynome(ex_to(*this), map, revmap); - } - else if (is_exactly_a(*this)) - { - const mul& m = ex_to(*this); - giac::polynome p = gen2pol(giac_one); - for (const auto& termex : m.seq) { - p *= m.recombine_pair_to_ex(termex).to_polynome(map, revmap); - } - p *= num_to_polynome(m.overall_coeff, map, revmap); - return p; - } - else if (is_exactly_a(*this)) - { - const power& pow = ex_to(*this); - if (is_exactly_a(pow.exponent)) { - numeric expo = ex_to(pow.exponent); - if (pow.exponent.info(info_flags::posint)) - return std::move(giac::pow(pow.basis.to_polynome(map, revmap), expo.to_int())); - } - return replace_with_symbol(*this, map, revmap); - } - - return replace_with_symbol(*this, map, revmap); -} - -static ex gen2ex(const giac::gen& gen) -{ - // we need to handle giac types _INT_, _ZINT, and _CPLX - switch (gen.type) { - case giac::_INT_: - return numeric(gen.val); - case giac::_ZINT: - mpz_t bigint; - mpz_init_set(bigint, *(gen.ref_ZINTptr())); - return numeric(bigint); - case giac::_CPLX: - return (gen2ex(gen.ref_CPLXptr()[0]) - + I * gen2ex(gen.ref_CPLXptr()[1])); - case giac::_FRAC: - return (gen2ex(gen.ref_FRACptr()->num) - / gen2ex(gen.ref_FRACptr()->den)); - default: - std::ostringstream os; - os << "gen2ex: can't happen: " << int(gen.type) << std::flush; - throw std::runtime_error(os.str()); - } -} - -static ex polynome_to_ex(const giac::polynome& p, const exvector& revmap) -{ - ex e = _ex0; - for (const auto& mon : p.coord) { - ex prod = _ex1; - for (unsigned int varno=0; varno(a) && is_exactly_a(b)) { - numeric g = gcd(ex_to(a), ex_to(b)); - if ((ca != nullptr) || (cb != nullptr)) { - if (g.is_zero()) { - if (ca != nullptr) - *ca = _ex0; - if (cb != nullptr) - *cb = _ex0; - } else { - if (ca != nullptr) - *ca = ex_to(a) / g; - if (cb != nullptr) - *cb = ex_to(b) / g; - } - } - return g; - } - - // Partially factored cases (to avoid expanding large expressions) - if (is_exactly_a(a)) { - if (is_exactly_a(b) && b.nops() > a.nops()) - goto factored_b; -factored_a: - size_t num = a.nops(); - exvector g; g.reserve(num); - exvector acc_ca; acc_ca.reserve(num); - ex part_b = b; - for (size_t i=0; isetflag(status_flags::dynallocated); - if (cb != nullptr) - *cb = part_b; - return (new mul(g))->setflag(status_flags::dynallocated); - } else if (is_exactly_a(b)) { - if (is_exactly_a(a) && a.nops() > b.nops()) - goto factored_a; -factored_b: - size_t num = b.nops(); - exvector g; g.reserve(num); - exvector acc_cb; acc_cb.reserve(num); - ex part_a = a; - for (size_t i=0; isetflag(status_flags::dynallocated); - return (new mul(g))->setflag(status_flags::dynallocated); - } - - // Input polynomials of the form poly^n are sometimes also trivial - if (is_exactly_a(a)) { - ex p = a.op(0); - const ex& exp_a = a.op(1); - if (is_exactly_a(b)) { - ex pb = b.op(0); - const ex& exp_b = b.op(1); - if (p.is_equal(pb)) { - // a = p^n, b = p^m, gcd = p^min(n, m) - if (exp_a < exp_b) { - if (ca != nullptr) - *ca = _ex1; - if (cb != nullptr) - *cb = power(p, exp_b - exp_a); - return power(p, exp_a); - } else { - if (ca != nullptr) - *ca = power(p, exp_a - exp_b); - if (cb != nullptr) - *cb = _ex1; - return power(p, exp_b); - } - } else { - ex p_co, pb_co; - ex p_gcd = gcdpoly(p, pb, &p_co, &pb_co, check_args); - if (p_gcd.is_one()) { - // a(x) = p(x)^n, b(x) = p_b(x)^m, gcd (p, p_b) = 1 ==> - // gcd(a,b) = 1 - if (ca != nullptr) - *ca = a; - if (cb != nullptr) - *cb = b; - return _ex1; - // XXX: do I need to check for p_gcd = -1? - } else { - // there are common factors: - // a(x) = g(x)^n A(x)^n, b(x) = g(x)^m B(x)^m ==> - // gcd(a, b) = g(x)^n gcd(A(x)^n, g(x)^(n-m) B(x)^m - if (exp_a < exp_b) { - return power(p_gcd, exp_a)* - gcdpoly(power(p_co, exp_a), power(p_gcd, exp_b-exp_a)*power(pb_co, exp_b), ca, cb, false); - } else { - return power(p_gcd, exp_b)* - gcdpoly(power(p_gcd, exp_a - exp_b)*power(p_co, exp_a), power(pb_co, exp_b), ca, cb, false); - } - } // p_gcd.is_equal(_ex1) - } // p.is_equal(pb) - - } else { - if (p.is_equal(b)) { - // a = p^n, b = p, gcd = p - if (ca != nullptr) - *ca = power(p, a.op(1) - 1); - if (cb != nullptr) - *cb = _ex1; - return p; - } - - ex p_co, bpart_co; - ex p_gcd = gcdpoly(p, b, &p_co, &bpart_co, false); - - if (p_gcd.is_one()) { - // a(x) = p(x)^n, gcd(p, b) = 1 ==> gcd(a, b) = 1 - if (ca != nullptr) - *ca = a; - if (cb != nullptr) - *cb = b; - return _ex1; - } else { - // a(x) = g(x)^n A(x)^n, b(x) = g(x) B(x) ==> gcd(a, b) = g(x) gcd(g(x)^(n-1) A(x)^n, B(x)) - return p_gcd*gcdpoly(power(p_gcd, exp_a-1)*power(p_co, exp_a), bpart_co, ca, cb, false); - } - } // is_exactly_a(b) - - } else if (is_exactly_a(b)) { - ex p = b.op(0); - if (p.is_equal(a)) { - // a = p, b = p^n, gcd = p - if (ca != nullptr) - *ca = _ex1; - if (cb != nullptr) - *cb = power(p, b.op(1) - 1); - return p; - } - - ex p_co, apart_co; - const ex& exp_b(b.op(1)); - ex p_gcd = gcdpoly(a, p, &apart_co, &p_co, false); - if (p_gcd.is_one()) { - // b=p(x)^n, gcd(a, p) = 1 ==> gcd(a, b) == 1 - if (ca != nullptr) - *ca = a; - if (cb != nullptr) - *cb = b; - return _ex1; - } else { - // there are common factors: - // a(x) = g(x) A(x), b(x) = g(x)^n B(x)^n ==> gcd = g(x) gcd(g(x)^(n-1) A(x)^n, B(x)) - - return p_gcd*gcdpoly(apart_co, power(p_gcd, exp_b-1)*power(p_co, exp_b), ca, cb, false); - } // p_gcd.is_equal(_ex1) - } - - // Conversion necessary to count needed symbols beforehand - exmap repl; - ex poly_a = a.to_rational(repl); - ex poly_b = b.to_rational(repl); - - symbolset s1 = poly_a.symbols(); - const symbolset& s2 = poly_b.symbols(); - s1.insert(s2.begin(), s2.end()); - the_dimension = s1.size(); - - ex_int_map map; - exvector revmap; - - giac::polynome p = poly_a.to_polynome(map, revmap); - giac::polynome q = poly_b.to_polynome(map, revmap); - giac::polynome d(the_dimension); - giac::gcd(p, q, d); - - if (ca != nullptr) { - giac::polynome quo(the_dimension); - if (giac::exactquotient(p, d, quo)) - *ca = polynome_to_ex(quo, revmap).subs(repl, subs_options::no_pattern); - else - throw(std::runtime_error("can't happen in gcdpoly")); - } - if (cb != nullptr) { - giac::polynome quo(the_dimension); - if (giac::exactquotient(q, d, quo)) - *cb = polynome_to_ex(quo, revmap).subs(repl, subs_options::no_pattern); - else - throw(std::runtime_error("can't happen in gcdpoly")); - } - return polynome_to_ex(d, revmap).subs(repl, subs_options::no_pattern); -} - -#if 0 -ex resultantpoly(const ex & ee1, const ex & ee2, const ex & s) -{ - // Conversion necessary to count needed symbols beforehand - exmap repl; - ex poly_a = ee1.to_rational(repl); - ex poly_b = ee2.to_rational(repl); - - symbolset s1 = poly_a.symbols(); - const symbolset& s2 = poly_b.symbols(); - s1.insert(s2.begin(), s2.end()); - s1.insert(ex_to(s)); - the_dimension = s1.size(); - - ex_int_map map; - exvector revmap; - - giac::polynome p = poly_a.to_polynome(map, revmap); - giac::polynome q = poly_b.to_polynome(map, revmap); - giac::polynome d = giac::resultant(p, q); - return polynome_to_ex(d, revmap).subs(repl, subs_options::no_pattern); -} -#endif - -bool factorpoly(const ex& the_ex, ex& res_prod) -{ - if (is_exactly_a(the_ex) - or is_exactly_a(the_ex) - or is_exactly_a(the_ex) - or is_exactly_a(the_ex)) - return false; - - if (is_exactly_a(the_ex)) { - const mul& m = ex_to(the_ex); - exvector ev; - bool mchanged = false; - for (size_t i=0; i(the_ex)) { - const power& pow = ex_to(the_ex); - ex prod; - bool res = factorpoly(pow.op(0), prod); - if (not res) - return false; - res_prod = power(prod, pow.op(1)); - return true; - } - - if (not is_exactly_a(the_ex)) - throw(std::runtime_error("can't happen in factor")); - - if (context_ptr == nullptr) { - context_ptr=new giac::context(); - giac_zero = giac::gen(std::string("0"), context_ptr); - giac_one = giac::gen(std::string("1"), context_ptr); - } - - exmap repl; - ex poly = the_ex.to_rational(repl); - symbolset s1 = poly.symbols(); - the_dimension = s1.size(); - - ex_int_map map; - exvector revmap; - giac::polynome p = the_ex.to_polynome(map, revmap); - giac::polynome p_content(the_dimension); - giac::factorization f; - bool res = factor(p, p_content, f, - false, false, false, giac_one, giac_one); - if (not res) - return false; - res_prod = polynome_to_ex(p_content, revmap).subs(repl, subs_options::no_pattern); - for (auto fpair : f) - res_prod = mul(res_prod, - power(polynome_to_ex(fpair.fact, revmap).subs(repl, subs_options::no_pattern), - fpair.mult)); - return true; -} - -ex poly_mul_expand(const ex& a, const ex& b) -{ - exmap repl; - ex poly_a = a.to_rational(repl); - ex poly_b = b.to_rational(repl); - - symbolset s1 = poly_a.symbols(); - const symbolset& s2 = poly_b.symbols(); - s1.insert(s2.begin(), s2.end()); - the_dimension = s1.size(); - - ex_int_map map; - exvector revmap; - - giac::polynome p = poly_a.to_polynome(map, revmap); - giac::polynome q = poly_b.to_polynome(map, revmap); - giac::polynome d(the_dimension); - d = p * q; - - return polynome_to_ex(d, revmap).subs(repl, subs_options::no_pattern); -} - -} // namespace GiNaC - -#endif // HAVE_LIBGIAC diff --git a/src/sage/symbolic/ginac/mpoly-ginac.cpp b/src/sage/symbolic/ginac/mpoly-ginac.cpp index 608e0f6f207..02a07504a73 100644 --- a/src/sage/symbolic/ginac/mpoly-ginac.cpp +++ b/src/sage/symbolic/ginac/mpoly-ginac.cpp @@ -51,8 +51,6 @@ namespace GiNaC { -#ifndef PYNAC_HAVE_LIBGIAC - // If comparing expressions (ex::compare()) is fast, you can set this to 1. // Some routines like quo(), rem() and gcd() will then return a quick answer // when they are called with two identical arguments. @@ -547,7 +545,5 @@ ex sqrfree(const ex &a, const lst &l) #endif -#endif // HAVE_LIBGIAC - } // namespace GiNaC diff --git a/src/sage/symbolic/ginac/mpoly-singular.cpp b/src/sage/symbolic/ginac/mpoly-singular.cpp index 3050a96bac6..e66694ec1e0 100644 --- a/src/sage/symbolic/ginac/mpoly-singular.cpp +++ b/src/sage/symbolic/ginac/mpoly-singular.cpp @@ -344,8 +344,6 @@ static ex canonical_to_ex(const CanonicalForm& f, const exvector& revmap) } // GCD of two exes which are in polynomial form -// If giac is requested we stand back -#ifndef PYNAC_HAVE_LIBGIAC ex gcdpoly(const ex &a, const ex &b, ex *ca=nullptr, ex *cb=nullptr, bool check_args=true) { if (a.is_zero()) @@ -648,8 +646,6 @@ ex poly_mul_expand(const ex& a, const ex& b) return res; } -#endif //PYNAC_HAVE_LIBGIAC - ex resultantpoly(const ex & ee1, const ex & ee2, const ex & s) { ex_int_umap map; diff --git a/src/sage/symbolic/ginac/normal.cpp b/src/sage/symbolic/ginac/normal.cpp index d2c9e7be637..303f12d1aa7 100644 --- a/src/sage/symbolic/ginac/normal.cpp +++ b/src/sage/symbolic/ginac/normal.cpp @@ -1093,13 +1093,6 @@ static ex find_common_factor(const ex & e, ex & factor, exmap & repl) if (gc.is_one()) return e; -#ifdef PYNAC_HAVE_LIBGIAC - else { - ex f = 1; - gc = find_common_factor(gc, f, repl); - gc *= f; - } -#endif // The GCD is the factor we pull out factor *= gc; diff --git a/src/sage/symbolic/ginac/numeric.cpp b/src/sage/symbolic/ginac/numeric.cpp index 4bcf45e8793..a9bbfba9e15 100644 --- a/src/sage/symbolic/ginac/numeric.cpp +++ b/src/sage/symbolic/ginac/numeric.cpp @@ -74,15 +74,6 @@ #include "factory/factory.h" #pragma clang diagnostic pop -#ifdef PYNAC_HAVE_LIBGIAC -#undef _POSIX_C_SOURCE -#undef _XOPEN_SOURCE - -#include -#include -#include -#endif - //#define Logging_refctr #if defined(Logging_refctr) #undef Py_INCREF @@ -3258,33 +3249,6 @@ void numeric::canonicalize() } } -#ifdef PYNAC_HAVE_LIBGIAC -giac::gen* numeric::to_giacgen(giac::context* cptr) const -{ - if (t == LONG) - return new giac::gen(v._long); - if (t == MPZ) { - mpz_t bigint; - mpz_init_set(bigint, v._bigint); - auto ret = new giac::gen(bigint); - mpz_clear(bigint); - return ret; - } - if (t == MPQ) { - mpz_t bigint; - mpz_init_set(bigint, mpq_numref(v._bigrat)); - giac::gen gn(bigint); - mpz_set(bigint, mpq_denref(v._bigrat)); - giac::gen gd(bigint); - giac::Tfraction frac(gn, gd); - mpz_clear(bigint); - return new giac::gen(frac); - } - else - return nullptr; -} -#endif - CanonicalForm numeric::to_canonical() const { if (t == LONG) diff --git a/src/sage/symbolic/ginac/numeric.h b/src/sage/symbolic/ginac/numeric.h index 50b2b3d5e31..03697b2a474 100644 --- a/src/sage/symbolic/ginac/numeric.h +++ b/src/sage/symbolic/ginac/numeric.h @@ -64,12 +64,6 @@ PyObject* CC_get(); class CanonicalForm; -#ifdef PYNAC_HAVE_LIBGIAC -namespace giac { - class context; -} -#endif - namespace GiNaC { enum Type { @@ -246,9 +240,6 @@ class numeric : public basic { const numeric try_py_method(const std::string& s, const numeric& x2) const; const numeric to_dict_parent(PyObject* dict) const; -#ifdef PYNAC_HAVE_LIBGIAC - giac::gen* to_giacgen(giac::context*) const; -#endif CanonicalForm to_canonical() const; const numeric real() const; diff --git a/src/sage/symbolic/ginac/pynac-config.h b/src/sage/symbolic/ginac/pynac-config.h index 4d686828c7f..00d7445049a 100644 --- a/src/sage/symbolic/ginac/pynac-config.h +++ b/src/sage/symbolic/ginac/pynac-config.h @@ -7,8 +7,5 @@ /* Current GiNaC archive file version number */ #define PYNAC_ARCHIVE_VERSION 3 -/* Define if you have libgiac */ -/* #undef PYNAC_HAVE_LIBGIAC */ - /* once: _PYNAC_CONFIG_H */ #endif diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index cba2493de95..3291fe3cea0 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -258,8 +258,7 @@ def random_expr_helper(n_nodes, internal, leaves, verbose): n_nodes -= 1 n_children = r[2] n_spare_nodes = n_nodes - n_children - if n_spare_nodes <= 0: - n_spare_nodes = 0 + n_spare_nodes = max(0, n_spare_nodes) nodes_per_child = random_integer_vector(n_spare_nodes, n_children) children = [random_expr_helper(n + 1, internal, leaves, verbose) for n in nodes_per_child] diff --git a/src/sage/tensor/modules/free_module_alt_form.py b/src/sage/tensor/modules/free_module_alt_form.py index 3ba9ec0a4a0..b9d9f98ef63 100644 --- a/src/sage/tensor/modules/free_module_alt_form.py +++ b/src/sage/tensor/modules/free_module_alt_form.py @@ -805,7 +805,7 @@ def interior_product(self, alt_tensor): """ from .format_utilities import is_atomic from .alternating_contr_tensor import AlternatingContrTensor - if not isinstance(alt_tensor, AlternatingContrTensor): + if not isinstance(alt_tensor, AlternatingContrTensor): raise TypeError("{} is not an alternating ".format(alt_tensor) + "contravariant tensor") p_res = alt_tensor._tensor_rank - self._tensor_rank # degree of result diff --git a/src/sage/topology/filtered_simplicial_complex.py b/src/sage/topology/filtered_simplicial_complex.py index 1354e7a8fb6..e468b80c662 100644 --- a/src/sage/topology/filtered_simplicial_complex.py +++ b/src/sage/topology/filtered_simplicial_complex.py @@ -620,8 +620,7 @@ def _max_index(self, d): currmax = -1 for s, x_s in d: j = self._index_of_simplex[s] - if j > currmax: - currmax = j + currmax = max(j, currmax) return currmax def persistence_intervals(self, dimension, field=2, strict=True, verbose=None): diff --git a/src/sage/typeset/ascii_art.py b/src/sage/typeset/ascii_art.py index e470e2bd88d..cf64d92a0b9 100644 --- a/src/sage/typeset/ascii_art.py +++ b/src/sage/typeset/ascii_art.py @@ -44,11 +44,11 @@ sage: shell.run_cell('%display ascii_art') sage: shell.run_cell("i = var('i')") # needs sage.symbolic sage: shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)') # needs sage.symbolic - 10 9 8 7 6 5 4 3 > - 3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x > + 10 9 8 7 6 5 4 3... + 3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x... - > 2 - > + 2*x + x + 1 + ...2 + ...+ 2*x + x + 1 sage: shell.run_cell('3/(7*x)') # needs sage.symbolic 3 diff --git a/src/sage/typeset/character_art_factory.py b/src/sage/typeset/character_art_factory.py index eb268f3228a..d9b13a1cb05 100644 --- a/src/sage/typeset/character_art_factory.py +++ b/src/sage/typeset/character_art_factory.py @@ -469,11 +469,9 @@ def concatenate(self, iterable, separator, empty=None, baseline=0, top = separator._h - bot for obj in iterable: bot1 = obj.get_baseline() - if bot1 > bot: - bot = bot1 + bot = max(bot1, bot) top1 = obj._h - bot1 - if top1 > top: - top = top1 + top = max(top1, top) # bot + top is the new height def padded_line(obj, i): diff --git a/src/sage/version.py b/src/sage/version.py index a8d3c7fd130..41343e5ca1a 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.beta4' -date = '2024-09-15' -banner = 'SageMath version 10.5.beta4, Release Date: 2024-09-15' +version = '10.5.beta5' +date = '2024-09-22' +banner = 'SageMath version 10.5.beta5, Release Date: 2024-09-22' diff --git a/src/tox.ini b/src/tox.ini index 970b2330aec..094c1f54806 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -315,7 +315,7 @@ passenv = RUFF_OUTPUT_FORMAT # 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable # 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values # -commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1730,PLR1736,F403,PLR0402,PLW0603,F841,E713,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,E713,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} [flake8] rst-roles =