diff --git a/.devcontainer/portability-centos-stream-8-python3.9-minimal/devcontainer.json b/.devcontainer/portability-centos-stream-8-python3.9-minimal/devcontainer.json
deleted file mode 100644
index 5fa562346cb..00000000000
--- a/.devcontainer/portability-centos-stream-8-python3.9-minimal/devcontainer.json
+++ /dev/null
@@ -1,25 +0,0 @@
-// The command "tox -e update_docker_platforms"
-// creates .devcontainer/portability-*-*/devcontainer.json
-// from .devcontainer/portability-devcontainer.json.in
-// See https://aka.ms/devcontainer.json for format details.
-{
- "name": "centos-stream-8-python3.9-minimal (≥ 8-core)",
- "build": {
- "dockerfile": "portability-Dockerfile",
- // See tox.ini for definitions
- "args": {
- "SYSTEM_FACTOR": "centos-stream-8-python3.9",
- "PACKAGE_FACTOR": "minimal",
- "DOCKER_TARGET": "with-targets",
- "DOCKER_TAG": "dev"
- }
- },
- "containerEnv": {
- "MAKE": "make -j4"
- },
- "onCreateCommand": ".devcontainer/onCreate.sh",
- "updateContentCommand": ".devcontainer/portability-updateContent.sh",
- "extensions": [
- "ms-python.python"
- ]
-}
diff --git a/.devcontainer/portability-centos-stream-8-python3.9-minimal/portability-Dockerfile b/.devcontainer/portability-centos-stream-8-python3.9-minimal/portability-Dockerfile
deleted file mode 120000
index 692e2a79d64..00000000000
--- a/.devcontainer/portability-centos-stream-8-python3.9-minimal/portability-Dockerfile
+++ /dev/null
@@ -1 +0,0 @@
-../portability-Dockerfile
\ No newline at end of file
diff --git a/.devcontainer/portability-centos-stream-8-python3.9-standard/devcontainer.json b/.devcontainer/portability-centos-stream-8-python3.9-standard/devcontainer.json
deleted file mode 100644
index 0c76ce86244..00000000000
--- a/.devcontainer/portability-centos-stream-8-python3.9-standard/devcontainer.json
+++ /dev/null
@@ -1,25 +0,0 @@
-// The command "tox -e update_docker_platforms"
-// creates .devcontainer/portability-*-*/devcontainer.json
-// from .devcontainer/portability-devcontainer.json.in
-// See https://aka.ms/devcontainer.json for format details.
-{
- "name": "centos-stream-8-python3.9-standard (≥ 8-core)",
- "build": {
- "dockerfile": "portability-Dockerfile",
- // See tox.ini for definitions
- "args": {
- "SYSTEM_FACTOR": "centos-stream-8-python3.9",
- "PACKAGE_FACTOR": "standard",
- "DOCKER_TARGET": "with-targets",
- "DOCKER_TAG": "dev"
- }
- },
- "containerEnv": {
- "MAKE": "make -j4"
- },
- "onCreateCommand": ".devcontainer/onCreate.sh",
- "updateContentCommand": ".devcontainer/portability-updateContent.sh",
- "extensions": [
- "ms-python.python"
- ]
-}
diff --git a/.devcontainer/portability-centos-stream-8-python3.9-standard/portability-Dockerfile b/.devcontainer/portability-centos-stream-8-python3.9-standard/portability-Dockerfile
deleted file mode 120000
index 692e2a79d64..00000000000
--- a/.devcontainer/portability-centos-stream-8-python3.9-standard/portability-Dockerfile
+++ /dev/null
@@ -1 +0,0 @@
-../portability-Dockerfile
\ No newline at end of file
diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml
index 6860bd6e460..0ce9a1f142b 100644
--- a/.github/workflows/ci-linux.yml
+++ b/.github/workflows/ci-linux.yml
@@ -118,7 +118,6 @@ jobs:
"linuxmint-21.2",
"fedora-38",
"fedora-39",
- "centos-stream-8-python3.9",
"centos-stream-9-python3.9",
"almalinux-8-python3.9",
"gentoo-python3.10",
diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
index 9dfb8d7d221..01d05b25b5d 100644
--- a/.github/workflows/doc-build.yml
+++ b/.github/workflows/doc-build.yml
@@ -130,10 +130,10 @@ jobs:
new_version=$(docker exec BUILD cat src/VERSION.txt)
mkdir -p docs/
docker cp BUILD:/sage/local/share/doc/sage/html docs/
- # Wipe out chronic diffs between old doc and new doc
+ # Wipe out chronic diffs of old doc against new doc
(cd docs && \
find . -name "*.html" | xargs sed -i -e '/class="sidebar-brand-text"/ s/Sage [0-9a-z.]* /Sage '"$new_version"' /' \
- -e '/This is documentation for/ s/ built with GitHub PR [^.]*././' \
+ -e '/;,\;; d')
# Create git repo from old doc
@@ -166,7 +166,13 @@ jobs:
docker cp BUILD:/sage/local/share/doc/sage/html docs
docker cp BUILD:/sage/local/share/doc/sage/index.html docs
(cd docs && git commit -a -m 'new')
+ # Wipe out chronic diffs of new doc against old doc
+ (cd docs && \
+ find . -name "*.html" | xargs sed -i -e '/This is documentation for/ s/ built with GitHub PR .*. Doc/. Doc/' \
+ -e '/>>'"'"', `<<<'"')dnl" >> $a
done
+ eval $(sage-package properties --format=shell :all:)
spkg_configures=""
# initialize SAGE_ENABLE... options for standard packages
for pkgname in $(sage-package list :standard:); do
@@ -62,28 +61,36 @@ AS_VAR_SET_IF([SAGE_ENABLE_$pkgname], [], [AS_VAR_SET([SAGE_ENABLE_$pkgname], [y
done
# --enable-SPKG options
for pkgname in $(sage-package list :optional: :experimental:); do
+ eval DIR=\$path_$pkgname pkgtype=\$type_$pkgname pkgsource=\$source_$pkgname
+ case "$pkgname:$pkgsource" in
+ *:pip)
# Issue #29629: Temporary solution for Sage 9.1: Do not provide
# --enable-SPKG options for installing pip packages
- if [ ! -f build/pkgs/$pkgname/requirements.txt ]; then
- pkgtype="$(cat build/pkgs/$pkgname/type)"
- # Issue #29124: Do not provide --enable-_recommended and similar
- case "$pkgname" in
- _*) ;;
- *) spkg_configures="$spkg_configures
+ ;;
+ _*:*)
+ # Issue #29124: Do not provide --enable-_recommended and similar
+ ;;
+ *:none)
+ # Issue #31163: Just an optional dummy package
+ spkg_configures="$spkg_configures
AC_SUBST(SAGE_ENABLE_$pkgname, [if_installed])"
- if [ -f build/pkgs/$pkgname/spkg-install -o -f build/pkgs/$pkgname/spkg-install.in ]; then
- # Issue #31163: Not just an optional dummy package
- spkg_configures="$spkg_configures
-SAGE_SPKG_ENABLE([$pkgname], [$pkgtype], [$(grep -v ^= build/pkgs/$pkgname/SPKG.rst | head -n1 2>/dev/null || echo $pkgname)])"
- fi
- ;;
- esac
- fi
+ ;;
+ *:*)
+ spkg_configures="$spkg_configures
+AC_SUBST(SAGE_ENABLE_$pkgname, [if_installed])"
+ spkg_configures="$spkg_configures
+SAGE_SPKG_ENABLE([$pkgname], [$pkgtype], [$(grep -v ^= "$DIR/SPKG.rst" | head -n1 2>/dev/null || echo $pkgname)])"
+ ;;
+ esac
done
+ cat >> m4/sage_spkg_configures.m4 <> m4/sage_spkg_configures.m4
- cat >> m4/sage_spkg_configures.m4 <>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(sage-get-system-packages install-requires ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions.m4
- echo "define(>>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(sage-get-system-packages install-requires-toml ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions_toml.m4
- fi
+ eval DIR=\$path_$pkgname pkgtype=\$type_$pkgname SPKG_SOURCE=\$source_$pkgname SPKG_TREE_VAR=\$trees_$pkgname
+ if test -f "$DIR/requirements.txt" -o -f "$DIR/version_requirements.txt"; then
+ # A Python package
+ echo "define(>>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(sage-get-system-packages install-requires ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions.m4
+ INSTALL_REQUIRES_TOML=
+ echo "define(>>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(sage-get-system-packages install-requires-toml ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions_toml.m4
+ echo "m4_define([SPKG_INSTALL_REQUIRES_${pkgname}], [[$(echo $(sage-get-system-packages install-requires-toml ${pkgname} | sed 's/"/\\"/g'))]])dnl" >> m4/sage_spkg_configures.m4
fi
spkg_finalizes="$spkg_finalizes
SAGE_SPKG_FINALIZE([$pkgname], [$pkgtype], [$SPKG_SOURCE], [$SPKG_TREE_VAR])"
done
- echo "$spkg_finalizes" >> m4/sage_spkg_configures.m4
for a in m4/sage_spkg_versions.m4 m4/sage_spkg_versions_toml.m4; do
echo 'changequote(>>>`<<<, >>>'"'"'<<<)dnl' >> $a
done
+ cat >> m4/sage_spkg_configures.m4 <&2 "bootstrap:$LINENO: Nothing to do for $pkgname"; fi) || exit 1
+ eval DIR=\$path_$pkgname
+ (cd "$DIR" && if [ -x bootstrap ]; then ./bootstrap; else echo >&2 "bootstrap:$LINENO: Nothing to do for $pkgname"; fi) || exit 1
done
if [ $# != 0 ]; then
@@ -196,10 +187,10 @@ SAGE_SPKG_FINALIZE([$pkgname], [$pkgtype], [$SPKG_SOURCE], [$SPKG_TREE_VAR])"
bootstrap_download () {
SAGE_DL_LOGLEVEL=""
[ "${BOOTSTRAP_QUIET}" = "yes" ] && SAGE_DL_LOGLEVEL="--log=WARNING"
- sage-download-file ${SAGE_DL_LOGLEVEL} configure-$CONFVERSION.tar.gz
+ CONFBALL=$(sage-package download $SAGE_DL_LOGLEVEL configure)
if [ $? -ne 0 ]; then
- echo >&2 "Error: downloading configure-$CONFVERSION.tar.gz failed"
+ echo >&2 "Error: downloading configure tarball failed"
exit 1
fi
@@ -255,16 +246,8 @@ save () {
build/pkgs/setuptools/version_requirements.txt \
build/pkgs/wheel/version_requirements.txt
- # Update version
- echo "$NEWCONFVERSION" >$PKG/package-version.txt
-
- # Compute checksum
- if [ "${BOOTSTRAP_QUIET}" = "no" ]; then
- sage-package fix-checksum configure
- else
- # Hide the "Updating checksum..." message
- sage-package fix-checksum configure > /dev/null
- fi
+ # Update version; this re-computes the checksum
+ sage-package update configure "$NEWCONFVERSION"
}
@@ -304,7 +287,6 @@ do
done
shift $(($OPTIND - 1))
export BOOTSTRAP_QUIET
-CONFBALL="upstream/configure-$CONFVERSION.tar.gz"
if [ $DOWNLOAD$SAVE = yesyes ]; then
echo >&2 "$0: refusing to download and save."
@@ -331,15 +313,16 @@ mkdir -p config 2>/dev/null
if [ $ALWAYSDOWNLOAD = yes ]; then
if [ -n "$CONFTARBALL_URL" ]; then
- URL="$CONFTARBALL_URL"/configure-$CONFVERSION.tar.gz
+ CONFTARBALL=$(sage-package tarball configure)
+ URL="$CONFTARBALL_URL"/"$CONFTARBALL"
SAGE_DL_LOGLEVEL=""
[ "${BOOTSTRAP_QUIET}" = "yes" ] && SAGE_DL_LOGLEVEL="--log=WARNING"
- sage-download-file ${SAGE_DL_LOGLEVEL} "$URL" upstream/configure-$CONFVERSION.tar.gz
+ sage-download-file ${SAGE_DL_LOGLEVEL} "$URL" upstream/"$CONFTARBALL"
if [ $? -ne 0 ]; then
- echo >&2 "Error: downloading configure-$CONFVERSION.tar.gz from $CONFTARBALL_URL failed"
+ echo >&2 "Error: downloading $CONFTARBALL from $CONFTARBALL_URL failed"
exit 1
fi
- echo >&2 "Downloaded configure-$CONFVERSION.tar.gz from $CONFTARBALL_URL "
+ echo >&2 "Downloaded $CONFTARBALL from $CONFTARBALL_URL "
else
bootstrap_download || exit $?
fi
diff --git a/bootstrap-conda b/bootstrap-conda
index 62d7557a9b5..c64e2a72b6c 100755
--- a/bootstrap-conda
+++ b/bootstrap-conda
@@ -18,10 +18,11 @@ SAGELIB_PACKAGES=
SAGELIB_OPTIONAL_PACKAGES=
DEVELOP_PACKAGES=
+eval $(sage-package properties --format=shell :all:)
+
for PKG_BASE in $(sage-package list --has-file distros/conda.txt --exclude _sagemath); do
- PKG_SCRIPTS=build/pkgs/$PKG_BASE
+ eval PKG_SCRIPTS=\$path_$PKG_BASE PKG_TYPE=\$type_$PKG_BASE
SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/conda.txt
- PKG_TYPE=$(cat $PKG_SCRIPTS/type)
PKG_SYSTEM_PACKAGES=$(echo $(${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE))
if [ -n "$PKG_SYSTEM_PACKAGES" ]; then
if [ -f $PKG_SCRIPTS/spkg-configure.m4 ]; then
@@ -133,12 +134,11 @@ echo >&2 $0:$LINENO: generate conda environment files
echo >&4 " - pip:"
echo >&5 " - pip:"
for PKG_BASE in $(sage-package list :standard: :optional: --has-file requirements.txt --no-file distros/conda.txt --no-file src; sage-package list :standard: :optional: --has-file version_requirements.txt --no-file requirements.txt --no-file distros/conda.txt --no-file src); do
- PKG_SCRIPTS=build/pkgs/$PKG_BASE
+ eval PKG_SCRIPTS=\$path_$PKG_BASE PKG_TYPE=\$type_$PKG_BASE
SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt
if [ ! -f $SYSTEM_PACKAGES_FILE ]; then
SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/version_requirements.txt
fi
- PKG_TYPE=$(cat $PKG_SCRIPTS/type)
if grep -q SAGERUNTIME $PKG_SCRIPTS/dependencies $PKG_SCRIPTS/dependencies_order_only 2>/dev/null; then
: # cannot install packages that depend on the Sage library
else
diff --git a/build/bin/sage-get-system-packages b/build/bin/sage-get-system-packages
index 0a90232ed6e..f28e0356375 100755
--- a/build/bin/sage-get-system-packages
+++ b/build/bin/sage-get-system-packages
@@ -15,26 +15,40 @@ fi
case "$SYSTEM" in
install-requires)
# Collect from src/pyproject.toml or from version_requirements.txt (falling back to requirements.txt) and output it in the format
- # needed by setup.cfg [options] version_requirements=
- SYSTEM_PACKAGES_FILE_NAMES="version_requirements.txt requirements.txt"
- STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;"
- FROM_PYPROJECT_TOML=1
+ # needed by setup.cfg [options] install_requires=
+ SYSTEM_PACKAGES_FILE_NAMES="src/pyproject.toml version_requirements.txt requirements.txt"
+ # also normalizes quotes from "" to ''.
+ STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;s/\"/'/g;"
COLLECT=
;;
install-requires-toml)
# Collect from src/pyproject.toml or from version_requirements.txt (falling back to requirements.txt) and output it in the format
# needed by pyproject.toml [build-system] requires=
- SYSTEM_PACKAGES_FILE_NAMES="version_requirements.txt requirements.txt"
- STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;s/^/'/;s/$/',/;"
- FROM_PYPROJECT_TOML=1
+ SYSTEM_PACKAGES_FILE_NAMES="src/pyproject.toml version_requirements.txt requirements.txt"
+ # also normalizes quotes from '' to "".
+ STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;s/'/\"/g;s/^/'/;s/$/',/;"
COLLECT=
;;
pip)
- SYSTEM_PACKAGES_FILE_NAMES="requirements.txt version_requirements.txt"
+ SYSTEM_PACKAGES_FILE_NAMES="requirements.txt src/pyproject.toml version_requirements.txt"
STRIP_COMMENTS='sed s/#.*//;s/[[:space:]]//g;'
- FROM_PYPROJECT_TOML=1
COLLECT=echo
;;
+ versions)
+ # For use in sage-spkg-info
+ SYSTEM_PACKAGES_FILE_NAMES="package-version.txt requirements.txt src/pyproject.toml version_requirements.txt"
+ strip_comments () {
+ TEXT=$(sed "s/#.*//;/^[[:space:]]*$/d;s/\"/'/g;s/^/ /;" "$@")
+ if [ -n "$(echo $TEXT)" ]; then
+ echo "$NAME::"
+ echo
+ echo "$TEXT"
+ echo
+ fi
+ }
+ STRIP_COMMENTS=strip_comments
+ COLLECT=
+ ;;
*)
if [ "$SYSTEM" = auto ]; then
SYSTEM=$(sage-guess-package-system 2>/dev/null)
@@ -45,7 +59,6 @@ case "$SYSTEM" in
fi
SYSTEM_PACKAGES_FILE_NAMES="distros/$SYSTEM.txt"
STRIP_COMMENTS="sed s/#.*//;s/\${PYTHON_MINOR}/${PYTHON_MINOR}/g"
- FROM_PYPROJECT_TOML=0
COLLECT=echo
;;
esac
@@ -57,19 +70,10 @@ case "$SPKGS" in
esac
for PKG_BASE in $SPKGS; do
- if [ $FROM_PYPROJECT_TOML -eq 1 ]; then
- if [ -f "$SAGE_ROOT/src/pyproject.toml" ]; then
- # Extract from the "requires" block in src/pyproject.toml
- # Packages are in the format "'sage-conf ~= 10.3b3',"
- PACKAGE_INFO=$(sed -n '/requires *= *\[/,/^\]/s/^ *'\''\('$PKG_BASE'.*\)'\'',/\1/p' "$SAGE_ROOT/src/pyproject.toml")
- if [ -n "$PACKAGE_INFO" ]; then
- echo "$PACKAGE_INFO" | ${STRIP_COMMENTS}
- continue
- fi
- fi
- fi
-
case "$SYSTEM:$ENABLE_SYSTEM_SITE_PACKAGES" in
+ versions*)
+ # Show everything.
+ ;;
install-requires*|pip*)
# This is output for installation of packages into a Python environment.
# So it's OK to use any Python packages.
@@ -93,14 +97,30 @@ for PKG_BASE in $SPKGS; do
esac
for NAME in $SYSTEM_PACKAGES_FILE_NAMES; do
- SYSTEM_PACKAGES_FILE="$SAGE_ROOT"/build/pkgs/$PKG_BASE/$NAME
- if [ -f $SYSTEM_PACKAGES_FILE ]; then
- if [ -z "$COLLECT" ]; then
- ${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE
- else
- $COLLECT $(${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE)
- fi
- break
- fi
+ case $NAME in
+ *pyproject.toml)
+ SYSTEM_PACKAGES_FILE="$SAGE_ROOT"/$NAME
+ if [ -f "$SYSTEM_PACKAGES_FILE" ]; then
+ # Extract from the "requires" block in src/pyproject.toml
+ # Packages are in the format "'sage-conf ~= 10.3b3',"
+ PACKAGE_INFO=$(sed -n '/requires *= *\[/,/^\]/s/^ *'\''\('$PKG_BASE'.*\)'\'',/\1/p' "$SAGE_ROOT/src/pyproject.toml")
+ if [ -n "$PACKAGE_INFO" ]; then
+ echo "$PACKAGE_INFO" | ${STRIP_COMMENTS}
+ [ $SYSTEM = versions ] || break
+ fi
+ fi
+ ;;
+ *)
+ SYSTEM_PACKAGES_FILE="$SAGE_ROOT"/build/pkgs/$PKG_BASE/$NAME
+ if [ -f $SYSTEM_PACKAGES_FILE ]; then
+ if [ -z "$COLLECT" ]; then
+ ${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE
+ else
+ $COLLECT $(${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE)
+ fi
+ [ $SYSTEM = versions ] || break
+ fi
+ ;;
+ esac
done
done
diff --git a/build/bin/sage-spkg-info b/build/bin/sage-spkg-info
index dd289fee4d3..29d833a29bf 100755
--- a/build/bin/sage-spkg-info
+++ b/build/bin/sage-spkg-info
@@ -54,14 +54,7 @@ echo
echo "Version Information"
echo "-------------------"
echo
-for a in package-version.txt requirements.txt version_requirements.txt; do
- if [ -f "$PKG_SCRIPTS"/"$a" ]; then
- echo "$a::"
- echo
- sed 's/^/ /' "$PKG_SCRIPTS/$a"
- echo
- fi
-done
+sage-get-system-packages versions $PKG_BASE
echo
echo "Equivalent System Packages"
echo "--------------------------"
diff --git a/build/pkgs/anyio/checksums.ini b/build/pkgs/anyio/checksums.ini
index edc3a769889..6559f060ac2 100644
--- a/build/pkgs/anyio/checksums.ini
+++ b/build/pkgs/anyio/checksums.ini
@@ -1,4 +1,4 @@
tarball=anyio-VERSION-py3-none-any.whl
-sha1=bb08368bb19e1aff2f4190e39300e43fee52103e
-sha256=cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f
+sha1=f5bd548b3a14c9c93622bf04f7c6464e3f44966a
+sha256=c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7
upstream_url=https://pypi.io/packages/py3/a/anyio/anyio-VERSION-py3-none-any.whl
diff --git a/build/pkgs/anyio/dependencies b/build/pkgs/anyio/dependencies
index 5be99073470..1703c203525 100644
--- a/build/pkgs/anyio/dependencies
+++ b/build/pkgs/anyio/dependencies
@@ -1,4 +1,4 @@
-idna sniffio | $(PYTHON_TOOLCHAIN) $(PYTHON)
+idna sniffio exceptiongroup typing_extensions | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/anyio/package-version.txt b/build/pkgs/anyio/package-version.txt
index fcdb2e109f6..fdc6698807a 100644
--- a/build/pkgs/anyio/package-version.txt
+++ b/build/pkgs/anyio/package-version.txt
@@ -1 +1 @@
-4.0.0
+4.4.0
diff --git a/build/pkgs/appnope/checksums.ini b/build/pkgs/appnope/checksums.ini
index e9ee40864d3..4e49f102dd5 100644
--- a/build/pkgs/appnope/checksums.ini
+++ b/build/pkgs/appnope/checksums.ini
@@ -1,4 +1,4 @@
tarball=appnope-VERSION.tar.gz
-sha1=dd705054af5f6c80d0ce9e1b444428c7b1b07daa
-sha256=02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24
+sha1=4dcd80020b345a184d6da6063a69e25b1d353323
+sha256=1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee
upstream_url=https://pypi.io/packages/source/a/appnope/appnope-VERSION.tar.gz
diff --git a/build/pkgs/appnope/package-version.txt b/build/pkgs/appnope/package-version.txt
index b1e80bb2480..845639eef26 100644
--- a/build/pkgs/appnope/package-version.txt
+++ b/build/pkgs/appnope/package-version.txt
@@ -1 +1 @@
-0.1.3
+0.1.4
diff --git a/build/pkgs/attrs/checksums.ini b/build/pkgs/attrs/checksums.ini
index 01a3de82ed3..7d271509d6d 100644
--- a/build/pkgs/attrs/checksums.ini
+++ b/build/pkgs/attrs/checksums.ini
@@ -1,4 +1,4 @@
tarball=attrs-VERSION-py3-none-any.whl
-sha1=d916b1ecad441ce7f07d86034085475f6c231830
-sha256=1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04
+sha1=563b272af703f8960b76f6637d009fa5fc5864d3
+sha256=99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
upstream_url=https://pypi.io/packages/py3/a/attrs/attrs-VERSION-py3-none-any.whl
diff --git a/build/pkgs/attrs/dependencies b/build/pkgs/attrs/dependencies
index 47296a7bace..b09cbab3e0e 100644
--- a/build/pkgs/attrs/dependencies
+++ b/build/pkgs/attrs/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+importlib_metadata | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/attrs/package-version.txt b/build/pkgs/attrs/package-version.txt
index f8aed3e0b7a..11ebcd0e4f9 100644
--- a/build/pkgs/attrs/package-version.txt
+++ b/build/pkgs/attrs/package-version.txt
@@ -1 +1 @@
-23.1.0
+23.2.0
diff --git a/build/pkgs/cachetools/checksums.ini b/build/pkgs/cachetools/checksums.ini
index 9c2aa8528b0..29f982e9277 100644
--- a/build/pkgs/cachetools/checksums.ini
+++ b/build/pkgs/cachetools/checksums.ini
@@ -1,4 +1,4 @@
tarball=cachetools-VERSION-py3-none-any.whl
-sha1=f7deaa4b10ae6d8955c83b0573e5b80f84e5d87a
-sha256=95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590
+sha1=4210b349f838f75d64da22fbef7e5dc8e494c5f6
+sha256=0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945
upstream_url=https://pypi.io/packages/py3/c/cachetools/cachetools-VERSION-py3-none-any.whl
diff --git a/build/pkgs/cachetools/dependencies b/build/pkgs/cachetools/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/cachetools/dependencies
+++ b/build/pkgs/cachetools/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/cachetools/package-version.txt b/build/pkgs/cachetools/package-version.txt
index c7cb1311a64..74664af7400 100644
--- a/build/pkgs/cachetools/package-version.txt
+++ b/build/pkgs/cachetools/package-version.txt
@@ -1 +1 @@
-5.3.1
+5.3.3
diff --git a/build/pkgs/certifi/checksums.ini b/build/pkgs/certifi/checksums.ini
index 1a07649c990..ecb9291cd62 100644
--- a/build/pkgs/certifi/checksums.ini
+++ b/build/pkgs/certifi/checksums.ini
@@ -1,4 +1,4 @@
tarball=certifi-VERSION-py3-none-any.whl
-sha1=9e99fff8d517d9c5b8d8fe6fe66bc31fa55b0fec
-sha256=e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
+sha1=4acb42f49aed94aeb687b33d3dcb6b564ff36fac
+sha256=dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
upstream_url=https://pypi.io/packages/py3/c/certifi/certifi-VERSION-py3-none-any.whl
diff --git a/build/pkgs/certifi/dependencies b/build/pkgs/certifi/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/certifi/dependencies
+++ b/build/pkgs/certifi/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/certifi/package-version.txt b/build/pkgs/certifi/package-version.txt
index 7b4ca80e8a8..fa996f67f93 100644
--- a/build/pkgs/certifi/package-version.txt
+++ b/build/pkgs/certifi/package-version.txt
@@ -1 +1 @@
-2023.11.17
+2024.2.2
diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini
index da9cfbb1ff9..4a0731816fb 100644
--- a/build/pkgs/configure/checksums.ini
+++ b/build/pkgs/configure/checksums.ini
@@ -1,3 +1,3 @@
tarball=configure-VERSION.tar.gz
-sha1=f3e560bbf33add8504ba9f7ba93fff9e82e3e445
-sha256=bef93be1bb978fa34cd5aaa9c041d1a97a33ff35f88c9df2f9c25e6764770c56
+sha1=44fc3d7b5ad99c9b59153bf24d2a982eb690d5c2
+sha256=4e9e0fada9495365f673f83de311d7dbbc1fbcf9e5f7163209cf396c4ccd5479
diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt
index ca5926f5634..1a9044b121d 100644
--- a/build/pkgs/configure/package-version.txt
+++ b/build/pkgs/configure/package-version.txt
@@ -1 +1 @@
-5c12765f7e585b58ab0cd99f7998cfa615f85247
+b7e60e161981964b92657e427662fa6e69938428
diff --git a/build/pkgs/debugpy/SPKG.rst b/build/pkgs/debugpy/SPKG.rst
index f99081496dd..b4df549df07 100644
--- a/build/pkgs/debugpy/SPKG.rst
+++ b/build/pkgs/debugpy/SPKG.rst
@@ -1,10 +1,10 @@
-debugpy: An implementation of the Debug Adapter Protocol for Python
-===================================================================
+debugpy: Implementation of the Debug Adapter Protocol for Python
+================================================================
Description
-----------
-An implementation of the Debug Adapter Protocol for Python
+Implementation of the Debug Adapter Protocol for Python
License
-------
diff --git a/build/pkgs/debugpy/checksums.ini b/build/pkgs/debugpy/checksums.ini
index 9ffea011e6e..1879bd6e197 100644
--- a/build/pkgs/debugpy/checksums.ini
+++ b/build/pkgs/debugpy/checksums.ini
@@ -1,4 +1,4 @@
-tarball=debugpy-VERSION.zip
-sha1=af611dc5c401424196c27363379fc483814efe26
-sha256=12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0
-upstream_url=https://pypi.io/packages/source/d/debugpy/debugpy-VERSION.zip
+tarball=debugpy-VERSION-py2.py3-none-any.whl
+sha1=cc85be805ef4f25e85bae65cf5b04badca032bb6
+sha256=28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242
+upstream_url=https://pypi.io/packages/py2.py3/d/debugpy/debugpy-VERSION-py2.py3-none-any.whl
diff --git a/build/pkgs/debugpy/dependencies b/build/pkgs/debugpy/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/debugpy/dependencies
+++ b/build/pkgs/debugpy/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/debugpy/package-version.txt b/build/pkgs/debugpy/package-version.txt
index 27f9cd322bb..a8fdfda1c78 100644
--- a/build/pkgs/debugpy/package-version.txt
+++ b/build/pkgs/debugpy/package-version.txt
@@ -1 +1 @@
-1.8.0
+1.8.1
diff --git a/build/pkgs/debugpy/spkg-install.in b/build/pkgs/debugpy/spkg-install.in
deleted file mode 100644
index 37ac1a53437..00000000000
--- a/build/pkgs/debugpy/spkg-install.in
+++ /dev/null
@@ -1,2 +0,0 @@
-cd src
-sdh_pip_install .
diff --git a/build/pkgs/e_antic/checksums.ini b/build/pkgs/e_antic/checksums.ini
index f0afbce6ac8..2df790ac90f 100644
--- a/build/pkgs/e_antic/checksums.ini
+++ b/build/pkgs/e_antic/checksums.ini
@@ -1,4 +1,4 @@
tarball=e-antic-VERSION.tar.gz
-sha1=587052e189f9a7a145ac3144e6b7f11fca54b1ff
-sha256=a38d2ab62c1b00fa2ee78f39039cc4d9d8e83de5fa5e2a18529ad34ab8976fe1
+sha1=f20808a3f4857ecec58929f811b73c2a7664e666
+sha256=8328e6490129dfec7f4aa478ebd54dc07686bd5e5e7f5f30dcf20c0f11b67f60
upstream_url=https://github.com/flatsurf/e-antic/releases/download/VERSION/e-antic-VERSION.tar.gz
diff --git a/build/pkgs/e_antic/package-version.txt b/build/pkgs/e_antic/package-version.txt
index 227cea21564..e9307ca5751 100644
--- a/build/pkgs/e_antic/package-version.txt
+++ b/build/pkgs/e_antic/package-version.txt
@@ -1 +1 @@
-2.0.0
+2.0.2
diff --git a/build/pkgs/exceptiongroup/checksums.ini b/build/pkgs/exceptiongroup/checksums.ini
index ef04b565062..62cef9ee502 100644
--- a/build/pkgs/exceptiongroup/checksums.ini
+++ b/build/pkgs/exceptiongroup/checksums.ini
@@ -1,4 +1,4 @@
tarball=exceptiongroup-VERSION-py3-none-any.whl
-sha1=e69c438e6d15111c4f7cc18224b31a42a58663da
-sha256=4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14
+sha1=4114f66482c6e55856d9bd6a4780ce716bd550cd
+sha256=5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad
upstream_url=https://pypi.io/packages/py3/e/exceptiongroup/exceptiongroup-VERSION-py3-none-any.whl
diff --git a/build/pkgs/exceptiongroup/dependencies b/build/pkgs/exceptiongroup/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/exceptiongroup/dependencies
+++ b/build/pkgs/exceptiongroup/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/exceptiongroup/package-version.txt b/build/pkgs/exceptiongroup/package-version.txt
index 26aaba0e866..6085e946503 100644
--- a/build/pkgs/exceptiongroup/package-version.txt
+++ b/build/pkgs/exceptiongroup/package-version.txt
@@ -1 +1 @@
-1.2.0
+1.2.1
diff --git a/build/pkgs/filelock/SPKG.rst b/build/pkgs/filelock/SPKG.rst
index d39b439be2e..ebebf9cfbdc 100644
--- a/build/pkgs/filelock/SPKG.rst
+++ b/build/pkgs/filelock/SPKG.rst
@@ -1,10 +1,10 @@
-filelock: A platform independent file lock
-==========================================
+filelock: Platform independent file lock
+========================================
Description
-----------
-A platform independent file lock.
+Platform independent file lock
License
-------
diff --git a/build/pkgs/filelock/checksums.ini b/build/pkgs/filelock/checksums.ini
index 330f4d53a36..e6fc5ecc6f5 100644
--- a/build/pkgs/filelock/checksums.ini
+++ b/build/pkgs/filelock/checksums.ini
@@ -1,4 +1,4 @@
tarball=filelock-VERSION-py3-none-any.whl
-sha1=f1fa92751023660a10b248f8559d09f3c461403f
-sha256=57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c
+sha1=475b56870663924527abcf2f91b7d8dd7a7ab0ee
+sha256=43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f
upstream_url=https://pypi.io/packages/py3/f/filelock/filelock-VERSION-py3-none-any.whl
diff --git a/build/pkgs/filelock/package-version.txt b/build/pkgs/filelock/package-version.txt
index c10780c628a..f982feb41bd 100644
--- a/build/pkgs/filelock/package-version.txt
+++ b/build/pkgs/filelock/package-version.txt
@@ -1 +1 @@
-3.13.1
+3.14.0
diff --git a/build/pkgs/glpk/package-version.txt b/build/pkgs/glpk/package-version.txt
index 496a5a8b3ea..11729725c0e 100644
--- a/build/pkgs/glpk/package-version.txt
+++ b/build/pkgs/glpk/package-version.txt
@@ -1 +1 @@
-5.0.p0
+5.0.p1
diff --git a/build/pkgs/glpk/patches/error_recovery.patch b/build/pkgs/glpk/patches/error_recovery.patch
deleted file mode 100644
index a383e25769b..00000000000
--- a/build/pkgs/glpk/patches/error_recovery.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-From: Jeroen Demeyer
-Allow error recovery. See discussion at
-https://github.com/sagemath/sage/issues/20710#comment:18
-
-diff --git a/src/env/error.c b/src/env/error.c
-index a898b76..154de0f 100644
---- a/src/env/error.c
-+++ b/src/env/error.c
-@@ -48,6 +48,7 @@ static void errfunc(const char *fmt, ...)
- va_end(arg);
- xprintf("Error detected in file %s at line %d\n",
- env->err_file, env->err_line);
-+ env->err_st = 0;
- if (env->err_hook != NULL)
- env->err_hook(env->err_info);
- abort();
diff --git a/build/pkgs/httpcore/SPKG.rst b/build/pkgs/httpcore/SPKG.rst
index fed1a457967..a116180ec5f 100644
--- a/build/pkgs/httpcore/SPKG.rst
+++ b/build/pkgs/httpcore/SPKG.rst
@@ -1,10 +1,10 @@
-httpcore: A minimal low-level HTTP client.
-==========================================
+httpcore: Minimal low-level HTTP client
+=======================================
Description
-----------
-A minimal low-level HTTP client.
+Minimal low-level HTTP client
License
-------
diff --git a/build/pkgs/httpcore/checksums.ini b/build/pkgs/httpcore/checksums.ini
index 627dc72c115..21cb43c4bf6 100644
--- a/build/pkgs/httpcore/checksums.ini
+++ b/build/pkgs/httpcore/checksums.ini
@@ -1,4 +1,4 @@
tarball=httpcore-VERSION-py3-none-any.whl
-sha1=e83eb30232906df8ac673d6c49c657957dc00ce1
-sha256=ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73
+sha1=52c8337dcf474d63f5b053e0f65cf79714ae69fe
+sha256=421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5
upstream_url=https://pypi.io/packages/py3/h/httpcore/httpcore-VERSION-py3-none-any.whl
diff --git a/build/pkgs/httpcore/dependencies b/build/pkgs/httpcore/dependencies
index 36787c2193d..b47892606c1 100644
--- a/build/pkgs/httpcore/dependencies
+++ b/build/pkgs/httpcore/dependencies
@@ -1,4 +1,4 @@
-h11 | $(PYTHON_TOOLCHAIN) $(PYTHON)
+certifi h11 | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/httpcore/package-version.txt b/build/pkgs/httpcore/package-version.txt
index ee90284c27f..90a27f9cea6 100644
--- a/build/pkgs/httpcore/package-version.txt
+++ b/build/pkgs/httpcore/package-version.txt
@@ -1 +1 @@
-1.0.4
+1.0.5
diff --git a/build/pkgs/httpcore/spkg-configure.m4 b/build/pkgs/httpcore/spkg-configure.m4
new file mode 100644
index 00000000000..8ef9c0cbd4d
--- /dev/null
+++ b/build/pkgs/httpcore/spkg-configure.m4
@@ -0,0 +1,3 @@
+SAGE_SPKG_CONFIGURE([httpcore], [
+ SAGE_PYTHON_PACKAGE_CHECK([httpcore])
+])
diff --git a/build/pkgs/httpx/spkg-configure.m4 b/build/pkgs/httpx/spkg-configure.m4
new file mode 100644
index 00000000000..024f1a0c12c
--- /dev/null
+++ b/build/pkgs/httpx/spkg-configure.m4
@@ -0,0 +1,3 @@
+SAGE_SPKG_CONFIGURE([httpx], [
+ SAGE_PYTHON_PACKAGE_CHECK([httpx])
+])
diff --git a/build/pkgs/idna/checksums.ini b/build/pkgs/idna/checksums.ini
index 0381d537291..b3a22afe657 100644
--- a/build/pkgs/idna/checksums.ini
+++ b/build/pkgs/idna/checksums.ini
@@ -1,4 +1,4 @@
tarball=idna-VERSION-py3-none-any.whl
-sha1=352c6bd8ee12319953116397718c1a8ab6887259
-sha256=c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+sha1=ccb2491074ec1b6ffda6e6c11c1c668f885ed20a
+sha256=82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
upstream_url=https://pypi.io/packages/py3/i/idna/idna-VERSION-py3-none-any.whl
diff --git a/build/pkgs/idna/dependencies b/build/pkgs/idna/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/idna/dependencies
+++ b/build/pkgs/idna/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/idna/package-version.txt b/build/pkgs/idna/package-version.txt
index d70c8f8d89f..475ba515c04 100644
--- a/build/pkgs/idna/package-version.txt
+++ b/build/pkgs/idna/package-version.txt
@@ -1 +1 @@
-3.6
+3.7
diff --git a/build/pkgs/jinja2/checksums.ini b/build/pkgs/jinja2/checksums.ini
index fa9f5daf853..8f1cd2ceb6a 100644
--- a/build/pkgs/jinja2/checksums.ini
+++ b/build/pkgs/jinja2/checksums.ini
@@ -1,4 +1,4 @@
-tarball=Jinja2-VERSION-py3-none-any.whl
-sha1=2a4d66fe16c565145c8bec1b22d57ab1e7028613
-sha256=7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa
-upstream_url=https://pypi.io/packages/py3/j/jinja2/Jinja2-VERSION-py3-none-any.whl
+tarball=jinja2-VERSION-py3-none-any.whl
+sha1=57760ed83d9ad15fcdf63ad1ffa14941333ef655
+sha256=bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
+upstream_url=https://pypi.io/packages/py3/j/jinja2/jinja2-VERSION-py3-none-any.whl
diff --git a/build/pkgs/jinja2/dependencies b/build/pkgs/jinja2/dependencies
index 151ae9767d1..9236c02b29e 100644
--- a/build/pkgs/jinja2/dependencies
+++ b/build/pkgs/jinja2/dependencies
@@ -1,4 +1,4 @@
- markupsafe docutils | $(PYTHON_TOOLCHAIN) $(PYTHON)
+markupsafe | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/jinja2/package-version.txt b/build/pkgs/jinja2/package-version.txt
index ff365e06b95..0aec50e6ede 100644
--- a/build/pkgs/jinja2/package-version.txt
+++ b/build/pkgs/jinja2/package-version.txt
@@ -1 +1 @@
-3.1.3
+3.1.4
diff --git a/build/pkgs/markupsafe/checksums.ini b/build/pkgs/markupsafe/checksums.ini
index 53502ada131..8b2cb02af26 100644
--- a/build/pkgs/markupsafe/checksums.ini
+++ b/build/pkgs/markupsafe/checksums.ini
@@ -1,4 +1,4 @@
tarball=MarkupSafe-VERSION.tar.gz
-sha1=ffca1ac960cedaf0cb419b5c97b64aab12220d04
-sha256=3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f
+sha1=08593f9490b9be070aa2337e7311a392d33944dd
+sha256=d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b
upstream_url=https://pypi.io/packages/source/m/markupsafe/MarkupSafe-VERSION.tar.gz
diff --git a/build/pkgs/markupsafe/package-version.txt b/build/pkgs/markupsafe/package-version.txt
index 7d2ed7c7020..cd57a8b95d6 100644
--- a/build/pkgs/markupsafe/package-version.txt
+++ b/build/pkgs/markupsafe/package-version.txt
@@ -1 +1 @@
-2.1.4
+2.1.5
diff --git a/build/pkgs/nest_asyncio/checksums.ini b/build/pkgs/nest_asyncio/checksums.ini
index 2e37d5585ca..48626a85ae1 100644
--- a/build/pkgs/nest_asyncio/checksums.ini
+++ b/build/pkgs/nest_asyncio/checksums.ini
@@ -1,4 +1,4 @@
-tarball=nest_asyncio-VERSION.tar.gz
-sha1=e7d8036f6558011c5ae0c649e0af21eb530044d3
-sha256=25aa2ca0d2a5b5531956b9e273b45cf664cae2b145101d73b86b199978d48fdb
-upstream_url=https://pypi.io/packages/source/n/nest_asyncio/nest_asyncio-VERSION.tar.gz
+tarball=nest_asyncio-VERSION-py3-none-any.whl
+sha1=675b145491553e6a725884081244860a635552cd
+sha256=87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
+upstream_url=https://pypi.io/packages/py3/n/nest_asyncio/nest_asyncio-VERSION-py3-none-any.whl
diff --git a/build/pkgs/nest_asyncio/dependencies b/build/pkgs/nest_asyncio/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/nest_asyncio/dependencies
+++ b/build/pkgs/nest_asyncio/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/nest_asyncio/package-version.txt b/build/pkgs/nest_asyncio/package-version.txt
index 1cc9c180e26..dc1e644a101 100644
--- a/build/pkgs/nest_asyncio/package-version.txt
+++ b/build/pkgs/nest_asyncio/package-version.txt
@@ -1 +1 @@
-1.5.8
+1.6.0
diff --git a/build/pkgs/nest_asyncio/spkg-install.in b/build/pkgs/nest_asyncio/spkg-install.in
deleted file mode 100644
index 37ac1a53437..00000000000
--- a/build/pkgs/nest_asyncio/spkg-install.in
+++ /dev/null
@@ -1,2 +0,0 @@
-cd src
-sdh_pip_install .
diff --git a/build/pkgs/normaliz/checksums.ini b/build/pkgs/normaliz/checksums.ini
index acb6e5cde7f..c281052483f 100644
--- a/build/pkgs/normaliz/checksums.ini
+++ b/build/pkgs/normaliz/checksums.ini
@@ -1,4 +1,4 @@
tarball=normaliz-VERSION.tar.gz
-sha1=d3c4e554c6a5ccf4fd04147e7744a63e3def1766
-sha256=365e1d1e2a338dc4df1947a440e606bb66dd261307e617905e8eca64eaafcf6e
+sha1=ca5c9debcc3b1a02165659cf619935c37fa4faa4
+sha256=0aeb58fbbca362ed759f338a85e74156ed411e2846cc395f52d23ae90022ec91
upstream_url=https://github.com/Normaliz/Normaliz/releases/download/vVERSION/normaliz-VERSION.tar.gz
diff --git a/build/pkgs/normaliz/package-version.txt b/build/pkgs/normaliz/package-version.txt
index 2377fe517a0..7d4ef04f654 100644
--- a/build/pkgs/normaliz/package-version.txt
+++ b/build/pkgs/normaliz/package-version.txt
@@ -1 +1 @@
-3.10.1.p0
+3.10.3
diff --git a/build/pkgs/normaliz/patches/411.patch b/build/pkgs/normaliz/patches/411.patch
deleted file mode 100644
index d9e52bd78bf..00000000000
--- a/build/pkgs/normaliz/patches/411.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-commit ecdb62c90a3767b440800dcf2c49589e890a53b1
-Author: Matthias Koeppe
-Date: Tue Aug 8 17:03:32 2023 -0700
-
- full_cone.cpp: Remove debug output
-
-diff --git a/source/libnormaliz/full_cone.cpp b/source/libnormaliz/full_cone.cpp
-index 0fd906b3..cb2cce2b 100644
---- a/source/libnormaliz/full_cone.cpp
-+++ b/source/libnormaliz/full_cone.cpp
-@@ -3447,8 +3447,8 @@ void Full_Cone::build_cone_dynamic() {
- // if they aren't in a hyperplane anyway
- if(IntHullNorm.size() > 0){
- #pragma omp parallel for
-- for(size_t i = 0; i< OriGens.nr_of_rows(); ++i){
-- cout << "i " << i << " -- " << OriGensFloat[i];
-+ for (size_t i = 0; i< OriGens.nr_of_rows(); ++i){
-+ // cout << "i " << i << " -- " << OriGensFloat[i];
- nmz_float norm = v_scalar_product(OriGensFloat[i], IntHullNormFloat);
- v_scalar_division(OriGensFloat[i], norm);
- }
diff --git a/build/pkgs/normaliz/patches/flint3_d-torrance.patch b/build/pkgs/normaliz/patches/flint3_d-torrance.patch
deleted file mode 100644
index 5a6e36c51c4..00000000000
--- a/build/pkgs/normaliz/patches/flint3_d-torrance.patch
+++ /dev/null
@@ -1,55 +0,0 @@
---- a/source/libnormaliz/vector_operations.h
-+++ b/source/libnormaliz/vector_operations.h
-@@ -547,7 +547,10 @@
-
- fmpq_poly_fit_length(flp, n);
- for (size_t i = 0; i < poly_vector.size(); ++i) {
-- fmpq_poly_set_coeff_mpq(flp, (slong)i, poly_vector[i].get_mpq_t());
-+ fmpq_t fcurrent_coeff;
-+ fmpq_init(fcurrent_coeff);
-+ fmpq_set_mpq(fcurrent_coeff, poly_vector[i].get_mpq_t());
-+ fmpq_poly_set_coeff_fmpq(flp, (slong)i, fcurrent_coeff);
- }
- }
-
-@@ -560,8 +563,11 @@
- poly_vector.resize(length);
- for (slong i = 0; i < length; i++) {
- mpq_t current_coeff;
-+ fmpq_t fcurrent_coeff;
- mpq_init(current_coeff);
-- fmpq_poly_get_coeff_mpq(current_coeff, flp, (slong)i);
-+ fmpq_init(fcurrent_coeff);
-+ fmpq_poly_get_coeff_fmpq(fcurrent_coeff, flp, (slong)i);
-+ fmpq_get_mpq(current_coeff, fcurrent_coeff);
- poly_vector[i] = mpq_class(current_coeff);
- }
- }
---- a/source/libnormaliz/HilbertSeries.cpp
-+++ b/source/libnormaliz/HilbertSeries.cpp
-@@ -72,7 +72,10 @@
- slong n = (slong)nmzp.size();
- fmpz_poly_fit_length(flp, n);
- for (size_t i = 0; i < nmzp.size(); ++i) {
-- fmpz_poly_set_coeff_mpz(flp, (slong)i, nmzp[i].get_mpz_t());
-+ fmpz_t fc;
-+ fmpz_init(fc);
-+ fmpz_set_mpz(fc, nmzp[i].get_mpz_t());
-+ fmpz_poly_set_coeff_fmpz(flp, (slong)i, fc);
- }
- }
-
-@@ -80,9 +83,12 @@
- size_t n = (size_t)fmpz_poly_length(flp);
- nmzp.resize(n);
- mpz_t c;
-+ fmpz_t fc;
- mpz_init(c);
-+ fmpz_init(fc);
- for (size_t i = 0; i < nmzp.size(); ++i) {
-- fmpz_poly_get_coeff_mpz(c, flp, i);
-+ fmpz_poly_get_coeff_fmpz(fc, flp, i);
-+ fmpz_get_mpz(c, fc);
- nmzp[i] = mpz_class(c);
- }
- mpz_clear(c);
diff --git a/build/pkgs/parso/SPKG.rst b/build/pkgs/parso/SPKG.rst
index 4c279026db9..141fdc09499 100644
--- a/build/pkgs/parso/SPKG.rst
+++ b/build/pkgs/parso/SPKG.rst
@@ -1,5 +1,5 @@
-parso: A Python parser
-======================
+parso: Python Parser
+====================
Description
-----------
@@ -7,3 +7,14 @@ Description
Parso is a Python parser that supports error recovery and round-trip
parsing for different Python versions (in multiple Python versions).
Parso is also able to list multiple syntax errors in your python file.
+
+License
+-------
+
+MIT
+
+Upstream Contact
+----------------
+
+https://pypi.org/project/parso/
+
diff --git a/build/pkgs/parso/checksums.ini b/build/pkgs/parso/checksums.ini
index caae59d79e8..d15402d82de 100644
--- a/build/pkgs/parso/checksums.ini
+++ b/build/pkgs/parso/checksums.ini
@@ -1,4 +1,4 @@
-tarball=parso-VERSION.tar.gz
-sha1=1a34ea6e597a6498ef5c154195f9ffe8dda3d254
-sha256=8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0
-upstream_url=https://pypi.io/packages/source/p/parso/parso-VERSION.tar.gz
+tarball=parso-VERSION-py2.py3-none-any.whl
+sha1=091d37e09a601d854e18f4d42aeb478392bb7e63
+sha256=a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18
+upstream_url=https://pypi.io/packages/py2.py3/p/parso/parso-VERSION-py2.py3-none-any.whl
diff --git a/build/pkgs/parso/dependencies b/build/pkgs/parso/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/parso/dependencies
+++ b/build/pkgs/parso/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/parso/package-version.txt b/build/pkgs/parso/package-version.txt
index ee94dd834b5..b60d71966ae 100644
--- a/build/pkgs/parso/package-version.txt
+++ b/build/pkgs/parso/package-version.txt
@@ -1 +1 @@
-0.8.3
+0.8.4
diff --git a/build/pkgs/parso/spkg-install.in b/build/pkgs/parso/spkg-install.in
deleted file mode 100644
index 058b1344dc2..00000000000
--- a/build/pkgs/parso/spkg-install.in
+++ /dev/null
@@ -1,3 +0,0 @@
-cd src
-
-sdh_pip_install .
diff --git a/build/pkgs/platformdirs/checksums.ini b/build/pkgs/platformdirs/checksums.ini
index 28576a25b7f..201a01de014 100644
--- a/build/pkgs/platformdirs/checksums.ini
+++ b/build/pkgs/platformdirs/checksums.ini
@@ -1,4 +1,4 @@
tarball=platformdirs-VERSION-py3-none-any.whl
-sha1=487a4610a037c90b242aafbe1e3f8b6ebb3ba1c8
-sha256=0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068
+sha1=81890edbdf2f709f83001cb5bcfd71c3978225ce
+sha256=2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee
upstream_url=https://pypi.io/packages/py3/p/platformdirs/platformdirs-VERSION-py3-none-any.whl
diff --git a/build/pkgs/platformdirs/package-version.txt b/build/pkgs/platformdirs/package-version.txt
index 6aba2b245a8..af8c8ec7c13 100644
--- a/build/pkgs/platformdirs/package-version.txt
+++ b/build/pkgs/platformdirs/package-version.txt
@@ -1 +1 @@
-4.2.0
+4.2.2
diff --git a/build/pkgs/polymake/checksums.ini b/build/pkgs/polymake/checksums.ini
index b76cd23ad88..3173f176491 100644
--- a/build/pkgs/polymake/checksums.ini
+++ b/build/pkgs/polymake/checksums.ini
@@ -1,4 +1,4 @@
tarball=polymake-VERSION-minimal.tar.bz2
-sha1=0445f1a6d174906317a07c4bef299d0b4502c779
-sha256=5df6f0acd700119bd0c4b5766762852ffbd857765b5dcc88802ff5d2108add23
+sha1=aa1a153fac97a9faad61842f4a4232fbf444155f
+sha256=bd5a667ffca4bf7eb8d51134030ce3df3b16dd9d0e800fafdb1ce835867640d9
upstream_url=https://polymake.org/lib/exe/fetch.php/download/polymake-VERSION-minimal.tar.bz2
diff --git a/build/pkgs/polymake/package-version.txt b/build/pkgs/polymake/package-version.txt
index b849ff8ebf1..f5885845348 100644
--- a/build/pkgs/polymake/package-version.txt
+++ b/build/pkgs/polymake/package-version.txt
@@ -1 +1 @@
-4.11
+4.12
diff --git a/build/pkgs/prompt_toolkit/version_requirements.txt b/build/pkgs/prompt_toolkit/version_requirements.txt
index e3e1de9a3ea..b33ff7f30e1 100644
--- a/build/pkgs/prompt_toolkit/version_requirements.txt
+++ b/build/pkgs/prompt_toolkit/version_requirements.txt
@@ -1 +1 @@
-prompt_toolkit >=3.0.38
+prompt_toolkit >=3.0.43
diff --git a/build/pkgs/pycparser/checksums.ini b/build/pkgs/pycparser/checksums.ini
index 1e113dfcbf8..4d250e61a00 100644
--- a/build/pkgs/pycparser/checksums.ini
+++ b/build/pkgs/pycparser/checksums.ini
@@ -1,4 +1,4 @@
-tarball=pycparser-VERSION.tar.gz
-sha1=359c718c6ece361047f61846b9fa4ea0239576dc
-sha256=e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
-upstream_url=https://pypi.io/packages/source/p/pycparser/pycparser-VERSION.tar.gz
+tarball=pycparser-VERSION-py3-none-any.whl
+sha1=34702512290f3bfd4850bcc95dfaf1ae972a8929
+sha256=c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
+upstream_url=https://pypi.io/packages/py3/p/pycparser/pycparser-VERSION-py3-none-any.whl
diff --git a/build/pkgs/pycparser/dependencies b/build/pkgs/pycparser/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/pycparser/dependencies
+++ b/build/pkgs/pycparser/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/pycparser/package-version.txt b/build/pkgs/pycparser/package-version.txt
index 2ef40bd8c62..4699fb07e80 100644
--- a/build/pkgs/pycparser/package-version.txt
+++ b/build/pkgs/pycparser/package-version.txt
@@ -1 +1 @@
-2.21
+2.22
diff --git a/build/pkgs/pycparser/spkg-install.in b/build/pkgs/pycparser/spkg-install.in
deleted file mode 100644
index deba1bb42bb..00000000000
--- a/build/pkgs/pycparser/spkg-install.in
+++ /dev/null
@@ -1 +0,0 @@
-cd src && sdh_pip_install .
diff --git a/build/pkgs/pygments/checksums.ini b/build/pkgs/pygments/checksums.ini
index c534a4a9a4d..5a54fdd0b9a 100644
--- a/build/pkgs/pygments/checksums.ini
+++ b/build/pkgs/pygments/checksums.ini
@@ -1,4 +1,4 @@
tarball=pygments-VERSION-py3-none-any.whl
-sha1=053e17b72ffea04e200d7b34edbe0f96b4b68e4b
-sha256=b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c
+sha1=edb9fdfbc4cf53d356a02beee8822dd8e9529f35
+sha256=b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
upstream_url=https://pypi.io/packages/py3/p/pygments/pygments-VERSION-py3-none-any.whl
diff --git a/build/pkgs/pygments/dependencies b/build/pkgs/pygments/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/pygments/dependencies
+++ b/build/pkgs/pygments/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/pygments/package-version.txt b/build/pkgs/pygments/package-version.txt
index 94dc0ec9104..cf8690732fe 100644
--- a/build/pkgs/pygments/package-version.txt
+++ b/build/pkgs/pygments/package-version.txt
@@ -1 +1 @@
-2.17.2
+2.18.0
diff --git a/build/pkgs/pynormaliz/checksums.ini b/build/pkgs/pynormaliz/checksums.ini
index 25b41b1c0ab..154f2bfb4c0 100644
--- a/build/pkgs/pynormaliz/checksums.ini
+++ b/build/pkgs/pynormaliz/checksums.ini
@@ -1,4 +1,4 @@
tarball=PyNormaliz-VERSION.tar.gz
-sha1=08617ca50ce0e0317a3377381bf37c1a0ab826c1
-sha256=359218cf35f400c43f338a132b7887f6a2affb05057c4e7eaa315a9f2b6a8b39
+sha1=4ce4fef4db61a0408bc84747294922fc49afc090
+sha256=95d29fff9380ea2948166fd2b4c730985e0881043fa41f3e44ff9f402b97f0b4
upstream_url=https://pypi.io/packages/source/p/pynormaliz/PyNormaliz-VERSION.tar.gz
diff --git a/build/pkgs/pynormaliz/package-version.txt b/build/pkgs/pynormaliz/package-version.txt
index fae0ceb2953..a4b5a6f4a49 100644
--- a/build/pkgs/pynormaliz/package-version.txt
+++ b/build/pkgs/pynormaliz/package-version.txt
@@ -1 +1 @@
-2.18.p0
+2.20
diff --git a/build/pkgs/pyparsing/checksums.ini b/build/pkgs/pyparsing/checksums.ini
index 7c946098d45..931d057f6b8 100644
--- a/build/pkgs/pyparsing/checksums.ini
+++ b/build/pkgs/pyparsing/checksums.ini
@@ -1,4 +1,4 @@
tarball=pyparsing-VERSION-py3-none-any.whl
-sha1=c44cd9476ad90a48af0f27d8f7966136b2a93fc6
-sha256=32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb
+sha1=bf1ab91fb997ccee2793e1e7f22a56a25f5e3a93
+sha256=f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742
upstream_url=https://pypi.io/packages/py3/p/pyparsing/pyparsing-VERSION-py3-none-any.whl
diff --git a/build/pkgs/pyparsing/package-version.txt b/build/pkgs/pyparsing/package-version.txt
index 94ff29cc4de..ef538c28109 100644
--- a/build/pkgs/pyparsing/package-version.txt
+++ b/build/pkgs/pyparsing/package-version.txt
@@ -1 +1 @@
-3.1.1
+3.1.2
diff --git a/build/pkgs/python3/SPKG.rst b/build/pkgs/python3/SPKG.rst
index 55757b972e6..b102c79fbbb 100644
--- a/build/pkgs/python3/SPKG.rst
+++ b/build/pkgs/python3/SPKG.rst
@@ -15,6 +15,9 @@ You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use
a number of Python modules to be available within the Python in question. Currently,
as of Sage 10.3, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``,
``hashlib``, ``socket``, ``zlib``, ``ssl``, ``ensurepip``.
+For Python >= 3.12, also ``setuptools`` is required; for older Python versions,
+``distutils.core`` is required. These modules will be checked for by the ``configure``
+script.
Use the ``configure`` option ``--without-system-python3`` if you want Python 3
built from scratch.
diff --git a/build/pkgs/python3/checksums.ini b/build/pkgs/python3/checksums.ini
index f0f0ce6eb75..73dddf24722 100644
--- a/build/pkgs/python3/checksums.ini
+++ b/build/pkgs/python3/checksums.ini
@@ -1,4 +1,4 @@
tarball=Python-VERSION.tar.xz
-sha1=a368aeed7a3325e47b55168452c356a8eb27ab50
-sha256=9e06008c8901924395bc1da303eac567a729ae012baa182ab39269f650383bb3
+sha1=c221421f3ba734daaf013dbdc7b48aa725cea18e
+sha256=f6d419a6d8743ab26700801b4908d26d97e8b986e14f95de31b32de2b0e79554
upstream_url=https://www.python.org/ftp/python/VERSION/Python-VERSION.tar.xz
diff --git a/build/pkgs/python3/package-version.txt b/build/pkgs/python3/package-version.txt
index b6d8b7612f0..455808f8e19 100644
--- a/build/pkgs/python3/package-version.txt
+++ b/build/pkgs/python3/package-version.txt
@@ -1 +1 @@
-3.11.8
+3.12.4
diff --git a/build/pkgs/python3/patches/0001-bpo-22699-Allow-compiling-on-debian-ubuntu-with-a-di.patch b/build/pkgs/python3/patches/0001-bpo-22699-Allow-compiling-on-debian-ubuntu-with-a-di.patch
deleted file mode 100644
index ec3d84c8499..00000000000
--- a/build/pkgs/python3/patches/0001-bpo-22699-Allow-compiling-on-debian-ubuntu-with-a-di.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From aef4a7749dec9ecf942647af39d7a1303c758131 Mon Sep 17 00:00:00 2001
-From: Isuru Fernando
-Date: Thu, 16 Sep 2021 15:46:09 -0500
-Subject: [PATCH 08/24] bpo-22699: Allow compiling on debian/ubuntu with a
- different compiler
-
-This PR fixes one issue mentioned in the bpo
-https://bugs.python.org/issue22699#msg364685 with a slightly better
-patch than given
----
- setup.py | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
-diff --git a/setup.py b/setup.py
-index 554699608d..d5bbeb90d5 100644
---- a/setup.py
-+++ b/setup.py
-@@ -667,9 +667,30 @@ def check_extension_import(self, ext):
- def add_multiarch_paths(self):
- # Debian/Ubuntu multiarch support.
- # https://wiki.ubuntu.com/MultiarchSpec
-- tmpfile = os.path.join(self.build_temp, 'multiarch')
- if not os.path.exists(self.build_temp):
- os.makedirs(self.build_temp)
-+
-+ tmpfile_sysroot = os.path.join(self.build_temp, 'sysroot')
-+ ret_sysroot = run_command(
-+ '%s -print-sysroot > %s 2> /dev/null' % (CC, tmpfile_sysroot))
-+
-+ try:
-+ if ret_sysroot == 0:
-+ with open(tmpfile_sysroot) as fp:
-+ sysroot = fp.readline().strip()
-+ # if the sysroot is not /, then we are not using
-+ # the compiler from debian/ubuntu
-+ if sysroot not in ['', '/']:
-+ add_dir_to_list(self.compiler.library_dirs,
-+ sysroot + '/usr/lib/')
-+ add_dir_to_list(self.compiler.include_dirs,
-+ sysroot + '/usr/include/')
-+ return
-+ finally:
-+ os.unlink(tmpfile_sysroot)
-+
-+ tmpfile = os.path.join(self.build_temp, 'multiarch')
-+
- ret = run_command(
- '%s -print-multiarch > %s 2> /dev/null' % (CC, tmpfile))
- multiarch_path_component = ''
---- a/setup.py 2021-09-28 23:49:53.193868987 -0700
-+++ b/setup.py 2021-09-28 23:50:13.554098642 -0700
-@@ -738,7 +738,8 @@
- for env_var, arg_name, dir_list in (
- ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
- ('LDFLAGS', '-L', self.compiler.library_dirs),
-- ('CPPFLAGS', '-I', self.compiler.include_dirs)):
-+ ('CPPFLAGS', '-I', self.compiler.include_dirs),
-+ ('CPPFLAGS', '-isystem', self.compiler.include_dirs)):
- env_val = sysconfig.get_config_var(env_var)
- if env_val:
- parser = argparse.ArgumentParser()
---
-2.30.2
-
diff --git a/build/pkgs/python3/patches/linux_linking_issue_25229.patch b/build/pkgs/python3/patches/linux_linking_issue_25229.patch
deleted file mode 100644
index 43131a27913..00000000000
--- a/build/pkgs/python3/patches/linux_linking_issue_25229.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ru a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
---- a/Lib/distutils/unixccompiler.py 2018-06-27 05:07:35.000000000 +0200
-+++ b/Lib/distutils/unixccompiler.py 2018-06-28 09:32:52.719006731 +0200
-@@ -234,7 +234,7 @@
- return ["-Wl,+s", "-L" + dir]
- return ["+s", "-L" + dir]
- else:
-- if self._is_gcc(compiler):
-+ if sys.platform[:5] == "linux" or self._is_gcc(compiler):
- # gcc on non-GNU systems does not need -Wl, but can
- # use it anyway. Since distutils has always passed in
- # -Wl whenever gcc was used in the past it is probably
diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4
index d67601a98ae..a51e2394e51 100644
--- a/build/pkgs/python3/spkg-configure.m4
+++ b/build/pkgs/python3/spkg-configure.m4
@@ -1,7 +1,7 @@
SAGE_SPKG_CONFIGURE([python3], [
m4_pushdef([MIN_VERSION], [3.9.0])
m4_pushdef([MIN_NONDEPRECATED_VERSION], [3.9.0])
- m4_pushdef([LT_STABLE_VERSION], [3.12.0])
+ m4_pushdef([LT_STABLE_VERSION], [3.13.0])
m4_pushdef([LT_VERSION], [3.13.0])
AC_ARG_WITH([python],
[AS_HELP_STRING([--with-python=PYTHON3],
diff --git a/build/pkgs/r/SPKG.rst b/build/pkgs/r/SPKG.rst
index 584294e891a..393860a2064 100644
--- a/build/pkgs/r/SPKG.rst
+++ b/build/pkgs/r/SPKG.rst
@@ -24,3 +24,14 @@ Upstream Contact
- https://www.r-project.org
- R mailing list, #R in IRC
+
+
+Special Installation Instructions
+---------------------------------
+
+In the Sage distribution, ``r`` is a "dummy" package:
+It is here to provide information about equivalent system packages.
+R cannot be installed using the Sage distribution.
+Please install it manually, either using one of the system package
+commands shown here or following the upstream instructions
+at https://www.r-project.org
diff --git a/build/pkgs/r/distros/conda.txt b/build/pkgs/r/distros/conda.txt
index 4c235733c5f..741d5f82d93 100644
--- a/build/pkgs/r/distros/conda.txt
+++ b/build/pkgs/r/distros/conda.txt
@@ -1,2 +1,3 @@
r
r-essentials
+r-lattice
diff --git a/build/pkgs/requests/checksums.ini b/build/pkgs/requests/checksums.ini
index 8b0dc85bd89..d7a9d3b8c66 100644
--- a/build/pkgs/requests/checksums.ini
+++ b/build/pkgs/requests/checksums.ini
@@ -1,4 +1,4 @@
tarball=requests-VERSION-py3-none-any.whl
-sha1=60b928b15e05d04a33b880a0232e44258c777740
-sha256=58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f
+sha1=e82ece8f17ba4237cc5a4fd641349e45e1d3ddfd
+sha256=fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
upstream_url=https://pypi.io/packages/py3/r/requests/requests-VERSION-py3-none-any.whl
diff --git a/build/pkgs/requests/dependencies b/build/pkgs/requests/dependencies
index 668fe014f12..6d09b791ef2 100644
--- a/build/pkgs/requests/dependencies
+++ b/build/pkgs/requests/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) idna urllib3 certifi charset_normalizer $(PYTHON)
+charset_normalizer idna urllib3 certifi | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/requests/package-version.txt b/build/pkgs/requests/package-version.txt
index bafceb320ec..544fe5d4382 100644
--- a/build/pkgs/requests/package-version.txt
+++ b/build/pkgs/requests/package-version.txt
@@ -1 +1 @@
-2.31.0
+2.32.2
diff --git a/build/pkgs/rpy2/SPKG.rst b/build/pkgs/rpy2/SPKG.rst
index 3ba34445021..ba81ab6c098 100644
--- a/build/pkgs/rpy2/SPKG.rst
+++ b/build/pkgs/rpy2/SPKG.rst
@@ -12,12 +12,16 @@ License
-------
- GPL 2+
-- Note that we have deleted references to Mozilla PL as an option,
- which we are allowed to do by the full rpy2 license in order to
- remain GPL-compatible
-
Upstream Contact
----------------
-- https://rpy2.bitbucket.io
+- https://github.com/rpy2/rpy2
+
+Special Installation Instructions
+---------------------------------
+
+In the Sage distribution, ``rpy2`` is a "semi-standard" package: It will be
+automatically installed by the Sage distribution if a suitable system
+installation of R is detected by ``configure``. (Note that Sage no longer
+ships and installs its own copy of R.)
diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt
index bf5142c02e5..dca9dbbf204 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.4b9
+sage-conf ~= 10.4rc0
diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt
index 3bc4e773ff1..008698c16c6 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.4b9
+sage-docbuild ~= 10.4rc0
diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt
index d04bde41fdd..e20cf38ff03 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.4b9
+sage-setup ~= 10.4rc0
diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt
index d3698b0a9ae..62965fc6d95 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.4b9
+sage-sws2rst ~= 10.4rc0
diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt
index 1dd1a4f846b..bf2e7bc9cda 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.4b9
+sagemath-standard ~= 10.4rc0
diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt
index bc95834828a..da26126cba2 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.4b9
+sagemath-bliss ~= 10.4rc0
diff --git a/build/pkgs/sagemath_categories/type b/build/pkgs/sagemath_categories/type
index 9839eb20815..134d9bc32d5 100644
--- a/build/pkgs/sagemath_categories/type
+++ b/build/pkgs/sagemath_categories/type
@@ -1 +1 @@
-experimental
+optional
diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt
index 08fa02e2044..ba9c2395040 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.4b9
+sagemath-categories ~= 10.4rc0
diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt
index 13e0b652f36..d9b7a8503be 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.4b9
+sagemath-coxeter3 ~= 10.4rc0
diff --git a/build/pkgs/sagemath_environment/type b/build/pkgs/sagemath_environment/type
index 9839eb20815..134d9bc32d5 100644
--- a/build/pkgs/sagemath_environment/type
+++ b/build/pkgs/sagemath_environment/type
@@ -1 +1 @@
-experimental
+optional
diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt
index 72433ad30cd..3f7a3473daa 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.4b9
+sagemath-environment ~= 10.4rc0
diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt
index 76e1fd5907c..5fd55401260 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.4b9
+sagemath-mcqd ~= 10.4rc0
diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt
index db6dcee5827..b1217ec6b0a 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.4b9
+sagemath-meataxe ~= 10.4rc0
diff --git a/build/pkgs/sagemath_objects/type b/build/pkgs/sagemath_objects/type
index 9839eb20815..134d9bc32d5 100644
--- a/build/pkgs/sagemath_objects/type
+++ b/build/pkgs/sagemath_objects/type
@@ -1 +1 @@
-experimental
+optional
diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt
index a48fb049cb7..a7052900eec 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.4b9
+sagemath-objects ~= 10.4rc0
diff --git a/build/pkgs/sagemath_repl/type b/build/pkgs/sagemath_repl/type
index 9839eb20815..134d9bc32d5 100644
--- a/build/pkgs/sagemath_repl/type
+++ b/build/pkgs/sagemath_repl/type
@@ -1 +1 @@
-experimental
+optional
diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt
index 661b369f395..3615095a834 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.4b9
+sagemath-repl ~= 10.4rc0
diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt
index af89ffdd30f..066d5854f62 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.4b9
+sagemath-sirocco ~= 10.4rc0
diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt
index 13e940295b6..74cf6d8910c 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.4b9
+sagemath-tdlib ~= 10.4rc0
diff --git a/build/pkgs/send2trash/checksums.ini b/build/pkgs/send2trash/checksums.ini
index d99aecb6b2f..8617b6b9b6b 100644
--- a/build/pkgs/send2trash/checksums.ini
+++ b/build/pkgs/send2trash/checksums.ini
@@ -1,4 +1,4 @@
-tarball=Send2Trash-VERSION.tar.gz
-sha1=211092dcefa5468582f7d083472ad7f1880cc019
-sha256=c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312
-upstream_url=https://pypi.io/packages/source/s/send2trash/Send2Trash-VERSION.tar.gz
+tarball=Send2Trash-VERSION-py3-none-any.whl
+sha1=e24d3494febe78a4a1c8ecbfde78ed52e78cf299
+sha256=0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9
+upstream_url=https://pypi.io/packages/py3/s/send2trash/Send2Trash-VERSION-py3-none-any.whl
diff --git a/build/pkgs/send2trash/dependencies b/build/pkgs/send2trash/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/send2trash/dependencies
+++ b/build/pkgs/send2trash/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/send2trash/package-version.txt b/build/pkgs/send2trash/package-version.txt
index 53adb84c822..a7ee35a3ea7 100644
--- a/build/pkgs/send2trash/package-version.txt
+++ b/build/pkgs/send2trash/package-version.txt
@@ -1 +1 @@
-1.8.2
+1.8.3
diff --git a/build/pkgs/send2trash/spkg-install.in b/build/pkgs/send2trash/spkg-install.in
deleted file mode 100644
index deba1bb42bb..00000000000
--- a/build/pkgs/send2trash/spkg-install.in
+++ /dev/null
@@ -1 +0,0 @@
-cd src && sdh_pip_install .
diff --git a/build/pkgs/sniffio/checksums.ini b/build/pkgs/sniffio/checksums.ini
index 8379b1841d0..c3a342052ec 100644
--- a/build/pkgs/sniffio/checksums.ini
+++ b/build/pkgs/sniffio/checksums.ini
@@ -1,4 +1,4 @@
tarball=sniffio-VERSION-py3-none-any.whl
-sha1=16f883fd7e31aa383df8901002f9ce5cec7606e5
-sha256=eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
+sha1=bd8d1ec2b285eed542c53ca22232e6e9e468c389
+sha256=2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2
upstream_url=https://pypi.io/packages/py3/s/sniffio/sniffio-VERSION-py3-none-any.whl
diff --git a/build/pkgs/sniffio/dependencies b/build/pkgs/sniffio/dependencies
index 47296a7bace..644ad35f773 100644
--- a/build/pkgs/sniffio/dependencies
+++ b/build/pkgs/sniffio/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/sniffio/package-version.txt b/build/pkgs/sniffio/package-version.txt
index f0bb29e7638..3a3cd8cc8b0 100644
--- a/build/pkgs/sniffio/package-version.txt
+++ b/build/pkgs/sniffio/package-version.txt
@@ -1 +1 @@
-1.3.0
+1.3.1
diff --git a/build/pkgs/sympy/SPKG.rst b/build/pkgs/sympy/SPKG.rst
index 12ccea9393b..45138f58d5b 100644
--- a/build/pkgs/sympy/SPKG.rst
+++ b/build/pkgs/sympy/SPKG.rst
@@ -24,16 +24,5 @@ New BSD: http://www.opensource.org/licenses/bsd-license.php
Upstream Contact
----------------
-sympy mailinglist: http://groups.google.com/group/sympy
+https://pypi.org/project/sympy/
-Dependencies
-------------
-
-- Python 2.5 or later
-
-
-Special Update/Build Instructions
----------------------------------
-
-- A simple script can be used to ease the updating of the SPKG. See the
- README.
diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini
index 4a8b9107b71..30e67c20de6 100644
--- a/build/pkgs/sympy/checksums.ini
+++ b/build/pkgs/sympy/checksums.ini
@@ -1,4 +1,4 @@
-tarball=sympy-VERSION.tar.gz
-sha1=604968f191e2d69053b8310066d089f73a1bd109
-sha256=ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8
-upstream_url=https://github.com/sympy/sympy/releases/download/sympy-VERSION/sympy-VERSION.tar.gz
+tarball=sympy-VERSION-py3-none-any.whl
+sha1=80fa00ab605295d61992ca3faa76771a62944527
+sha256=9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515
+upstream_url=https://pypi.io/packages/py3/s/sympy/sympy-VERSION-py3-none-any.whl
diff --git a/build/pkgs/sympy/dependencies b/build/pkgs/sympy/dependencies
index 6480ac46289..d5cdd780fb4 100644
--- a/build/pkgs/sympy/dependencies
+++ b/build/pkgs/sympy/dependencies
@@ -1,4 +1,4 @@
- mpmath | $(PYTHON_TOOLCHAIN) $(PYTHON)
+mpmath | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt
index 809bdcb851d..f8f4f03b3dc 100644
--- a/build/pkgs/sympy/package-version.txt
+++ b/build/pkgs/sympy/package-version.txt
@@ -1 +1 @@
-1.12
+1.12.1
diff --git a/build/pkgs/sympy/spkg-install.in b/build/pkgs/sympy/spkg-install.in
deleted file mode 100644
index 058b1344dc2..00000000000
--- a/build/pkgs/sympy/spkg-install.in
+++ /dev/null
@@ -1,3 +0,0 @@
-cd src
-
-sdh_pip_install .
diff --git a/build/pkgs/tdlib/SPKG.rst b/build/pkgs/tdlib/SPKG.rst
index ebcdd1213e0..9f4c30a3d01 100644
--- a/build/pkgs/tdlib/SPKG.rst
+++ b/build/pkgs/tdlib/SPKG.rst
@@ -1,32 +1,23 @@
-tdlib: Algorithms for computing tree decompositions
-===================================================
+tdlib: Algorithms for computing tree decompositions of graphs
+=============================================================
Description
-----------
-Providing algorithms concerning treedecompositions
+This library, now known as treedec,
+provides algorithms concerning tree decompositions.
-website: https://github.com/freetdi/tdlib
License
-------
-GNU General Public License v2
-
-
-SPKG Maintainers
-----------------
-
-Lukas Larisch (lukas.larisch@kaust.edu.sa)
+- GNU General Public License v2
+- GNU General Public License v3
Upstream Contact
----------------
-- Lukas Larisch (lukas.larisch@kaust.edu.sa)
-- git-repo: https://github.com/freetdi/tdlib
-
-Dependencies
-------------
-
-- None
+- https://gitlab.com/freetdi/treedec
+- https://github.com/freetdi/tdlib
+- https://github.com/felix-salfelder
diff --git a/build/pkgs/tdlib/checksums.ini b/build/pkgs/tdlib/checksums.ini
index 6f3275ad092..36ade31259e 100644
--- a/build/pkgs/tdlib/checksums.ini
+++ b/build/pkgs/tdlib/checksums.ini
@@ -1,3 +1,4 @@
-tarball=tdlib-VERSION.tar.gz
-sha1=8e200d0e3ac009030f3ada6658d20717e433220f
-sha256=5a40375e738e9e6dbd37f53e54deb1efa6b58f154d83b7bfeaee9f47d47b444b
+tarball=treedec-VERSION.tar.gz
+sha1=355930ce66a14afed89d32ead280bfdd801d53d7
+sha256=16f9683af4c33e3e79fe36439cb4bb4b63216ad88d59f5dc00dd3fb9256aa4ae
+upstream_url=https://www.algok.uni-bamberg.de/treedec/treedec-VERSION.tar.gz
diff --git a/build/pkgs/tdlib/dependencies b/build/pkgs/tdlib/dependencies
new file mode 100644
index 00000000000..d568ea3cf53
--- /dev/null
+++ b/build/pkgs/tdlib/dependencies
@@ -0,0 +1 @@
+boost_cropped
diff --git a/build/pkgs/tdlib/package-version.txt b/build/pkgs/tdlib/package-version.txt
index af2629893df..998ed53f13a 100644
--- a/build/pkgs/tdlib/package-version.txt
+++ b/build/pkgs/tdlib/package-version.txt
@@ -1 +1 @@
-0.3.1.p0
+0.9.3.p0
diff --git a/build/pkgs/tdlib/patches/0001-src-exact_cutset.hpp-Suppress-incomplete-message.patch b/build/pkgs/tdlib/patches/0001-src-exact_cutset.hpp-Suppress-incomplete-message.patch
new file mode 100644
index 00000000000..9369b84d496
--- /dev/null
+++ b/build/pkgs/tdlib/patches/0001-src-exact_cutset.hpp-Suppress-incomplete-message.patch
@@ -0,0 +1,25 @@
+From f9bea896a49ef909aeb910c140661ab06b3b6a0b Mon Sep 17 00:00:00 2001
+From: Matthias Koeppe
+Date: Fri, 7 Jun 2024 12:21:28 -0700
+Subject: [PATCH] src/exact_cutset.hpp: Suppress 'incomplete' message
+
+---
+ src/exact_cutset.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/exact_cutset.hpp b/src/exact_cutset.hpp
+index 782bb96..2caa7bd 100755
+--- a/src/exact_cutset.hpp
++++ b/src/exact_cutset.hpp
+@@ -994,7 +994,7 @@ bool exact_cutset::try_it(T_t &T, unsigned bagsize)
+ }else{
+ // incomplete(); //no//
+ // messes up random tests, send to cerr instead
+- std::cerr << "incomplete ../../src/exact_cutset.hpp:978:try_it\n";
++ // std::cerr << "incomplete ../../src/exact_cutset.hpp:978:try_it\n";
+ }
+
+ typename boost::graph_traits::vertex_iterator vIt, vEnd;
+--
+2.42.0
+
diff --git a/build/pkgs/tdlib/spkg-install.in b/build/pkgs/tdlib/spkg-install.in
index 9ee5b9f1566..09c5e4899a0 100644
--- a/build/pkgs/tdlib/spkg-install.in
+++ b/build/pkgs/tdlib/spkg-install.in
@@ -1,5 +1,5 @@
cd src
-sdh_configure
+sdh_configure --with-python=no
sdh_make
sdh_make_install -j1
diff --git a/build/pkgs/traitlets/checksums.ini b/build/pkgs/traitlets/checksums.ini
index 4be4683da86..ad86191465c 100644
--- a/build/pkgs/traitlets/checksums.ini
+++ b/build/pkgs/traitlets/checksums.ini
@@ -1,4 +1,4 @@
-tarball=traitlets-VERSION.tar.gz
-sha1=9f4cb2a04ffba7029ad67bbec3d39a23e9095db2
-sha256=fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772
-upstream_url=https://pypi.io/packages/source/t/traitlets/traitlets-VERSION.tar.gz
+tarball=traitlets-VERSION-py3-none-any.whl
+sha1=a6c667ce2b3adf2ab3562f144067f02326383c25
+sha256=b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
+upstream_url=https://pypi.io/packages/py3/t/traitlets/traitlets-VERSION-py3-none-any.whl
diff --git a/build/pkgs/traitlets/dependencies b/build/pkgs/traitlets/dependencies
index 85237293d1c..644ad35f773 100644
--- a/build/pkgs/traitlets/dependencies
+++ b/build/pkgs/traitlets/dependencies
@@ -1,4 +1,4 @@
- | $(PYTHON_TOOLCHAIN) ipython_genutils hatchling $(PYTHON)
+ | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/traitlets/package-version.txt b/build/pkgs/traitlets/package-version.txt
index 0a70cf03ca9..487fc4986a9 100644
--- a/build/pkgs/traitlets/package-version.txt
+++ b/build/pkgs/traitlets/package-version.txt
@@ -1 +1 @@
-5.14.0
+5.14.3
diff --git a/build/pkgs/traitlets/spkg-install.in b/build/pkgs/traitlets/spkg-install.in
deleted file mode 100644
index deba1bb42bb..00000000000
--- a/build/pkgs/traitlets/spkg-install.in
+++ /dev/null
@@ -1 +0,0 @@
-cd src && sdh_pip_install .
diff --git a/build/pkgs/typing_extensions/checksums.ini b/build/pkgs/typing_extensions/checksums.ini
index 2c1dd61052d..c22c17569af 100644
--- a/build/pkgs/typing_extensions/checksums.ini
+++ b/build/pkgs/typing_extensions/checksums.ini
@@ -1,4 +1,4 @@
tarball=typing_extensions-VERSION-py3-none-any.whl
-sha1=84d6a73b5a5d303c9187a861d5eedd50da42e7a3
-sha256=8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0
+sha1=049c6031f754e1c33932ce1c2ad78b857a70a244
+sha256=b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594
upstream_url=https://pypi.io/packages/py3/t/typing_extensions/typing_extensions-VERSION-py3-none-any.whl
diff --git a/build/pkgs/typing_extensions/package-version.txt b/build/pkgs/typing_extensions/package-version.txt
index 88f181192c4..815588ef140 100644
--- a/build/pkgs/typing_extensions/package-version.txt
+++ b/build/pkgs/typing_extensions/package-version.txt
@@ -1 +1 @@
-4.8.0
+4.12.0
diff --git a/build/pkgs/virtualenv/checksums.ini b/build/pkgs/virtualenv/checksums.ini
index 386df56a132..c83cfa5112d 100644
--- a/build/pkgs/virtualenv/checksums.ini
+++ b/build/pkgs/virtualenv/checksums.ini
@@ -1,4 +1,4 @@
tarball=virtualenv-VERSION-py3-none-any.whl
-sha1=9c942063d76d85361f0567b59cce8238c57f1183
-sha256=4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3
+sha1=f18ea5b827ba66a1724769371c6912601ec4d647
+sha256=a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b
upstream_url=https://pypi.io/packages/py3/v/virtualenv/virtualenv-VERSION-py3-none-any.whl
diff --git a/build/pkgs/virtualenv/dependencies b/build/pkgs/virtualenv/dependencies
index 148ef28948e..16beaa039a1 100644
--- a/build/pkgs/virtualenv/dependencies
+++ b/build/pkgs/virtualenv/dependencies
@@ -1,4 +1,4 @@
-distlib filelock platformdirs | pip $(PYTHON)
+distlib filelock importlib_metadata platformdirs | pip $(PYTHON)
----------
All lines of this file are ignored except the first.
diff --git a/build/pkgs/virtualenv/package-version.txt b/build/pkgs/virtualenv/package-version.txt
index 242a1e92b72..608d0b1c8b7 100644
--- a/build/pkgs/virtualenv/package-version.txt
+++ b/build/pkgs/virtualenv/package-version.txt
@@ -1 +1 @@
-20.25.0
+20.26.2
diff --git a/build/pkgs/zipp/checksums.ini b/build/pkgs/zipp/checksums.ini
index aef55046c00..1af443d7f19 100644
--- a/build/pkgs/zipp/checksums.ini
+++ b/build/pkgs/zipp/checksums.ini
@@ -1,4 +1,4 @@
tarball=zipp-VERSION-py3-none-any.whl
-sha1=8dd92e1b777b02ec6e1ebe72926d32a82c58b246
-sha256=0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31
+sha1=22cf149f293964ac7538ad41af8caa9aacf8fe1a
+sha256=96dc6ad62f1441bcaccef23b274ec471518daf4fbbc580341204936a5a3dddec
upstream_url=https://pypi.io/packages/py3/z/zipp/zipp-VERSION-py3-none-any.whl
diff --git a/build/pkgs/zipp/package-version.txt b/build/pkgs/zipp/package-version.txt
index 3f67e25cea1..419f3009654 100644
--- a/build/pkgs/zipp/package-version.txt
+++ b/build/pkgs/zipp/package-version.txt
@@ -1 +1 @@
-3.17.0
+3.19.0
diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py
index 018e5a2d5b5..2b8b44959b1 100644
--- a/build/sage_bootstrap/app.py
+++ b/build/sage_bootstrap/app.py
@@ -441,6 +441,7 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre
if not version:
version = pypi_version.version
if dependencies is None:
+ log.info('Requires-Python: {0}'.format(pypi_version.requires_python))
requires_dist = pypi_version.requires_dist
if requires_dist:
dependencies = []
diff --git a/build/sage_bootstrap/package.py b/build/sage_bootstrap/package.py
index bc607ebb6e6..c063af0c816 100644
--- a/build/sage_bootstrap/package.py
+++ b/build/sage_bootstrap/package.py
@@ -31,7 +31,7 @@ def __new__(cls, package_name):
if package_name.startswith("pypi/") or package_name.startswith("generic/"):
package_name = "pkg:" + package_name
if package_name.startswith("pkg:"):
- package_name = package_name.replace('_', '-')
+ package_name = package_name.replace('_', '-').lower()
if package_name.startswith("pkg:generic/"): # fast path
try:
pkg = cls(package_name[len("pkg:generic/"):].replace('-', '_'))
diff --git a/build/sage_bootstrap/pypi.py b/build/sage_bootstrap/pypi.py
index 9427e9c8808..215feb69343 100644
--- a/build/sage_bootstrap/pypi.py
+++ b/build/sage_bootstrap/pypi.py
@@ -114,6 +114,13 @@ def requires_dist(self):
"""
return self.json['info']['requires_dist']
+ @property
+ def requires_python(self):
+ """
+ Return the requires_python attribute
+ """
+ return self.json['info']['requires_python']
+
def update(self, package=None):
if package is None:
package = Package(self.name)
diff --git a/m4/sage_python_package_check.m4 b/m4/sage_python_package_check.m4
index 6465a67d7c0..921639e3735 100644
--- a/m4/sage_python_package_check.m4
+++ b/m4/sage_python_package_check.m4
@@ -8,8 +8,8 @@
# Determine if the system copy of a python package can be used by sage.
#
# This macro uses setuptools.version's pkg_resources to check that the
-# "version_requirements.txt" file for the named package is satisfied, and
-# it can typically fail in four ways:
+# "version_requirements.txt" file (or entry in "src/pyproject.toml") for
+# the named package is satisfied, and it can typically fail in four ways:
#
# 1. If --enable-system-site-packages was not passed to ./configure,
#
@@ -19,8 +19,9 @@
#
# 4. If setuptools is not available to the system python,
#
-# 5. If the contents of version_requirements.txt are not met (wrong
-# version, no version, etc.) by the system python.
+# 5. If the contents of version_requirements.txt (or entry in
+# "src/pyproject.toml") are not met (wrong version, no version,
+# etc.) by the system python.
#
# In any of those cases, we set sage_spkg_install_$package to "yes"
# so that the corresponding SPKG is installed. Otherwise, we do
@@ -56,29 +57,17 @@ AC_DEFUN([SAGE_PYTHON_PACKAGE_CHECK], [
config.venv dnl
2>&AS_MESSAGE_LOG_FD], [
AC_MSG_RESULT(yes)
- dnl strip all comments from version_requirements.txt; this should leave
- dnl only a single line containing the version specification for this
- dnl package. Afterwards, convert all double-quotes to single quotes.
- dnl Both work, but only single quotes are documented. However, at the
- dnl time of writing, double quotes are more compatible with our toml
- dnl generation in ./bootstrap. Converting them from double- to single-
- dnl quotes on-the-fly here lets us support both (in this macro, at
- dnl least).
- SAGE_PKG_VERSPEC=$(sed \
- -e '/^#/d' \
- -e "s/\"/'/g" \
- "./build/pkgs/$1/version_requirements.txt"
- )
- AC_MSG_CHECKING([for python package $1 ("${SAGE_PKG_VERSPEC}")])
+ dnl SAGE_PKG_VERSPEC is in the format of a toml list, but
+ dnl without surrounding brackets, of single-quoted strings,
+ dnl with any double-quotes escaped by backslash.
+ AS_VAR_SET([SAGE_PKG_VERSPEC], ["SPKG_INSTALL_REQUIRES_]$1["])
+ AC_MSG_CHECKING([for python package $1 (${SAGE_PKG_VERSPEC%,})])
WITH_SAGE_PYTHONUSERBASE([dnl
- dnl double-quote SAGE_PKG_VERSPEC because platform-specific
- dnl dependencies like python_version<'3.11' will have single
- dnl quotes in them. (We normalized the quotes earlier with sed.)
AS_IF(
- [config.venv/bin/python3 -c dnl
- "import pkg_resources; dnl
- pkg_resources.require(\"${SAGE_PKG_VERSPEC}\".splitlines())" dnl
+ [config.venv/bin/python3 -c dnl
+ "import pkg_resources; dnl
+ pkg_resources.require((${SAGE_PKG_VERSPEC}))" dnl
2>&AS_MESSAGE_LOG_FD],
[AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no); sage_spkg_install_$1=yes]
diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4
index 28480d720dd..231193ce8fb 100644
--- a/m4/sage_spkg_collect.m4
+++ b/m4/sage_spkg_collect.m4
@@ -75,7 +75,15 @@ m4_include([m4/sage_spkg_configures.m4])
dnl ==========================================================================
AC_DEFUN([SAGE_SPKG_COLLECT_INIT], [
+AS_BOX([Build status for each package: ]) >& AS_MESSAGE_FD
+AS_BOX([Build status for each package: ]) >& AS_MESSAGE_LOG_FD
dnl Intialize the collection variables.
+SPKGS="$1"
+dnl Obtain versions at configure time.
+AS_IF([properties=$($SAGE_BOOTSTRAP_PYTHON build/bin/sage-package properties --format=shell $SPKGS 2>& AS_MESSAGE_LOG_FD) && eval $properties], [], [
+ AC_MSG_ERROR([Package directory missing. Re-run bootstrap.])dnl
+])
+
# To deal with ABI incompatibilities when gcc is upgraded, every package
# (except gcc) should depend on gcc if gcc is already installed.
# See https://github.com/sagemath/sage/issues/24703
@@ -86,20 +94,6 @@ else
fi
AC_SUBST([SAGE_GCC_DEP])
-AS_BOX([Build status for each package: ]) >& AS_MESSAGE_FD
-AS_BOX([Build status for each package: ]) >& AS_MESSAGE_LOG_FD
-
-# Usage: newest_version $pkg
-# Print version number of latest package $pkg
-newest_version() {
- SPKG=$[1]
- if test -f "$SAGE_ROOT/build/pkgs/$SPKG/package-version.txt" ; then
- cat "$SAGE_ROOT/build/pkgs/$SPKG/package-version.txt"
- else
- echo none
- fi
-}
-
# Packages that are actually built/installed as opposed to packages that are
# not required on this platform or that can be taken from the underlying system
# installation. Note that this contains packages that are not actually going to
@@ -157,16 +151,15 @@ AC_DEFUN([SAGE_SPKG_FINALIZE], [dnl
dnl depending on the package type and other criteria (such as whether or not it
dnl needs to be installed)
dnl
- DIR="$SAGE_ROOT"/build/pkgs/SPKG_NAME
- AS_IF([test ! -d "$DIR"], [dnl
- AC_MSG_ERROR([Directory $DIR is missing. Re-run bootstrap.])dnl
- ])
- dnl
- SPKG_VERSION=$(newest_version SPKG_NAME)
+ SPKG_VERSION=$[version_with_patchlevel_]SPKG_NAME
dnl
dnl Determine package source
dnl
m4_case(SPKG_SOURCE,
+ [wheel], [dnl Treat it the same as a normal package
+ m4_define([SPKG_SOURCE], [normal])dnl
+ m4_define([in_sdist], [yes])dnl
+ ],
[normal], [dnl
m4_define([in_sdist], [yes])dnl
], [dnl pip/script/none (dummy package)
@@ -206,7 +199,7 @@ AC_DEFUN([SAGE_SPKG_FINALIZE], [dnl
AS_IF([test -r "$f"], [dnl
AS_IF([test "$is_installed" = "yes"], [dnl
m4_case(SPKG_SOURCE, [normal], [dnl
- dnl Only issue the multiple installation record test for normal packages,
+ dnl Only issue the multiple installation record test for normal/wheel packages,
dnl not for script packages.
AC_MSG_ERROR(m4_normalize([
multiple installation records for SPKG_NAME:
@@ -346,6 +339,7 @@ AC_DEFUN([SAGE_SPKG_FINALIZE], [dnl
dnl
dnl Determine package dependencies
dnl
+ DIR=$[path_]SPKG_NAME
AS_IF([test -f "$DIR/dependencies"], [dnl
dnl - the # symbol is treated as comment which is removed
AS_VAR_SET([DEPS], [`sed 's/^ *//; s/ *#.*//; q' $DIR/dependencies`])
diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-conf/VERSION.txt
+++ b/pkgs/sage-conf/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-conf_conda/VERSION.txt
+++ b/pkgs/sage-conf_conda/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-conf_pypi/VERSION.txt
+++ b/pkgs/sage-conf_pypi/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-docbuild/VERSION.txt
+++ b/pkgs/sage-docbuild/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-setup/VERSION.txt
+++ b/pkgs/sage-setup/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sage-sws2rst/VERSION.txt
+++ b/pkgs/sage-sws2rst/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-bliss/README.rst b/pkgs/sagemath-bliss/README.rst
index 72526111226..b1a27056fd4 100644
--- a/pkgs/sagemath-bliss/README.rst
+++ b/pkgs/sagemath-bliss/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-bliss/VERSION.txt
+++ b/pkgs/sagemath-bliss/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-categories/README.rst b/pkgs/sagemath-categories/README.rst
index 398b5f81a91..01e974442f8 100644
--- a/pkgs/sagemath-categories/README.rst
+++ b/pkgs/sagemath-categories/README.rst
@@ -8,27 +8,25 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
-About this experimental pip-installable source distribution
------------------------------------------------------------
+About this pip-installable distribution package
+-----------------------------------------------
-This pip-installable source distribution `sagemath-categories` is an
-experimental distribution of a small part of the Sage Library. Use at your own
-risk. It provides a small subset of the modules of the Sage library
-("sagelib", `sagemath-standard`). It is a superset of the `sagemath-objects`
+The pip-installable distribution package `sagemath-categories` is a
+distribution of a small part of the Sage Library.
+
+It provides a small subset of the modules of the Sage library
+("sagelib", `sagemath-standard`) that is a superset of `sagemath-objects`
(providing Sage objects, the element/parent framework, categories, the coercion
system and the related metaclasses), making various additional categories
available without introducing dependencies on additional mathematical
diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-categories/VERSION.txt
+++ b/pkgs/sagemath-categories/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-coxeter3/README.rst b/pkgs/sagemath-coxeter3/README.rst
index c75e83995a3..4df12768344 100644
--- a/pkgs/sagemath-coxeter3/README.rst
+++ b/pkgs/sagemath-coxeter3/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-coxeter3/VERSION.txt
+++ b/pkgs/sagemath-coxeter3/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst
index a8003060bd9..9c36dbc67df 100644
--- a/pkgs/sagemath-environment/README.rst
+++ b/pkgs/sagemath-environment/README.rst
@@ -8,26 +8,24 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
-About this experimental pip-installable source distribution
------------------------------------------------------------
+About this pip-installable distribution package
+-----------------------------------------------
-This pip-installable source distribution `sagemath-environment` is an
-experimental distribution of a small part of the Sage Library. Use at your own
-risk. It provides a small, fundamental subset of the modules of the Sage
+The pip-installable distribution package `sagemath-environment` is a
+distribution of a small part of the Sage Library.
+
+It provides a small, fundamental subset of the modules of the Sage
library ("sagelib", `sagemath-standard`), providing the connection to the
system and software environment. It also includes the `sage` script for
launching the Sage REPL and accessing various developer tools (see `sage
diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-environment/VERSION.txt
+++ b/pkgs/sagemath-environment/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-mcqd/README.rst b/pkgs/sagemath-mcqd/README.rst
index 4fcf37ec1a3..a0da3415874 100644
--- a/pkgs/sagemath-mcqd/README.rst
+++ b/pkgs/sagemath-mcqd/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-mcqd/VERSION.txt
+++ b/pkgs/sagemath-mcqd/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-meataxe/README.rst b/pkgs/sagemath-meataxe/README.rst
index e38540cc304..69c03deee6f 100644
--- a/pkgs/sagemath-meataxe/README.rst
+++ b/pkgs/sagemath-meataxe/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-meataxe/VERSION.txt
+++ b/pkgs/sagemath-meataxe/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-objects/README.rst b/pkgs/sagemath-objects/README.rst
index e2959d72eae..11f2444e982 100644
--- a/pkgs/sagemath-objects/README.rst
+++ b/pkgs/sagemath-objects/README.rst
@@ -8,26 +8,24 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
-About this experimental pip-installable source distribution
------------------------------------------------------------
+About this pip-installable distribution package
+-----------------------------------------------
-This pip-installable source distribution `sagemath-objects` is an experimental
-distribution of a small part of the Sage Library. Use at your own risk. It
-provides a small, fundamental subset of the modules of the Sage library
+The pip-installable distribution package `sagemath-objects` is a
+distribution of a small part of the Sage Library.
+
+It provides a small, fundamental subset of the modules of the Sage library
("sagelib", `sagemath-standard`), making Sage objects, the element/parent
framework, categories, the coercion system and the related metaclasses
available.
diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-objects/VERSION.txt
+++ b/pkgs/sagemath-objects/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-repl/README.rst b/pkgs/sagemath-repl/README.rst
index 115614a5d7e..53c3ac0e2de 100644
--- a/pkgs/sagemath-repl/README.rst
+++ b/pkgs/sagemath-repl/README.rst
@@ -8,25 +8,23 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
-About this experimental pip-installable source distribution
------------------------------------------------------------
+About this pip-installable distribution package
+-----------------------------------------------
-This pip-installable source distribution `sagemath-repl` is an experimental
-distribution of a small part of the Sage Library. Use at your own risk. It
-provides a small, fundamental subset of the modules of the Sage library
+The pip-installable source distribution `sagemath-repl` is a
+distribution of a small part of the Sage Library.
+
+It provides a small, fundamental subset of the modules of the Sage library
("sagelib", `sagemath-standard`), providing the IPython kernel, Sage preparser,
and doctester.
diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-repl/VERSION.txt
+++ b/pkgs/sagemath-repl/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-sirocco/README.rst b/pkgs/sagemath-sirocco/README.rst
index 824ca3b03a6..31d70482784 100644
--- a/pkgs/sagemath-sirocco/README.rst
+++ b/pkgs/sagemath-sirocco/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-sirocco/VERSION.txt
+++ b/pkgs/sagemath-sirocco/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/pkgs/sagemath-tdlib/README.rst b/pkgs/sagemath-tdlib/README.rst
index fb1729a073c..2f7d210e52f 100644
--- a/pkgs/sagemath-tdlib/README.rst
+++ b/pkgs/sagemath-tdlib/README.rst
@@ -8,18 +8,15 @@ About SageMath
"Creating a Viable Open Source Alternative to
Magma, Maple, Mathematica, and MATLAB"
- Copyright (C) 2005-2023 The Sage Development Team
+ Copyright (C) 2005-2024 The Sage Development Team
https://www.sagemath.org
SageMath fully supports all major Linux distributions, recent versions of
macOS, and Windows (Windows Subsystem for Linux).
-The traditional and recommended way to install SageMath is from source via
-Sage-the-distribution (https://www.sagemath.org/download-source.html).
-Sage-the-distribution first builds a large number of open source packages from
-source (unless it finds suitable versions installed in the system) and then
-installs the Sage Library (sagelib, implemented in Python and Cython).
+See https://doc.sagemath.org/html/en/installation/index.html
+for general installation instructions.
About this pip-installable source distribution
diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/pkgs/sagemath-tdlib/VERSION.txt
+++ b/pkgs/sagemath-tdlib/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/src/VERSION.txt b/src/VERSION.txt
index 88de6ab407c..ab84d34dabd 100644
--- a/src/VERSION.txt
+++ b/src/VERSION.txt
@@ -1 +1 @@
-10.4.beta9
+10.4.rc0
diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh
index e07f9f4e32b..b0b4139bf29 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.4.beta9'
-SAGE_RELEASE_DATE='2024-06-09'
-SAGE_VERSION_BANNER='SageMath version 10.4.beta9, Release Date: 2024-06-09'
+SAGE_VERSION='10.4.rc0'
+SAGE_RELEASE_DATE='2024-06-22'
+SAGE_VERSION_BANNER='SageMath version 10.4.rc0, Release Date: 2024-06-22'
diff --git a/src/doc/en/developer/portability_platform_table.rst b/src/doc/en/developer/portability_platform_table.rst
index 6b8c0724001..67ebb9f7c0b 100644
--- a/src/doc/en/developer/portability_platform_table.rst
+++ b/src/doc/en/developer/portability_platform_table.rst
@@ -1618,60 +1618,6 @@
.. |codespace-centos-7-devtoolset-gcc_11-maximal| image:: https://github.com/codespaces/badge.svg
:target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-7-devtoolset-gcc_11-maximal%2Fdevcontainer.json
-.. |image-centos-stream-8-python3.9-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-system-packages
-
-.. |image-centos-stream-8-python3.9-minimal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-minimal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-minimal-configured
-
-.. |image-centos-stream-8-python3.9-minimal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%23677895
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets-pre
-
-.. |image-centos-stream-8-python3.9-minimal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%236686c1
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets
-
-.. |image-centos-stream-8-python3.9-minimal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%236495ed
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-minimal-with-targets-optional
-
-.. |codespace-centos-stream-8-python3.9-minimal| image:: https://github.com/codespaces/badge.svg
- :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-8-python3.9-minimal%2Fdevcontainer.json
-
-.. |image-centos-stream-8-python3.9-standard-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-system-packages
-
-.. |image-centos-stream-8-python3.9-standard-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-standard-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-standard-configured
-
-.. |image-centos-stream-8-python3.9-standard-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%235d8a4c
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets-pre
-
-.. |image-centos-stream-8-python3.9-standard-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%2350ab2e
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets
-
-.. |image-centos-stream-8-python3.9-standard-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%2344cc11
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-standard-with-targets-optional
-
-.. |codespace-centos-stream-8-python3.9-standard| image:: https://github.com/codespaces/badge.svg
- :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-8-python3.9-standard%2Fdevcontainer.json
-
-.. |image-centos-stream-8-python3.9-maximal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-system-packages
-
-.. |image-centos-stream-8-python3.9-maximal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-maximal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-maximal-configured
-
-.. |image-centos-stream-8-python3.9-maximal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%238f6b8d
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets-pre
-
-.. |image-centos-stream-8-python3.9-maximal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%23b46eb2
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets
-
-.. |image-centos-stream-8-python3.9-maximal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%23da70d6
- :target: https://ghcr.io/sagemath/sage/sage-centos-stream-8-python3.9-maximal-with-targets-optional
-
-.. |codespace-centos-stream-8-python3.9-maximal| image:: https://github.com/codespaces/badge.svg
- :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-8-python3.9-maximal%2Fdevcontainer.json
-
.. |image-centos-stream-9-python3.9-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969
:target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-system-packages
@@ -2712,17 +2658,6 @@
* - ‑*maximal*
- |image-centos-7-devtoolset-gcc_11-maximal-with-system-packages| |image-centos-7-devtoolset-gcc_11-maximal-with-targets-pre|
-
- * - **centos**-stream-8-python3.9
-
- ‑*minimal*
- - |image-centos-stream-8-python3.9-minimal-with-system-packages| |image-centos-stream-8-python3.9-minimal-with-targets-pre| |image-centos-stream-8-python3.9-minimal-with-targets| |image-centos-stream-8-python3.9-minimal-with-targets-optional|
- - |codespace-centos-stream-8-python3.9-minimal|
- * - ‑*standard*
- - |image-centos-stream-8-python3.9-standard-with-system-packages| |image-centos-stream-8-python3.9-standard-with-targets-pre| |image-centos-stream-8-python3.9-standard-with-targets| |image-centos-stream-8-python3.9-standard-with-targets-optional|
- - |codespace-centos-stream-8-python3.9-standard|
- * - ‑*maximal*
- - |image-centos-stream-8-python3.9-maximal-with-system-packages| |image-centos-stream-8-python3.9-maximal-with-targets-pre|
- -
* - **centos**-stream-9-python3.9
‑*minimal*
diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst
index 6f50276a5ed..621767627b5 100644
--- a/src/doc/en/reference/algebras/index.rst
+++ b/src/doc/en/reference/algebras/index.rst
@@ -79,6 +79,7 @@ Hecke algebras
:maxdepth: 1
sage/algebras/hecke_algebras/ariki_koike_algebra
+ sage/algebras/hecke_algebras/ariki_koike_specht_modules
sage/algebras/iwahori_hecke_algebra
sage/algebras/nil_coxeter_algebra
sage/algebras/yokonuma_hecke_algebra
diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst
index 3d314f9c466..b7725c7848b 100644
--- a/src/doc/en/reference/references/index.rst
+++ b/src/doc/en/reference/references/index.rst
@@ -154,6 +154,12 @@ REFERENCES:
equilibria for two-person
games*. http://www.maths.lse.ac.uk/personal/stengel/TEXTE/nashsurvey.pdf (2002)
+.. [AHK1994] Sheldon B. Akers, Doy Horel and Balakrishnan Krishnamurthy,
+ *The star graph: An attractive alternative to the previous n-cube*.
+ In Interconnection Networks for High-Performance Parallel
+ Computers, pp. 145-152, 1994. IEEE.
+ :doi:`10.5555/201173.201191`
+
.. [AHK2015] Karim Adiprasito, June Huh, and Eric Katz. *Hodge theory
for combinatorial geometries*. :arxiv:`1511.02888`.
@@ -1451,6 +1457,11 @@ REFERENCES:
rationalité d'une série génératrice associée
aux arbres*, RAIRO, Inf. Théor. 16, 113--128 (1982)
+.. [CC1995] Wei-Kuo Chiang, Rong-Jaye Chen: *The (n, k)-star graph: A
+ generalized star graph*. Information Processing Letters
+ 56(5): 259-264, 1995.
+ :doi:`10.1016/0020-0190(95)00162-1`
+
.. [CC2013] Mahir Bilen Can and Yonah Cherniavsky.
*Omitting parentheses from the cyclic notation*. (2013).
:arxiv:`1308.0936v2`.
@@ -2315,6 +2326,9 @@ REFERENCES:
.. [DPVAR2000] \J. Daemen, M. Peeters, G. Van Assche, and V. Rijmen,
*Nessie proposal: NOEKEON*; in First Open NESSIE Workshop, (2000).
+.. [DR2001] \J. Du and H. Rui. *Specht modules for Ariki–Koike algebras*,
+ Comm. Alg., **29** (2001), 4710-4719.
+
.. [DR2002] Joan Daemen, Vincent Rijmen. *The Design of
Rijndael*. Springer-Verlag Berlin Heidelberg, 2002.
@@ -2683,6 +2697,10 @@ REFERENCES:
*Quantization of Lie Groups and Lie Algebras*.
Leningrad Math. J. vol. **1** (1990), no. 1.
+.. [Fru1977] Roberto Frucht. *A Canonical Representation of Trivalent
+ Hamiltonian Graphs*. Journal of Graph Theory, 1:45-60, 1977.
+ :doi:`10.1002/jgt.3190010111`
+
.. [FS1978] Dominique Foata, Marcel-Paul Schuetzenberger.
*Major Index and Inversion Number of Permutations*.
Mathematische Nachrichten, volume 83, Issue 1, pages 143-159, 1978.
@@ -3039,6 +3057,11 @@ REFERENCES:
4-polytopes with 8 vertices", J. Comb. Th. 2,
437-465 (1967)
+.. [Gru2003] Branko Grünbaum. *Convex Polytopes* (2nd ed),.
+ volume 221 of Graduate Texts in Mathematics, Springer, 2003.
+ (1st ed, 1967, Wiley New York).
+ :doi:`10.1007/978-1-4613-0019-9`
+
.. [GS1984] \A. M. Garsia, Dennis Stanton.
*Group actions on Stanley-Reisner rings and invariants of
permutation groups*. Adv. in Math. **51** (1984), 107-201.
@@ -4222,6 +4245,14 @@ REFERENCES:
Simons Symposia, Springer, 2021.
:arxiv:`2002.05234`
+.. [Led1965] Joshua Lederberg. *DENDRAL-64: A System for Computer
+ Construction, Enumeration and Notation of Organic
+ Molecules as Tree Structures and Cyclic
+ Graphs. Part II. Topology of Cyclic Graphs*. Interim
+ Report to the National Aeronautics and Space
+ Administration. Grant NsG 81-60. December 15, 1965.
+ https://ntrs.nasa.gov/api/citations/19660004785/downloads/19660004785.pdf
+
.. [Lee2016] Kwankyu Lee, *Decoding of differential AG codes*, Advances in
Mathematics of Communications, vol. 10, no. 2 (2016), pp. 307-–319.
@@ -4621,13 +4652,20 @@ REFERENCES:
Providence, RI, 1999. xiv+188 pp. ISBN: 0-8218-1926-7
:mathscinet:`MR1711316`
-.. [Mat2002] Jiří Matousek, "Lectures on Discrete Geometry", Springer,
- 2002
+.. [Mathas2002] Andrew Mathas.
+ *The representation theory of the Ariki-Koike and
+ cyclotomic* `q`-*Schur algebras*.
+ Representation Theory of Algebraic Groups and Quantum Groups,
+ Adv. Stud. Pure Math., vol. 40, Math. Soc. Japan, Tokyo (2004),
+ pp. 261-320. :arxiv:`math/0204025`.
.. [Mathas2004] Andrew Mathas.
*Matrix units and generic degrees for the Ariki-Koike algebras*.
J. Algebra. **281** (2004) pp. 695-730.
+.. [Mat2002] Jiří Matousek, "Lectures on Discrete Geometry", Springer,
+ 2002
+
.. [Mas1995] Mason, Geoffrey. *The quantum double of a finite group and its role
in conformal field theory*. Groups '93 Galway/St. Andrews, Vol. 2,
405-417, London Math. Soc. Lecture Note Ser., 212, Cambridge, 1995.
@@ -6383,6 +6421,11 @@ REFERENCES:
Journal of Combinatorial Theory, Series A 16.3 (1974), pp 313–333.
:doi:`10.1016/0097-3165(74)90056-9`
+.. [TVY2020] \N. V. Tsilevich, A. M. Vershik, and S. Yuzvinsky.
+ *The intrinsic hyperplane arrangement in an arbitrary irreducible
+ representation of the symmetric group*, Arnold Math. J. **6**
+ no. 2 (2020) pp. 173-187.
+
.. [TW1980] \A.D. Thomas and G.V. Wood, Group Tables (Exeter: Shiva
Publishing, 1980)
@@ -6579,6 +6622,9 @@ REFERENCES:
*Coboundary categories and local rules*,
The Electronic Journal of Combinatorics, *25* (2018)
+.. [West2001] Douglas B. West. *Introduction to Graph Theory*. 2nd
+ Edition, Prentice Hall, 2001, p. 150–151.
+
.. [WFYTP2008] \D. Watanable, S. Furuya, H. Yoshida, K. Takaragi, and B. Preneel,
*A new keystream generator MUGI*; in
FSE, (2002), pp. 179-194.
diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py
index 100a3d335f3..72744da3904 100644
--- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py
+++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py
@@ -39,7 +39,8 @@ class FiniteDimensionalAlgebraIdeal(Ideal_generic):
EXAMPLES::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: A.ideal(A([0,1]))
Ideal (e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3
"""
@@ -47,9 +48,10 @@ def __init__(self, A, gens=None, given_by_matrix=False):
"""
EXAMPLES::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: I = A.ideal(A([0,1]))
- sage: TestSuite(I).run(skip="_test_category") # Currently ideals are not using the category framework
+ sage: TestSuite(I).run(skip="_test_category") # Currently ideals are not using the category framework
"""
k = A.base_ring()
n = A.degree()
@@ -76,7 +78,8 @@ def _richcmp_(self, other, op):
TESTS::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: I = A.ideal(A([1,1]))
sage: J = A.ideal(A([0,1]))
sage: I == J
@@ -86,7 +89,8 @@ def _richcmp_(self, other, op):
sage: I == I + J
True
- sage: A2 = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A2 = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: A is A2
True
sage: A == A2
@@ -130,7 +134,8 @@ def __contains__(self, elt):
"""
EXAMPLES::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: J = A.ideal(A([0,1]))
sage: A([0,1]) in J
True
@@ -147,7 +152,8 @@ def basis_matrix(self):
EXAMPLES::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: I = A.ideal(A([1,1]))
sage: I.basis_matrix()
[1 0]
@@ -162,7 +168,8 @@ def vector_space(self):
EXAMPLES::
- sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
+ sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]),
+ ....: Matrix([[0, 1], [0, 0]])])
sage: I = A.ideal(A([1,1]))
sage: I.vector_space()
Vector space of degree 2 and dimension 2 over Finite Field of size 3
diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py
index c4ade5274b2..0523ff4b9dc 100644
--- a/src/sage/algebras/free_algebra_quotient_element.py
+++ b/src/sage/algebras/free_algebra_quotient_element.py
@@ -38,6 +38,10 @@ def is_FreeAlgebraQuotientElement(x):
sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
sage: sage.algebras.free_algebra_quotient_element.is_FreeAlgebraQuotientElement(i)
+ doctest:warning...
+ DeprecationWarning: The function is_FreeAlgebraQuotientElement is deprecated;
+ use 'isinstance(..., FreeAlgebraQuotientElement)' instead.
+ See https://github.com/sagemath/sage/issues/38184 for details.
True
Of course this is testing the data type::
@@ -47,6 +51,10 @@ def is_FreeAlgebraQuotientElement(x):
sage: sage.algebras.free_algebra_quotient_element.is_FreeAlgebraQuotientElement(H(1))
True
"""
+ from sage.misc.superseded import deprecation
+ deprecation(38184,
+ "The function is_FreeAlgebraQuotientElement is deprecated; "
+ "use 'isinstance(..., FreeAlgebraQuotientElement)' instead.")
return isinstance(x, FreeAlgebraQuotientElement)
diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py
index 30078e8ecdf..3bc2e541f7e 100644
--- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py
+++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py
@@ -192,6 +192,8 @@ class ArikiKoikeAlgebra(Parent, UniqueRepresentation):
default is the generators of `\ZZ[u_1, \ldots, u_r]`
- ``R`` -- (optional) a commutative ring containing ``q`` and ``u``;
the default is the parent of `q` and `u_1, \ldots, u_r`
+ - ``use_fraction_field`` -- (default: ``False``) whether to use the
+ fraction field or not
EXAMPLES:
@@ -268,7 +270,7 @@ class ArikiKoikeAlgebra(Parent, UniqueRepresentation):
True
"""
@staticmethod
- def __classcall_private__(cls, r, n, q=None, u=None, R=None):
+ def __classcall_private__(cls, r, n, q=None, u=None, R=None, use_fraction_field=False):
r"""
Standardize input to ensure a unique representation.
@@ -311,11 +313,12 @@ def __classcall_private__(cls, r, n, q=None, u=None, R=None):
R = cm.common_parent(q.parent(), *[val.parent() for val in u])
elif q is None:
q = 'q'
- u = [R(val) for val in u]
if R not in Rings().Commutative():
raise TypeError("base ring must be a commutative ring")
+ if use_fraction_field:
+ R = R.fraction_field()
q = R(q)
- u = tuple(u)
+ u = tuple([R(val) for val in u])
return super().__classcall__(cls, r, n, q, u, R)
def __init__(self, r, n, q, u, R):
@@ -414,6 +417,21 @@ def a_realization(self):
"""
return self.LT()
+ def specht_module(self, la):
+ r"""
+ Return the Specht module of ``self`` corresponding to the shape ``la``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(4, 6)
+ sage: AK.specht_module([[2], [], [1,1,1], [1]])
+ Specht module of shape ([2], [], [1, 1, 1], [1]) for
+ Ariki-Koike algebra of rank 4 and order 6 with q=q and u=(u0, u1, u2, u3)
+ over ... over Integer Ring
+ """
+ from sage.algebras.hecke_algebras.ariki_koike_specht_modules import SpechtModule
+ return SpechtModule(self, la)
+
class _BasesCategory(Category_realization_of_parent):
r"""
The category of bases of a Ariki-Koike algebra.
@@ -566,6 +584,24 @@ def some_elements(self):
elts += [self.L(2)**(self._r//2)]
return elts
+ def specht_module(self, la):
+ r"""
+ Return the Specht module of ``self`` corresponding
+ to the shape ``la``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(4, 3)
+ sage: LT = AK.LT()
+ sage: S1 = LT.specht_module([[1], [], [1,1], []])
+ sage: T = AK.T()
+ sage: S2 = T.specht_module([[1], [], [1,1], []])
+ sage: S1 is S2
+ True
+ """
+ from sage.algebras.hecke_algebras.ariki_koike_specht_modules import SpechtModule
+ return SpechtModule(self.realization_of(), la)
+
# -----------------------------------------------------
# Basis classes
# -----------------------------------------------------
@@ -1186,6 +1222,18 @@ def __init__(self, algebra):
_Basis.__init__(self, algebra, prefix='T')
self._assign_names(['T%s' % i for i in range(self._n)])
+ def _basis_to_word(self, t):
+ """
+ Return the basis element indexed by ``m`` to a word.
+ """
+ redword = []
+ for i, k in enumerate(t[0]):
+ if not k:
+ continue
+ redword.extend(list(range(i, 0, -1)) + [0]*k)
+ redword.extend(t[1].reduced_word())
+ return redword
+
def _repr_term(self, t):
r"""
Return a string representation of the basis element indexed by ``m``.
@@ -1196,13 +1244,8 @@ def _repr_term(self, t):
sage: T._repr_term( ((1,0,2), Permutation([3,2,1])) )
'T[0,2,1,0,0,2,1,2]'
"""
- redword = []
- for i,k in enumerate(t[0]):
- if k == 0:
- continue
- redword += list(reversed(range(1,i+1))) + [0]*k
- redword += t[1].reduced_word()
- if len(redword) == 0:
+ redword = self._basis_to_word(t)
+ if not redword:
return "1"
return (self._print_options['prefix']
+ '[%s]' % ','.join('%d' % i for i in redword))
@@ -1215,15 +1258,10 @@ def _latex_term(self, t):
sage: T = algebras.ArikiKoike(4, 3).T()
sage: T._latex_term( ((1,0,2), Permutation([3,2,1])) )
- 'T_{0}T_{1}T_{0}T_{0}T_{2}T_{1}T_{2}'
+ 'T_{0}T_{2}T_{1}T_{0}T_{0}T_{2}T_{1}T_{2}'
"""
- redword = []
- for i,k in enumerate(t[0]):
- if k == 0:
- continue
- redword += list(reversed(range(1,i))) + [0]*k
- redword += t[1].reduced_word()
- if len(redword) == 0:
+ redword = self._basis_to_word(t)
+ if not redword:
return "1"
return ''.join("%s_{%d}" % (self._print_options['prefix'], i)
for i in redword)
@@ -1529,7 +1567,7 @@ def product_on_basis(self, m1, m2):
# Compute t1 * T * sprod
def compute(T, sprod):
- if not T: # T=1, so just do t1 * sprod, each of which is in order
+ if not T: # T=1, so just do t1 * sprod, each of which is in order
return self._from_dict({(t1, s): sprod[s] for s in sprod},
remove_zeros=False, coerce=False)
diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py b/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py
new file mode 100644
index 00000000000..2bb7974ab35
--- /dev/null
+++ b/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py
@@ -0,0 +1,473 @@
+r"""
+Ariki-Koike Algebra Representations
+
+AUTHORS:
+
+- Travis Scrimshaw (2023-12-28): Initial version
+"""
+
+#*****************************************************************************
+# Copyright (C) 2023 Travis Scrimshaw
+#
+# 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/
+#*****************************************************************************
+
+from sage.misc.misc_c import prod
+from sage.misc.latex import latex
+from sage.categories.modules import Modules
+from sage.rings.integer_ring import ZZ
+from sage.combinat.free_module import CombinatorialFreeModule
+from sage.combinat.partition_tuple import PartitionTuples
+from sage.combinat.permutation import Permutations
+from sage.combinat.tableau_tuple import StandardTableauTuples
+
+
+class SpechtModule(CombinatorialFreeModule):
+ r"""
+ Specht module of the Ariki-Koike algebra.
+
+ Let `H_{r,n}(q, u)` be the Ariki-Koike algebra with parameters `q`
+ and `u = (u_1, \ldots, u_r)` (note our indexing convention for
+ the `u` parameters differs from
+ :mod:`sage.algebras.hecke_algebras.ariki_koike_algebra`) over a
+ commutative ring `R`. Let `\lambda` be a partition tuple of level
+ `r` and size `n`. The *Specht module* of shape `\lambda` is the (right)
+ `H_{r,n}(q,u)`-representation `S^{\lambda}` given as free `R`-module
+ with basis given by the standard tableau (tuples) of shape `\lambda`.
+
+ We will now describe the right action of the Ariki-Koike algebra,
+ but we first need to set some notation and definitions.
+ Let `t` be a standard tableau tuple of level `r` and size `n`.
+ Define the *residue* of `i` in `t` to be `r_t(i) = q^{c-r} u_k`,
+ where `i` is in cell `(r, c)` of the `k`-th tableau.
+
+ The action of `L_i` is given by `t \cdot L_i = r_T(i) t`. For `T_i`,
+ we need to consider the following cases. If `i, i+1` are in the same
+ row (resp. column), then `t \cdot T_i = q t` (resp. `t \cdot T_i = -t`).
+ Otherwise if we swap `i, i+1`, the resulting tableau tuple `s` is again
+ standard and the action is given by
+
+ .. MATH::
+
+ t \cdot T_i = \frac{(q - 1) r_t(i)}{r_s(i) - r_t(i)} t
+ + \frac{q r_t(i) - r_s(i)}{r_s(i) - r_t(i)} s.
+
+ Note that `r_s(i) = r_t(i+1)`.
+
+ Over a field of characteristic `0`, the set of Specht modules for all
+ partition tuples of level `r` and size `n` form the complete set
+ of irreducible modules for `H_{r,n}(q, u)` [AK1994]_. (The condition
+ on the base ring can be weakened; see Theorem 3.2 of [Mathas2002]_.)
+
+ EXAMPLES:
+
+ We construct the Specht module `S^{(2,1,21)}` for `H_{3,6}(q, u)` with
+ generic parameters `q, u` over `\GF(3)` and perform some basic
+ computations. We change the tableaux to use the compact representation
+ to condense the output::
+
+ sage: TableauTuples.options.display = 'compact'
+
+ sage: R = PolynomialRing(GF(3), 'u', 3)
+ sage: u = R.gens()
+ sage: q = R['q'].gen()
+ sage: H = algebras.ArikiKoike(3, 6, q, u, use_fraction_field=True)
+ sage: LT = H.LT()
+ sage: T0, T1, T2, T3, T4, T5 = LT.T()
+ sage: S = H.specht_module([[2], [1], [2,1]])
+ sage: S.dimension()
+ 120
+ sage: elt = S.an_element(); elt
+ S[1,2|3|4,5/6] - S[1,3|2|4,5/6] + S[1,3|4|2,5/6]
+ sage: elt * LT.L(3)
+ u1*S[1,2|3|4,5/6] + (-u0*q)*S[1,3|2|4,5/6] + u0*q*S[1,3|4|2,5/6]
+ sage: elt * T2
+ (((-u0-u1)*q-u1)/(-u0*q+u1))*S[1,2|3|4,5/6]
+ + (((-u0+u2)*q)/(u0*q-u2))*S[1,2|4|3,5/6]
+ + ((-u0*q^2-u0*q-u1)/(-u0*q+u1))*S[1,3|2|4,5/6]
+ + ((u0*q^2-u0*q)/(u0*q-u2))*S[1,3|4|2,5/6]
+ sage: (elt * T3) * T2 == elt * (T3 * T2)
+ True
+ sage: elt * T2 * T3 * T2 == elt * T3 * T2 * T3
+ True
+ sage: elt * T0 * T1 * T0 * T1 == elt * T1 * T0 * T1 * T0
+ True
+ sage: elt * T2 * T5 == elt * T5 * T2
+ True
+
+ sage: TableauTuples.options._reset()
+
+ REFERENCES:
+
+ - [AK1994]_
+ - [DJM1998]_
+ - [DR2001]_
+ - [Mathas2002]_
+ - [Mathas2004]_
+ """
+ @staticmethod
+ def __classcall_private__(cls, AK, la):
+ """
+ Normalize input to ensure a unique representation.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 6)
+ sage: S1 = AK.specht_module([[3], [1], [1,1]])
+ sage: S2 = AK.specht_module(PartitionTuple([[3], [1], [1,1]]))
+ sage: S1 is S2
+ True
+ """
+ la = PartitionTuples(AK._r, AK._n)(la)
+ return super().__classcall__(cls, AK, la)
+
+ def __init__(self, AK, la):
+ r"""
+ Initialize ``self``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 6, use_fraction_field=True)
+ sage: S = AK.specht_module([[3], [1], [1,1]])
+ sage: TestSuite(S).run() # long time
+ sage: Sp = AK.specht_module([[], [2,1,1], [2]])
+ sage: TestSuite(Sp).run() # long time
+ """
+ self._shape = la
+ self._AK = AK
+ self._q = AK.q()
+ self._u = AK.u()
+ self._Pn = Permutations(la.size())
+ indices = StandardTableauTuples(la)
+ R = AK.base_ring()
+ cat = Modules(R).FiniteDimensional().WithBasis()
+ CombinatorialFreeModule.__init__(self, R, indices, category=cat, prefix='S')
+
+ def _repr_(self):
+ r"""
+ Return a string representation of ``self``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 8)
+ sage: AK.specht_module([[3], [], [2,2,1]])
+ Specht module of shape ([3], [], [2, 2, 1]) for
+ Ariki-Koike algebra of rank 3 and order 8 with q=q and u=(u0, u1, u2)
+ over ... over Integer Ring
+ """
+ return "Specht module of shape {} for {}".format(self._shape, self._AK)
+
+ def _latex_(self):
+ r"""
+ Return a latex representation of ``self``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 8)
+ sage: S = AK.specht_module([[3], [], [2,2,1]])
+ sage: latex(S)
+ S^{{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
+ \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{1-3}
+ \lr{\phantom{x}}&\lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-3}
+ \end{array}$},\emptyset,\raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
+ \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
+ \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
+ \lr{\phantom{x}}\\\cline{1-1}
+ \end{array}$}
+ }}_{\mathcal{H}_{3,8}(q)}
+ """
+ return "S^{{{}}}_{{{}}}".format(latex(self._shape), latex(self._AK))
+
+ def _test_representation(self, **options):
+ r"""
+ Test that the relations of the Ariki-Koike algebra are satisfied.
+
+ EXAMPLES::
+
+ sage: q = ZZ['q'].fraction_field().gen()
+ sage: AK = algebras.ArikiKoike(2, 4, q, [q^2+1, q-3], q.parent())
+ sage: S = AK.specht_module([[2,1], [1]])
+ sage: S._test_representation(elements=S.basis())
+ """
+ tester = self._tester(**options)
+ n = self._shape.size()
+ q = self._q
+ from sage.misc.misc import some_tuples
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
+
+ # Build the polynomial for testing the T0 action
+ z = PolynomialRing(self.base_ring(), 'DUMMY').gen()
+ T0_poly = -prod(z - val for val in self._u)
+
+ def apply_T0_power(b, exp):
+ for i in range(exp):
+ b = b.T(0)
+ return b
+
+ AKelts = self._AK.some_elements()
+ for b in tester.some_elements():
+ t0 = self.linear_combination((apply_T0_power(b, exp), c)
+ for exp, c in enumerate(T0_poly))
+ tester.assertEqual(t0, self.zero())
+
+ tester.assertEqual(b.T([0, 1, 0, 1]), b.T([1, 0, 1, 0]))
+ tester.assertEqual(b.T(1).T(1), (q-1)*b.T(1) + q*b)
+ for i in range(2, n):
+ tester.assertEqual(b.T(i).T(i), (q-1)*b.T(i) + q*b)
+ tester.assertEqual(b.T(i).T(0), b.T(0).T(i))
+ if i < n - 1:
+ tester.assertEqual(b.T([i, i+1, i]), b.T([i+1, i, i+1]))
+ for j in range(i+2, n):
+ tester.assertEqual(b.T([i, j]), b.T([j, i]))
+
+ for (x, y) in some_tuples(AKelts, 2, tester._max_runs):
+ tester.assertEqual(b*(x*y), (b*x)*y)
+
+ def _L_on_basis(self, i, t):
+ """
+ Return the action of `L_i` on the basis element indexed by
+ the standard tableau tuple ``t``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 10)
+ sage: S = AK.specht_module([[2,1], [], [3,2,2]])
+ sage: P = S.basis().keys()
+ sage: t = P([[[2,4],[8]], [], [[1,3,7],[5,6],[9,10]]])
+ sage: S._L_on_basis(1, t)
+ u2*S[([[2, 4], [8]], [], [[1, 3, 7], [5, 6], [9, 10]])]
+ sage: S._L_on_basis(4, t)
+ u0*q*S[([[2, 4], [8]], [], [[1, 3, 7], [5, 6], [9, 10]])]
+ sage: S._L_on_basis(6, t)
+ u2*S[([[2, 4], [8]], [], [[1, 3, 7], [5, 6], [9, 10]])]
+ sage: S._L_on_basis(8, t)
+ (u0*q^-1)*S[([[2, 4], [8]], [], [[1, 3, 7], [5, 6], [9, 10]])]
+ sage: S._L_on_basis(9, t)
+ (u2*q^-2)*S[([[2, 4], [8]], [], [[1, 3, 7], [5, 6], [9, 10]])]
+ """
+ c = t.cells_containing(i)[0]
+ if len(c) == 2: # it is of level 1 and a regular tableau
+ c = (0,) + c
+ res = self._q**(c[2]-c[1]) * self._u[c[0]]
+ R = self.base_ring()
+ return self.element_class(self, {t: R(res)})
+
+ def _T_on_basis(self, i, t):
+ r"""
+ Return the action of `T_i` on the basis element indexed by
+ the standard tableau tuple ``t``.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 10, use_fraction_field=True)
+ sage: S = AK.specht_module([[2,1], [], [3,2,2]])
+ sage: P = S.basis().keys()
+ sage: t = P([[[2,4],[8]], [], [[1,5,7],[3,6],[9,10]]])
+ sage: S._T_on_basis(0, t) == S._L_on_basis(1, t)
+ True
+ sage: S._T_on_basis(1, t)
+ ((u2*q-u0)/(u0-u2))*S[([[1, 4], [8]], [], [[2, 5, 7], [3, 6], [9, 10]])]
+ + ((u0*q-u0)/(u0-u2))*S[([[2, 4], [8]], [], [[1, 5, 7], [3, 6], [9, 10]])]
+ sage: S._T_on_basis(2, t)
+ ((u2*q-u2)/(-u0*q+u2))*S[([[2, 4], [8]], [], [[1, 5, 7], [3, 6], [9, 10]])]
+ + ((u0*q^2-u2)/(-u0*q+u2))*S[([[3, 4], [8]], [], [[1, 5, 7], [2, 6], [9, 10]])]
+ sage: S._T_on_basis(5, t)
+ -S[([[2, 4], [8]], [], [[1, 5, 7], [3, 6], [9, 10]])]
+ sage: S._T_on_basis(7, t)
+ ((u2*q^4-u0)/(-u2*q^3+u0))*S[([[2, 4], [7]], [], [[1, 5, 8], [3, 6], [9, 10]])]
+ + ((u0*q-u0)/(-u2*q^3+u0))*S[([[2, 4], [8]], [], [[1, 5, 7], [3, 6], [9, 10]])]
+ sage: S._T_on_basis(9, t)
+ q*S[([[2, 4], [8]], [], [[1, 5, 7], [3, 6], [9, 10]])]
+ """
+ R = self.base_ring()
+ if i == 0:
+ return self._L_on_basis(1, t)
+
+ ct = t.cells_containing(i)[0]
+ cs = t.cells_containing(i+1)[0]
+ if len(ct) == 2: # it is of level 1 and a regular tableau
+ ct = (0,) + ct
+ cs = (0,) + cs
+
+ if ct[0] == cs[0] and ct[2] == cs[2]: # same column
+ return self.element_class(self, {t: -R.one()})
+
+ if ct[0] == cs[0] and ct[1] == cs[1]: # same row
+ return self.element_class(self, {t: self._q})
+
+ # result is standard
+ s = t.symmetric_group_action_on_entries(self._Pn.simple_reflection(i))
+ assert s.parent() is t.parent()
+
+ def res(cell):
+ return self._q**(cell[2]-cell[1]) * self._u[cell[0]]
+
+ # Note that the residue of i in t is given by the cell c
+ # and of i in s corresponds to cell cp because the
+ # corresponding action of the permutation on t.
+ one = self.base_ring().one()
+ denom = res(cs) - res(ct)
+ coefft = (self._q - one) * res(cs) / denom
+ coeffs = (self._q * res(ct) - res(cs)) / denom
+ return self.element_class(self, {t: R(coefft), s: R(coeffs)})
+
+ def ariki_koike_algebra(self):
+ r"""
+ Return the Ariki-Koike algebra that ``self`` is a representation of.
+
+ EXAMPLES::
+
+ sage: AK = algebras.ArikiKoike(3, 6)
+ sage: S = AK.specht_module([[2], [], [3,1]])
+ sage: S.ariki_koike_algebra() is AK
+ True
+ """
+ return self._AK
+
+ class Element(CombinatorialFreeModule.Element):
+ def _acted_upon_(self, scalar, self_on_left):
+ r"""
+ Return the action of ``scalar`` on ``self``.
+
+ EXAMPLES::
+
+ sage: TableauTuples.options.display = 'compact'
+ sage: AK = algebras.ArikiKoike(4, 6, use_fraction_field=True)
+ sage: q = AK.q()
+ sage: LT = AK.LT()
+ sage: T = AK.T()
+ sage: S = AK.specht_module([[], [2], [1], [2,1]])
+ sage: elt = S.an_element()
+ sage: 5 * elt
+ 5*S[-|1,2|3|4,5/6] + 10*S[-|1,3|2|4,5/6] + 5*S[-|1,3|4|2,5/6]
+ + 15*S[-|2,3|1|4,5/6]
+ sage: elt * (q - 2)
+ (q-2)*S[-|1,2|3|4,5/6] + (2*q-4)*S[-|1,3|2|4,5/6]
+ + (q-2)*S[-|1,3|4|2,5/6] + (3*q-6)*S[-|2,3|1|4,5/6]
+ sage: elt * LT.an_element() == elt * T(LT.an_element())
+ True
+ sage: T.an_element() * elt
+ Traceback (most recent call last):
+ ...
+ TypeError: unsupported operand parent(s) for *: 'Ariki-Koike algebra ... over Integer Ring'
+ sage: TableauTuples.options._reset()
+
+ TESTS::
+
+ sage: AK = algebras.ArikiKoike(2, 4, use_fraction_field=True)
+ sage: LT = AK.LT()
+ sage: T = AK.T()
+ sage: S = AK.specht_module([[1], [2,1]])
+ sage: B = list(LT.basis())[::55]
+ sage: all(b * x == b * T(x) for b in S.basis() for x in B) # long time
+ True
+ """
+ ret = super()._acted_upon_(scalar, self_on_left)
+ if ret is not None:
+ return ret
+ if not self_on_left: # only a right action
+ return None
+ P = self.parent()
+ if scalar not in P._AK:
+ return None
+ scalar = P._AK(scalar)
+ if scalar.parent() is P._AK.LT():
+ return P.linear_combination((self.L(sum(([i]*val for i, val in enumerate(m[0], start=1)), [])).T(m[1].reduced_word()), c)
+ for m, c in scalar)
+ elif scalar.parent() is P._AK.T():
+ AKT = P._AK.T()
+ return P.linear_combination((self.T(AKT._basis_to_word(m)), c)
+ for m, c in scalar)
+ return self * P._AK.LT()(scalar)
+
+ def L(self, i):
+ r"""
+ Return the (right) action of `L_i` on ``self``.
+
+ INPUT:
+
+ - ``i`` -- an integer or a list of integers
+
+ EXAMPLES::
+
+ sage: TableauTuples.options.display = 'compact' # compact tableau printing
+ sage: AK = algebras.ArikiKoike(3, 6, use_fraction_field=True)
+ sage: S = AK.specht_module([[2], [], [3,1]])
+ sage: elt = S.an_element(); elt
+ S[1,2|-|3,4,5/6] + 2*S[1,3|-|2,4,5/6]
+ + 3*S[2,3|-|1,4,5/6] + S[2,4|-|1,3,5/6]
+ sage: elt.L(1)
+ u0*S[1,2|-|3,4,5/6] + 2*u0*S[1,3|-|2,4,5/6]
+ + 3*u2*S[2,3|-|1,4,5/6] + u2*S[2,4|-|1,3,5/6]
+ sage: elt.L(2)
+ u0*q*S[1,2|-|3,4,5/6] + 2*u2*S[1,3|-|2,4,5/6]
+ + 3*u0*S[2,3|-|1,4,5/6] + u0*S[2,4|-|1,3,5/6]
+ sage: elt.L(6)
+ u2/q*S[1,2|-|3,4,5/6] + 2*u2/q*S[1,3|-|2,4,5/6]
+ + 3*u2/q*S[2,3|-|1,4,5/6] + u2/q*S[2,4|-|1,3,5/6]
+ sage: elt.L([3,3,3])
+ u2^3*S[1,2|-|3,4,5/6] + 2*u0^3*q^3*S[1,3|-|2,4,5/6]
+ + 3*u0^3*q^3*S[2,3|-|1,4,5/6] + u2^3*q^3*S[2,4|-|1,3,5/6]
+ sage: LT = AK.LT()
+ sage: elt.L([3,3,3]) == elt * (LT.L(3)^3)
+ True
+ sage: TableauTuples.options._reset() # reset
+ """
+ if not self: # action on 0 is 0
+ return self
+ if i not in ZZ:
+ ret = self
+ for val in i:
+ ret = ret.L(val)
+ return ret
+ P = self.parent()
+ return P.linear_combination((P._L_on_basis(i, t), c) for t, c in self)
+
+ def T(self, i):
+ r"""
+ Return the (right) action of `T_i` on ``self``.
+
+ INPUT:
+
+ - ``i`` -- an integer or a list of integers
+
+ EXAMPLES::
+
+ sage: TableauTuples.options.display = 'compact' # compact tableau printing
+ sage: AK = algebras.ArikiKoike(3, 10, use_fraction_field=True)
+ sage: q = AK.q()
+ sage: S = AK.specht_module([[2,1], [], [3,2,2]])
+ sage: P = S.basis().keys()
+ sage: t = P([[[2,4],[8]], [], [[1,5,7],[3,6],[9,10]]])
+ sage: b = S.basis()[t]
+ sage: b.T(2)
+ ((u2*q-u2)/(-u0*q+u2))*S[2,4/8|-|1,5,7/3,6/9,10]
+ + ((u0*q^2-u2)/(-u0*q+u2))*S[3,4/8|-|1,5,7/2,6/9,10]
+ sage: b.T(6)
+ ((-q)/(q+1))*S[2,4/8|-|1,5,6/3,7/9,10]
+ + (q^2/(q+1))*S[2,4/8|-|1,5,7/3,6/9,10]
+ sage: b.T([2,1,2]) == b.T([1,2,1])
+ True
+ sage: b.T(9)
+ q*S[2,4/8|-|1,5,7/3,6/9,10]
+ sage: all(b.T([i,i]) == (q-1)*b.T(i) + q*b for i in range(1,10))
+ True
+ sage: b.T(0)
+ u2*S[2,4/8|-|1,5,7/3,6/9,10]
+ sage: b.T([0,1,0,1]) == b.T([1,0,1,0])
+ True
+ sage: TableauTuples.options._reset() # reset
+ """
+ if not self: # action on 0 is 0
+ return self
+ if i not in ZZ:
+ ret = self
+ for val in i:
+ ret = ret.T(val)
+ return ret
+ P = self.parent()
+ return P.linear_combination((P._T_on_basis(i, t), c) for t, c in self)
diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py
index 885ab854170..93e22abd6fd 100644
--- a/src/sage/algebras/quatalg/quaternion_algebra.py
+++ b/src/sage/algebras/quatalg/quaternion_algebra.py
@@ -51,7 +51,7 @@
from sage.rings.rational import Rational
from sage.rings.finite_rings.finite_field_constructor import GF
from sage.rings.ideal import Ideal_fractional
-from sage.rings.rational_field import is_RationalField, QQ
+from sage.rings.rational_field import RationalField, QQ
from sage.rings.infinity import infinity
from sage.rings.number_field.number_field_base import NumberField
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
@@ -429,7 +429,7 @@ def is_division_algebra(self) -> bool:
...
NotImplementedError: base field must be rational numbers
"""
- if not is_RationalField(self.base_ring()):
+ if not isinstance(self.base_ring(), RationalField):
raise NotImplementedError("base field must be rational numbers")
return self.discriminant() != 1
@@ -453,7 +453,7 @@ def is_matrix_ring(self) -> bool:
NotImplementedError: base field must be rational numbers
"""
- if not is_RationalField(self.base_ring()):
+ if not isinstance(self.base_ring(), RationalField):
raise NotImplementedError("base field must be rational numbers")
return self.discriminant() == 1
@@ -678,7 +678,7 @@ def __init__(self, base_ring, a, b, names='i,j,k'):
Parent.__init__(self, base=base_ring, names=names, category=cat)
self._a = a
self._b = b
- if is_RationalField(base_ring) and a.denominator() == 1 == b.denominator():
+ if isinstance(base_ring, RationalField) and a.denominator() == 1 == b.denominator():
self.Element = QuaternionAlgebraElement_rational_field
elif (isinstance(base_ring, NumberField) and base_ring.degree() > 2 and base_ring.is_absolute() and
a.denominator() == 1 == b.denominator() and base_ring.defining_polynomial().is_monic()):
@@ -1066,7 +1066,7 @@ def is_definite(self):
...
ValueError: base field must be rational numbers
"""
- if not is_RationalField(self.base_ring()):
+ if not isinstance(self.base_ring(), RationalField):
raise ValueError("base field must be rational numbers")
a, b = self.invariants()
return a < 0 and b < 0
@@ -1218,7 +1218,7 @@ def discriminant(self):
sage: QuaternionAlgebra(QQ[sqrt(2)], 3, 19).discriminant() # needs sage.symbolic
Fractional ideal (1)
"""
- if not is_RationalField(self.base_ring()):
+ if not isinstance(self.base_ring(), RationalField):
try:
F = self.base_ring()
return F.hilbert_conductor(self._a, self._b)
@@ -1245,7 +1245,7 @@ def ramified_primes(self):
sage: QuaternionAlgebra(QQ, -58, -69).ramified_primes()
[3, 23, 29]
"""
- if not is_RationalField(self.base_ring()):
+ if not isinstance(self.base_ring(), RationalField):
raise ValueError("base field must be the rational numbers")
a, b = self._a, self._b
@@ -2517,7 +2517,7 @@ def attempt_isomorphism(self, other):
if other.quaternion_algebra() != Q:
raise TypeError('not an order in the same quaternion algebra')
- if not is_RationalField(Q.base_ring()):
+ if not isinstance(Q.base_ring(), RationalField):
raise NotImplementedError('only implemented for orders in a rational quaternion algebra')
if not Q.is_definite():
raise NotImplementedError('only implemented for definite quaternion orders')
diff --git a/src/sage/arith/functions.pyx b/src/sage/arith/functions.pyx
index 6e8f3db88a5..92dbc709897 100644
--- a/src/sage/arith/functions.pyx
+++ b/src/sage/arith/functions.pyx
@@ -39,17 +39,17 @@ def lcm(a, b=None):
EXAMPLES::
- sage: lcm(97,100)
+ sage: lcm(97, 100)
9700
- sage: LCM(97,100)
+ sage: LCM(97, 100)
9700
- sage: LCM(0,2)
+ sage: LCM(0, 2)
0
- sage: LCM(-3,-5)
+ sage: LCM(-3, -5)
15
sage: LCM([1,2,3,4,5])
60
- sage: v = LCM(range(1,10000)) # *very* fast!
+ sage: v = LCM(range(1, 10000)) # *very* fast!
sage: len(str(v))
4349
diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py
index 310f2b0b189..28f81d7b798 100644
--- a/src/sage/arith/misc.py
+++ b/src/sage/arith/misc.py
@@ -3748,9 +3748,9 @@ def binomial(x, m, **kwds):
Some floating point cases -- see :issue:`7562`, :issue:`9633`, and
:issue:`12448`::
- sage: binomial(1., 3)
+ sage: binomial(1., 3) # needs sage.rings.real_mpfr
0.000000000000000
- sage: binomial(-2., 3)
+ sage: binomial(-2., 3) # needs sage.rings.real_mpfr
-4.00000000000000
sage: binomial(0.5r, 5)
0.02734375
diff --git a/src/sage/arith/srange.pyx b/src/sage/arith/srange.pyx
index 59c39d8fc2a..51855f9646d 100644
--- a/src/sage/arith/srange.pyx
+++ b/src/sage/arith/srange.pyx
@@ -234,16 +234,21 @@ def srange(*args, **kwds):
sage: srange(1, 10, 1/2)
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]
+
+ sage: # needs sage.rings.real_mpfr
sage: srange(1, 5, 0.5)
- [1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000, 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
+ [1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
+ 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
sage: srange(0, 1, 0.4)
[0.000000000000000, 0.400000000000000, 0.800000000000000]
sage: srange(1.0, 5.0, include_endpoint=True)
- [1.00000000000000, 2.00000000000000, 3.00000000000000, 4.00000000000000, 5.00000000000000]
+ [1.00000000000000, 2.00000000000000, 3.00000000000000, 4.00000000000000,
+ 5.00000000000000]
sage: srange(1.0, 1.1)
[1.00000000000000]
sage: srange(1.0, 1.0)
[]
+
sage: V = VectorSpace(QQ, 2) # needs sage.modules
sage: srange(V([0,0]), V([5,5]), step=V([2,2])) # needs sage.modules
[(0, 0), (2, 2), (4, 4)]
@@ -264,7 +269,8 @@ def srange(*args, **kwds):
sage: srange(0.5, 0.9, 0.1, universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999]
sage: srange(0, 1.1, 0.1, universe=RDF, include_endpoint=True)
- [0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999, 1.1]
+ [0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7,
+ 0.7999999999999999, 0.8999999999999999, 0.9999999999999999, 1.1]
sage: srange(0, 0.2, 0.1, universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2]
sage: srange(0, 0.3, 0.1, universe=RDF, include_endpoint=True)
@@ -275,9 +281,10 @@ def srange(*args, **kwds):
sage: Q = RationalField()
sage: srange(1, 10, Q('1/2'))
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]
- sage: srange(1, 5, 0.5)
- [1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000, 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
- sage: srange(0, 1, 0.4)
+ sage: srange(1, 5, 0.5) # needs sage.rings.real_mpfr
+ [1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
+ 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
+ sage: srange(0, 1, 0.4) # needs sage.rings.real_mpfr
[0.000000000000000, 0.400000000000000, 0.800000000000000]
Negative steps are also allowed::
@@ -512,7 +519,7 @@ def ellipsis_range(*args, step=None):
Examples in which the step determines the parent of the elements::
- sage: [1..3, step=0.5]
+ sage: [1..3, step=0.5] # needs sage.rings.real_mpfr
[1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000, 3.00000000000000]
sage: v = [1..5, step=1/1]; v
[1, 2, 3, 4, 5]
diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx
index 446c3f5ee33..d907eedb9e8 100644
--- a/src/sage/categories/category_singleton.pyx
+++ b/src/sage/categories/category_singleton.pyx
@@ -219,13 +219,14 @@ class Category_singleton(Category):
,
,
,
+ ,
,
,
,
,
,
,
- <... 'object'>]
+ ]
sage: R() is R()
True
sage: R() is R().__class__()
diff --git a/src/sage/categories/chain_complexes.py b/src/sage/categories/chain_complexes.py
index 640285f1633..6e6448f3d38 100644
--- a/src/sage/categories/chain_complexes.py
+++ b/src/sage/categories/chain_complexes.py
@@ -81,8 +81,8 @@ def homology(self, n=None):
::
sage: # needs sage.combinat sage.modules
- sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3))
- sage: C = A.cdg_algebra({z: x*y})
+ sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.libs.singular
+ sage: C = A.cdg_algebra({z: x*y}) # needs sage.libs.singular
sage: C.homology(0)
Free module generated by {[1]} over Rational Field
sage: C.homology(1)
@@ -110,8 +110,8 @@ def differential(self, *args, **kwargs):
::
- sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.modules
- sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.modules
+ sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.libs.singular sage.modules
+ sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.libs.singular sage.modules
sage: C.differential() # needs sage.combinat sage.modules
Differential of Commutative Differential Graded Algebra with
generators ('x', 'y', 'z') in degrees (2, 2, 3) over Rational Field
@@ -183,8 +183,8 @@ class HomologyFunctor(Functor):
::
- sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.modules
- sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.modules
+ sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.libs.singular sage.modules
+ sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.libs.singular sage.modules
sage: H = HomologyFunctor(ChainComplexes(QQ), 2)
sage: H(C) # needs sage.combinat sage.modules
Free module generated by {[x], [y]} over Rational Field
diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py
index 8b9e20ad03e..25261db6645 100644
--- a/src/sage/categories/coxeter_groups.py
+++ b/src/sage/categories/coxeter_groups.py
@@ -937,22 +937,27 @@ def simple_projections(self, side='right', length_increasing=True):
from sage.sets.family import Family
return Family(self.index_set(), lambda i: self.simple_projection(i, side=side, length_increasing=length_increasing))
- def sign_representation(self, base_ring=None, side="twosided"):
+ def sign_representation(self, base_ring=None):
r"""
Return the sign representation of ``self`` over ``base_ring``.
INPUT:
- ``base_ring`` -- (optional) the base ring; the default is `\ZZ`
- - ``side`` -- ignored
EXAMPLES::
- sage: W = WeylGroup(["A", 1, 1]) # needs sage.combinat sage.groups
- sage: W.sign_representation() # needs sage.combinat sage.groups
+ sage: W = WeylGroup(['D', 4]) # needs sage.combinat sage.groups
+ sage: W.sign_representation(QQ) # needs sage.combinat sage.groups
Sign representation of
- Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space)
- over Integer Ring
+ Weyl Group of type ['D', 4] (as a matrix group acting on the ambient space)
+ over Rational Field
+
+ sage: # optional - gap3
+ sage: W = CoxeterGroup(['B',3], implementation="coxeter3")
+ sage: W.sign_representation()
+ Sign representation of Coxeter group of type ['B', 3]
+ implemented by Coxeter3 over Integer Ring
"""
if base_ring is None:
from sage.rings.integer_ring import ZZ
diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py
index 14dfce40c03..b8a3f9c8e21 100644
--- a/src/sage/categories/examples/lie_algebras.py
+++ b/src/sage/categories/examples/lie_algebras.py
@@ -71,7 +71,7 @@ def __classcall_private__(cls, gens):
EXAMPLES::
- sage: # needs sage.combinat
+ sage: # needs sage.combinat sage.groups
sage: S3 = SymmetricGroupAlgebra(QQ, 3)
sage: L1 = LieAlgebras(QQ).example()
sage: gens = list(S3.algebra_generators())
@@ -85,8 +85,8 @@ def __init__(self, gens):
"""
EXAMPLES::
- sage: L = LieAlgebras(QQ).example() # needs sage.combinat
- sage: TestSuite(L).run() # needs sage.combinat
+ sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups
+ sage: TestSuite(L).run() # needs sage.combinat sage.groups
"""
if not gens:
raise ValueError("need at least one generator")
diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py
index a7474d07602..1a069f4d5e9 100644
--- a/src/sage/categories/fields.py
+++ b/src/sage/categories/fields.py
@@ -99,25 +99,31 @@ def __contains__(self, x):
in other doctests, we introduced a strong reference to all previously created
uncollected objects in :issue:`19244`. ::
+ sage: # needs sage.libs.pari
sage: import gc
sage: _ = gc.collect()
- sage: permstore = [X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]
+ sage: permstore = [X for X in gc.get_objects()
+ ....: if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]
sage: n = len(permstore)
- sage: for i in prime_range(100): # needs sage.libs.pari
+ sage: for i in prime_range(100):
....: R = ZZ.quotient(i)
....: t = R in Fields()
First, we show that there are now more quotient rings in cache than before::
- sage: len([X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]) > n
+ sage: # needs sage.libs.pari
+ sage: len([X for X in gc.get_objects()
+ ....: if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]) > n
True
When we delete the last quotient ring created in the loop and then do a garbage
collection, all newly created rings vanish::
+ sage: # needs sage.libs.pari
sage: del R
sage: _ = gc.collect()
- sage: len([X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]) - n
+ sage: len([X for X in gc.get_objects()
+ ....: if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]) - n
0
"""
@@ -624,15 +630,15 @@ def gcd(self,other):
For field of characteristic zero, the gcd of integers is considered
as if they were elements of the integer ring::
- sage: gcd(15.0,12.0)
+ sage: gcd(15.0,12.0) # needs sage.rings.real_mpfr
3.00000000000000
But for other floating point numbers, the gcd is just `0.0` or `1.0`::
- sage: gcd(3.2, 2.18)
+ sage: gcd(3.2, 2.18) # needs sage.rings.real_mpfr
1.00000000000000
- sage: gcd(0.0, 0.0)
+ sage: gcd(0.0, 0.0) # needs sage.rings.real_mpfr
0.000000000000000
AUTHOR:
@@ -678,15 +684,15 @@ def lcm(self, other):
For field of characteristic zero, the lcm of integers is considered
as if they were elements of the integer ring::
- sage: lcm(15.0,12.0)
+ sage: lcm(15.0, 12.0) # needs sage.rings.real_mpfr
60.0000000000000
But for others floating point numbers, it is just `0.0` or `1.0`::
- sage: lcm(3.2, 2.18)
+ sage: lcm(3.2, 2.18) # needs sage.rings.real_mpfr
1.00000000000000
- sage: lcm(0.0, 0.0)
+ sage: lcm(0.0, 0.0) # needs sage.rings.real_mpfr
0.000000000000000
AUTHOR:
@@ -748,13 +754,13 @@ def xgcd(self, other):
the result is a floating point version of the standard gcd on
`\ZZ`::
- sage: xgcd(12.0, 8.0)
+ sage: xgcd(12.0, 8.0) # needs sage.rings.real_mpfr
(4.00000000000000, 1.00000000000000, -1.00000000000000)
- sage: xgcd(3.1, 2.98714)
+ sage: xgcd(3.1, 2.98714) # needs sage.rings.real_mpfr
(1.00000000000000, 0.322580645161290, 0.000000000000000)
- sage: xgcd(0.0, 1.1)
+ sage: xgcd(0.0, 1.1) # needs sage.rings.real_mpfr
(1.00000000000000, 0.000000000000000, 0.909090909090909)
"""
P = self.parent()
@@ -787,7 +793,7 @@ def factor(self):
sage: x = GF(7)(5)
sage: x.factor()
5
- sage: RR(0).factor()
+ sage: RR(0).factor() # needs sage.rings.real_mpfr
Traceback (most recent call last):
...
ArithmeticError: factorization of 0.000000000000000 is not defined
diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py
index a86754c9493..c5566fc0f20 100644
--- a/src/sage/categories/finite_dimensional_modules_with_basis.py
+++ b/src/sage/categories/finite_dimensional_modules_with_basis.py
@@ -686,6 +686,7 @@ def _repr_matrix(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
@@ -714,6 +715,7 @@ def _ascii_art_matrix(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
@@ -745,6 +747,7 @@ def _unicode_art_matrix(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
@@ -910,6 +913,7 @@ def characteristic_polynomial(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: V = ZZ^2; phi = V.hom([V.0 + V.1, 2*V.1])
sage: phi.characteristic_polynomial()
x^2 - 3*x + 2
@@ -919,7 +923,6 @@ def characteristic_polynomial(self):
x^2 - 3*x + 2
sage: phi.charpoly('T')
T^2 - 3*T + 2
-
sage: W = CombinatorialFreeModule(ZZ, ['x', 'y'])
sage: M = matrix(ZZ, [[1, 0], [1, 2]])
sage: psi = W.module_morphism(matrix=M, codomain=W)
@@ -939,12 +942,12 @@ def determinant(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: V = ZZ^2; phi = V.hom([V.0 + V.1, 2*V.1])
sage: phi.determinant()
2
sage: phi.det()
2
-
sage: W = CombinatorialFreeModule(ZZ, ['x', 'y'])
sage: M = matrix(ZZ, [[1, 0], [1, 2]])
sage: psi = W.module_morphism(matrix=M, codomain=W)
@@ -966,12 +969,12 @@ def fcp(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: V = ZZ^2; phi = V.hom([V.0 + V.1, 2*V.1])
sage: phi.fcp() # needs sage.libs.pari
(x - 2) * (x - 1)
sage: phi.fcp('T') # needs sage.libs.pari
(T - 2) * (T - 1)
-
sage: W = CombinatorialFreeModule(ZZ, ['x', 'y'])
sage: M = matrix(ZZ, [[1, 0], [1, 2]])
sage: psi = W.module_morphism(matrix=M, codomain=W)
@@ -995,6 +998,7 @@ def minimal_polynomial(self):
Compute the minimal polynomial, and check it. ::
+ sage: # needs sage.modules
sage: V = GF(7)^3
sage: H = V.Hom(V)([[0,1,2], [-1,0,3], [2,4,1]]); H
Vector space morphism represented by the matrix:
@@ -1015,7 +1019,7 @@ def minimal_polynomial(self):
Domain: Vector space of dimension 3 over Finite Field of size 7
Codomain: Vector space of dimension 3 over Finite Field of size 7
- sage: # needs sage.rings.finite_rings
+ sage: # needs sage.modules sage.rings.finite_rings
sage: k = GF(9, 'c')
sage: V = CombinatorialFreeModule(k, ['x', 'y', 'z', 'w'])
sage: A = matrix(k, 4, [1,1,0,0, 0,1,0,0, 0,0,5,0, 0,0,0,5])
@@ -1038,10 +1042,10 @@ def trace(self):
EXAMPLES::
+ sage: # needs sage.modules
sage: V = ZZ^2; phi = V.hom([V.0 + V.1, 2*V.1])
sage: phi.trace()
3
-
sage: W = CombinatorialFreeModule(ZZ, ['x', 'y'])
sage: M = matrix(ZZ, [[1, 0], [1, 2]])
sage: psi = W.module_morphism(matrix=M, codomain=W)
diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py
index a88a56e96cf..8ef8541bdbf 100644
--- a/src/sage/categories/finite_groups.py
+++ b/src/sage/categories/finite_groups.py
@@ -95,11 +95,11 @@ def cardinality(self):
We need to use a finite group which uses this default
implementation of cardinality::
- sage: G = groups.misc.SemimonomialTransformation(GF(5), 3); G
+ sage: G = groups.misc.SemimonomialTransformation(GF(5), 3); G # needs sage.rings.number_field
Semimonomial transformation group over Finite Field of size 5 of degree 3
- sage: G.cardinality.__module__
+ sage: G.cardinality.__module__ # needs sage.rings.number_field
'sage.categories.finite_groups'
- sage: G.cardinality()
+ sage: G.cardinality() # needs sage.rings.number_field
384
"""
if hasattr(self, 'order'):
@@ -173,7 +173,7 @@ def conjugacy_classes_representatives(self):
EXAMPLES::
sage: G = SymmetricGroup(3)
- sage: G.conjugacy_classes_representatives()
+ sage: G.conjugacy_classes_representatives() # needs sage.combinat
[(), (1,2), (1,2,3)]
"""
return [C.representative() for C in self.conjugacy_classes()]
@@ -232,7 +232,7 @@ def __init_extra__(self):
sage: A in Algebras.Semisimple
False
- sage: G = groups.misc.AdditiveCyclic(4)
+ sage: G = groups.misc.AdditiveCyclic(4) # needs sage.rings.number_field
sage: Cat = CommutativeAdditiveGroups().Finite()
sage: A = G.algebra(GF(5), category=Cat)
sage: A in Algebras.Semisimple
diff --git a/src/sage/categories/functor.pyx b/src/sage/categories/functor.pyx
index 5e3262c8dd3..2ca369c2ef5 100644
--- a/src/sage/categories/functor.pyx
+++ b/src/sage/categories/functor.pyx
@@ -96,15 +96,15 @@ cdef class Functor(SageObject):
Category of rings
sage: F.codomain()
Category of commutative additive groups
- sage: from sage.categories.functor import is_Functor
- sage: is_Functor(F)
+ sage: from sage.categories.functor import Functor
+ sage: isinstance(F, Functor)
True
sage: I = IdentityFunctor(abgrps)
sage: I
The identity functor on Category of commutative additive groups
sage: I.domain()
Category of commutative additive groups
- sage: is_Functor(I)
+ sage: isinstance(I, Functor)
True
Note that by default, an instance of the class Functor is coercion
@@ -422,12 +422,9 @@ cdef class Functor(SageObject):
def is_Functor(x):
"""
- Test whether the argument is a functor
-
- NOTE:
+ Test whether the argument is a functor.
- There is a deprecation warning when using it from top level.
- Therefore we import it in our doc test.
+ This function is deprecated.
EXAMPLES::
@@ -436,6 +433,10 @@ def is_Functor(x):
sage: F1
FractionField
sage: is_Functor(F1)
+ doctest:warning...
+ DeprecationWarning: The function is_Functor is deprecated;
+ use 'isinstance(..., Functor)' instead.
+ See https://github.com/sagemath/sage/issues/38184 for details.
True
sage: is_Functor(FractionField)
False
@@ -446,6 +447,10 @@ def is_Functor(x):
True
"""
+ from sage.misc.superseded import deprecation
+ deprecation(38184,
+ "The function is_Functor is deprecated; "
+ "use 'isinstance(..., Functor)' instead.")
return isinstance(x, Functor)
diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py
index 5c490a6a026..b0700b004de 100644
--- a/src/sage/categories/group_algebras.py
+++ b/src/sage/categories/group_algebras.py
@@ -129,7 +129,7 @@ def __init_extra__(self):
EXAMPLES::
- sage: # needs sage.groups sage.modules
+ sage: # needs sage.combinat sage.groups sage.modules
sage: A = GroupAlgebra(SymmetricGroup(4), QQ)
sage: B = GroupAlgebra(SymmetricGroup(3), ZZ)
sage: A.has_coerce_map_from(B)
@@ -173,7 +173,7 @@ def group(self):
sage: GroupAlgebras(QQ).example(GL(3, GF(11))).group() # needs sage.groups sage.modules
General Linear Group of degree 3 over Finite Field of size 11
- sage: SymmetricGroup(10).algebra(QQ).group() # needs sage.groups sage.modules
+ sage: SymmetricGroup(10).algebra(QQ).group() # needs sage.combinat sage.groups sage.modules
Symmetric group of order 10! as a permutation group
"""
return self.basis().keys()
@@ -201,7 +201,7 @@ def center_basis(self):
EXAMPLES::
- sage: SymmetricGroup(3).algebra(QQ).center_basis() # needs sage.groups sage.modules
+ sage: SymmetricGroup(3).algebra(QQ).center_basis() # needs sage.combinat sage.groups sage.modules
((), (2,3) + (1,2) + (1,3), (1,2,3) + (1,3,2))
.. SEEALSO::
@@ -319,12 +319,12 @@ def is_integral_domain(self, proof=True):
sage: # needs sage.groups sage.modules
sage: S2 = SymmetricGroup(2)
- sage: GroupAlgebra(S2).is_integral_domain()
+ sage: GroupAlgebra(S2).is_integral_domain() # needs sage.combinat
False
sage: S1 = SymmetricGroup(1)
- sage: GroupAlgebra(S1).is_integral_domain()
+ sage: GroupAlgebra(S1).is_integral_domain() # needs sage.combinat
True
- sage: GroupAlgebra(S1, IntegerModRing(4)).is_integral_domain()
+ sage: GroupAlgebra(S1, IntegerModRing(4)).is_integral_domain() # needs sage.combinat
False
sage: GroupAlgebra(AbelianGroup(1)).is_integral_domain()
True
@@ -400,7 +400,7 @@ def central_form(self):
EXAMPLES::
- sage: # needs sage.groups sage.modules
+ sage: # needs sage.combinat sage.groups sage.modules
sage: QS3 = SymmetricGroup(3).algebra(QQ)
sage: A = QS3([2,3,1]) + QS3([3,1,2])
sage: A.central_form()
diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py
index 2ed6590887a..ae0721c0a55 100644
--- a/src/sage/categories/groups.py
+++ b/src/sage/categories/groups.py
@@ -70,7 +70,7 @@ def free(index_set=None, names=None, **kwds):
EXAMPLES::
- sage: # needs sage.groups
+ sage: # needs sage.combinat sage.groups
sage: Groups.free(index_set=ZZ)
Free group indexed by Integer Ring
sage: Groups().free(ZZ)
@@ -273,7 +273,7 @@ def cayley_table(self, names='letters', elements=None):
::
sage: M = SL(2, 2) # needs sage.modules
- sage: M.cayley_table() # needs sage.modules
+ sage: M.cayley_table() # needs sage.libs.gap sage.modules
* a b c d e f
+------------
a| a b c d e f
@@ -477,8 +477,8 @@ def conjugacy_class(self):
)
sage: G = SL(2, GF(2)) # needs sage.modules
- sage: g = G.gens()[0] # needs sage.modules
- sage: g.conjugacy_class() # needs sage.modules
+ sage: g = G.gens()[0] # needs sage.groups sage.modules
+ sage: g.conjugacy_class() # needs sage.groups sage.modules
Conjugacy class of [1 1]
[0 1] in Special Linear Group of degree 2 over Finite Field of size 2
@@ -515,7 +515,7 @@ def free(index_set=None, names=None, **kwds):
EXAMPLES::
- sage: # needs sage.groups
+ sage: # needs sage.combinat sage.groups
sage: Groups.Commutative.free(index_set=ZZ)
Free abelian group indexed by Integer Ring
sage: Groups().Commutative().free(ZZ)
@@ -592,13 +592,13 @@ def group_generators(self):
We check the other portion of :issue:`16718` is fixed::
- sage: len(C.j_classes()) # needs sage.groups
+ sage: len(C.j_classes()) # needs sage.graphs sage.groups
1
An example with an infinitely generated group (a better output
is needed)::
- sage: # needs sage.groups
+ sage: # needs sage.combinat sage.groups
sage: G = Groups.free([1,2])
sage: H = Groups.free(ZZ)
sage: C = cartesian_product([G, H])
@@ -631,17 +631,17 @@ def lift(i, gen):
def order(self):
r"""
- Return the cardinality of self.
+ Return the cardinality of ``self``.
EXAMPLES::
- sage: C = cartesian_product([SymmetricGroup(10), SL(2, GF(3))]) # needs sage.groups sage.rings.finite_rings
- sage: C.order() # needs sage.groups sage.rings.finite_rings
+ sage: C = cartesian_product([SymmetricGroup(10), SL(2, GF(3))]) # needs sage.groups sage.modules
+ sage: C.order() # needs sage.groups sage.modules
87091200
TESTS::
- sage: C.order.__module__ # needs sage.groups sage.rings.finite_rings
+ sage: C.order.__module__ # needs sage.groups sage.modules
'sage.categories.groups'
.. TODO::
diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py
index 38f6364a9f0..23848497247 100644
--- a/src/sage/categories/pushout.py
+++ b/src/sage/categories/pushout.py
@@ -1867,7 +1867,7 @@ def merge(self, other):
LaurentPolynomialFunctor
sage: F1.merge(F2)(LaurentPolynomialRing(GF(2), 'a')) # needs sage.modules
Multivariate Laurent Polynomial Ring in a, t over Finite Field of size 2
- sage: F1.merge(F1)(LaurentPolynomialRing(GF(2), 'a')) # needs sage.modules
+ sage: F1.merge(F1)(LaurentPolynomialRing(GF(2), 'a'))
Univariate Laurent Polynomial Ring in t over
Univariate Laurent Polynomial Ring in a over Finite Field of size 2
@@ -3926,7 +3926,7 @@ def __init__(self, S, action=operator.mul, side='left',
"""
EXAMPLES::
- sage: # needs sage.groups sage.modules
+ sage: # needs sage.combinat sage.groups sage.modules
sage: G = SymmetricGroup(3); G.rename('S3')
sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M')
sage: action = lambda g, x: M.term(g(x))
@@ -3976,14 +3976,20 @@ class BlackBoxConstructionFunctor(ConstructionFunctor):
EXAMPLES::
sage: from sage.categories.pushout import BlackBoxConstructionFunctor
+
+ sage: # needs sage.libs.gap
+ sage: from sage.interfaces.gap import gap
sage: FG = BlackBoxConstructionFunctor(gap)
- sage: FS = BlackBoxConstructionFunctor(singular)
sage: FG
BlackBoxConstructionFunctor
- sage: FG(ZZ) # needs sage.libs.gap
+ sage: FG(ZZ)
Integers
- sage: FG(ZZ).parent() # needs sage.libs.gap
+ sage: FG(ZZ).parent()
Gap
+ sage: FG == loads(dumps(FG))
+ True
+
+ sage: FS = BlackBoxConstructionFunctor(singular)
sage: FS(QQ['t']) # needs sage.libs.singular
polynomial ring, over a field, global ordering
// coefficients: QQ
@@ -3993,8 +3999,6 @@ class BlackBoxConstructionFunctor(ConstructionFunctor):
// block 2 : ordering C
sage: FG == FS # needs sage.libs.gap sage.libs.singular
False
- sage: FG == loads(dumps(FG)) # needs sage.libs.gap
- True
"""
rank = 100
diff --git a/src/sage/categories/quantum_group_representations.py b/src/sage/categories/quantum_group_representations.py
index 23755cc3aef..07dad6d28d6 100644
--- a/src/sage/categories/quantum_group_representations.py
+++ b/src/sage/categories/quantum_group_representations.py
@@ -53,7 +53,7 @@ def example(self):
sage: from sage.categories.quantum_group_representations import QuantumGroupRepresentations
sage: Cat = QuantumGroupRepresentations(ZZ['q'].fraction_field())
- sage: Cat.example() # needs sage.combinat sage.modules
+ sage: Cat.example() # needs sage.combinat sage.graphs sage.modules
V((2, 1, 0))
"""
from sage.algebras.quantum_groups.representations import AdjointRepresentation
@@ -98,7 +98,7 @@ def e_on_basis(self, i, b):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import (
....: MinusculeRepresentation, AdjointRepresentation)
sage: R = ZZ['q'].fraction_field()
@@ -149,7 +149,7 @@ def f_on_basis(self, i, b):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import (
....: MinusculeRepresentation, AdjointRepresentation)
sage: R = ZZ['q'].fraction_field()
@@ -213,7 +213,7 @@ def K_on_basis(self, i, b, power=1):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import (
....: MinusculeRepresentation, AdjointRepresentation)
sage: R = ZZ['q'].fraction_field()
@@ -246,7 +246,7 @@ def tensor(*factors):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import (
....: MinusculeRepresentation, AdjointRepresentation)
sage: R = ZZ['q'].fraction_field()
@@ -285,7 +285,7 @@ def e(self, i):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation
sage: C = crystals.Tableaux(['G',2], shape=[1,1])
sage: R = ZZ['q'].fraction_field()
@@ -312,7 +312,7 @@ def f(self, i):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation
sage: K = crystals.KirillovReshetikhin(['D',4,1], 2,1)
sage: R = ZZ['q'].fraction_field()
@@ -346,7 +346,7 @@ def K(self, i, power=1):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation
sage: K = crystals.KirillovReshetikhin(['D',4,2], 1,1)
sage: R = ZZ['q'].fraction_field()
@@ -397,7 +397,7 @@ def cartan_type(self):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation
sage: C = crystals.Tableaux(['C',2], shape=[1])
sage: R = ZZ['q'].fraction_field()
@@ -417,7 +417,7 @@ def _test_representation(self, tester=None, **options):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import (
....: MinusculeRepresentation, AdjointRepresentation)
sage: C = crystals.Tableaux(['G',2], shape=[1,1])
@@ -428,8 +428,8 @@ def _test_representation(self, tester=None, **options):
We verify that ``C`` does not define a minuscule
representation::
- sage: M = MinusculeRepresentation(R, C) # needs sage.combinat sage.modules
- sage: M._test_representation() # needs sage.combinat sage.modules
+ sage: M = MinusculeRepresentation(R, C) # needs sage.combinat sage.graphs sage.modules
+ sage: M._test_representation() # needs sage.combinat sage.graphs sage.modules
Traceback (most recent call last):
...
AssertionError: [e,f] = (K-K^-1)/(q_i-q_i^-1) -- i: 1 j: 1
@@ -500,7 +500,7 @@ def cartan_type(self):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation
sage: C = crystals.Tableaux(['C',4], shape=[1])
sage: R = ZZ['q'].fraction_field()
@@ -516,7 +516,7 @@ def index_set(self):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation
sage: C = crystals.Tableaux(['C',4], shape=[1])
sage: R = ZZ['q'].fraction_field()
@@ -532,7 +532,7 @@ def q(self):
EXAMPLES::
- sage: # needs sage.combinat sage.modules
+ sage: # needs sage.combinat sage.graphs sage.modules
sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation
sage: C = crystals.Tableaux(['C',4], shape=[1])
sage: R = ZZ['q'].fraction_field()
diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py
index 8699dcf8b43..51eb9b14453 100644
--- a/src/sage/categories/sets_cat.py
+++ b/src/sage/categories/sets_cat.py
@@ -137,6 +137,7 @@ class Sets(Category_singleton):
+
@@ -144,7 +145,7 @@ class Sets(Category_singleton):
- <... 'object'>
+
We run some generic checks on P::
diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py
index e7d0a77fc0c..e714a4571c4 100644
--- a/src/sage/categories/simplicial_sets.py
+++ b/src/sage/categories/simplicial_sets.py
@@ -9,21 +9,20 @@
# https://www.gnu.org/licenses/
# *****************************************************************************
-from sage.functions.generalized import sign
-from sage.matrix.special import identity_matrix
-from sage.misc.cachefunc import cached_method
-from sage.misc.lazy_import import lazy_import
from sage.categories.category_singleton import Category_singleton
from sage.categories.category_with_axiom import CategoryWithAxiom
-from sage.categories.sets_cat import Sets
from sage.categories.homsets import HomsetsCategory
-from sage.matrix.constructor import matrix
+from sage.categories.sets_cat import Sets
+from sage.functions.generalized import sign
+from sage.misc.cachefunc import cached_method
+from sage.misc.lazy_import import lazy_import
from sage.misc.misc_c import prod
from sage.rings.infinity import Infinity
from sage.rings.integer import Integer
from sage.rings.integer_ring import ZZ
lazy_import('sage.matrix.constructor', 'matrix')
+lazy_import('sage.matrix.special', 'identity_matrix')
class SimplicialSets(Category_singleton):
@@ -362,10 +361,10 @@ def _universal_cover_dict(self):
TESTS::
- sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups
- sage: RP2._universal_cover_dict() # needs sage.groups
+ sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.graphs sage.groups
+ sage: RP2._universal_cover_dict() # needs sage.graphs sage.groups
(Finitely presented group < e | e^2 >, {f: e})
- sage: RP2.nondegenerate_simplices() # needs sage.groups
+ sage: RP2.nondegenerate_simplices() # needs sage.graphs sage.groups
[1, f, f * f]
"""
from sage.groups.free_group import FreeGroup
@@ -407,14 +406,14 @@ def universal_cover_map(self):
EXAMPLES::
- sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups
- sage: phi = RP2.universal_cover_map(); phi # needs sage.groups
+ sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.graphs sage.groups
+ sage: phi = RP2.universal_cover_map(); phi # needs sage.graphs sage.groups
Simplicial set morphism:
From: Simplicial set with 6 non-degenerate simplices
To: RP^2
Defn: [(1, 1), (1, e), (f, 1), (f, e), (f * f, 1), (f * f, e)]
--> [1, 1, f, f, f * f, f * f]
- sage: phi.domain().face_data() # needs sage.groups
+ sage: phi.domain().face_data() # needs sage.graphs sage.groups
{(1, 1): None,
(1, e): None,
(f, 1): ((1, e), (1, 1)),
@@ -563,7 +562,7 @@ def universal_cover(self):
EXAMPLES::
- sage: # needs sage.groups
+ sage: # needs sage.graphs sage.groups
sage: RP3 = simplicial_sets.RealProjectiveSpace(3)
sage: C = RP3.universal_cover(); C
Simplicial set with 8 non-degenerate simplices
@@ -590,6 +589,7 @@ def _canonical_twisting_operator(self):
EXAMPLES::
+ sage: # needs sage.graphs
sage: X = simplicial_sets.Torus()
sage: d = X._canonical_twisting_operator()
sage: d
@@ -658,6 +658,7 @@ def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augment
EXAMPLES::
+ sage: # needs sage.graphs
sage: W = simplicial_sets.Sphere(1).wedge(simplicial_sets.Sphere(2))
sage: W.nondegenerate_simplices()
[*, sigma_1, sigma_2]
@@ -672,6 +673,7 @@ def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augment
::
+ sage: # needs sage.graphs
sage: X = simplicial_sets.Torus()
sage: C = X.twisted_chain_complex()
sage: C.differential(1)
@@ -685,6 +687,7 @@ def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augment
::
+ sage: # needs sage.graphs
sage: Y = simplicial_sets.RealProjectiveSpace(2)
sage: C = Y.twisted_chain_complex()
sage: C.differential(1)
@@ -829,6 +832,7 @@ def twisted_homology(self, n, reduced=False):
EXAMPLES::
+ sage: # needs sage.graphs
sage: X = simplicial_sets.Sphere(1).wedge(simplicial_sets.Sphere(2))
sage: X.twisted_homology(1)
Quotient module by Submodule of Ambient free module of rank 0 over the integral domain Multivariate Polynomial Ring in f1, f1inv over Integer Ring
@@ -841,6 +845,7 @@ def twisted_homology(self, n, reduced=False):
::
+ sage: # needs sage.graphs
sage: Y = simplicial_sets.Torus()
sage: Y.twisted_homology(1)
Quotient module by Submodule of Ambient free module of rank 5 over the integral domain Multivariate Polynomial Ring in f2, f2inv, f3, f3inv over Integer Ring
@@ -875,6 +880,7 @@ def twisted_homology(self, n, reduced=False):
TESTS::
+ sage: # needs sage.graphs
sage: X = simplicial_sets.PresentationComplex(groups.presentation.FGAbelian((3,2)))
sage: TW2 = X.twisted_homology(2, reduced=True)
sage: M = TW2.relations_matrix()
diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py
index a6578c4ec6a..aa2d4cd6f11 100644
--- a/src/sage/categories/weyl_groups.py
+++ b/src/sage/categories/weyl_groups.py
@@ -572,9 +572,10 @@ def stanley_symmetric_function(self):
- [Pon2010]_
"""
- import sage.combinat.sf
from sage.rings.rational_field import QQ
- m = sage.combinat.sf.sf.SymmetricFunctions(QQ).monomial()
+ from sage.combinat.sf.sf import SymmetricFunctions
+
+ m = SymmetricFunctions(QQ).monomial()
return m.from_polynomial_exp(self.stanley_symmetric_function_as_polynomial())
@cached_in_parent_method
diff --git a/src/sage/combinat/SJT.py b/src/sage/combinat/SJT.py
new file mode 100644
index 00000000000..03883eeb401
--- /dev/null
+++ b/src/sage/combinat/SJT.py
@@ -0,0 +1,246 @@
+r"""
+The Steinhaus-Johnson-Trotter algorithm generates all permutations of a list in
+an order such that each permutation is obtained by transposing two adjacent
+elements from the previous permutation.
+
+Each element of the list has a direction (initialized at -1) that changes at
+each permutation and that is used to determine which elements to transpose. Thus
+in addition to the permutation itself, the direction of each element is also
+stored.
+
+Note that the permutations are not generated in lexicographic order.
+
+AUTHORS:
+
+- Martin Grenouilloux (2024-05-22): initial version
+"""
+
+# ****************************************************************************
+# Copyright (C) 2024 Martin Grenouilloux
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+# https://www.gnu.org/licenses/
+# ****************************************************************************
+from sage.combinat.combinat import CombinatorialElement
+
+class SJT(CombinatorialElement):
+ r"""
+ A representation of a list permuted using the Steinhaus-Johnson-Trotter
+ algorithm.
+
+ Each element of the list has a direction (initialized at -1) that changes at
+ each permutation and that is used to determine which elements to transpose.
+ The directions have three possible values:
+
+ - ``-1``: element tranposes to the left
+
+ - ``1``: element transposes to the right
+
+ - ``0``: element does not move
+
+ Thus in addition to the permutation itself, the direction of each element is
+ also stored.
+
+ Note that the permutations are not generated in lexicographic order.
+
+ .. WARNING::
+
+ An ``SJT`` object should always be created with identity permutation for
+ the algorithm to behave properly. If the identity permutation is not
+ provided, it expects a coherent list of directions according to the
+ provided input. This list is not checked.
+
+ .. TODO::
+
+ Implement the previous permutation for the Steinhaus-Johnson-Trotter
+ algorithm.
+
+ EXAMPLES::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 2, 3, 4]); s
+ [1, 2, 3, 4]
+ sage: s = s.next(); s
+ [1, 2, 4, 3]
+ sage: p = Permutation(s._list, algorithm='sjt', sjt=s)
+ sage: p
+ [1, 2, 4, 3]
+ sage: p.next()
+ [1, 4, 2, 3]
+
+ TESTS::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 2, 3, 4]); s
+ [1, 2, 3, 4]
+ sage: s = SJT([1]); s
+ [1]
+ sage: s = s.next(); s
+ False
+ sage: s = SJT([]); s
+ []
+ sage: s = s.next(); s
+ False
+ """
+ def __init__(self, l, directions=None) -> None:
+ r"""
+ Transpose two elements at positions ``a`` and ``b`` in ``perm`` and
+ their corresponding directions as well following the
+ Steinhaus-Johnson-Trotter algorithm.
+
+ Each permutation is obtained by transposing two adjacent elements from
+ the previous permutation.
+
+ INPUT:
+
+ - ``l`` -- list; a list of ordered ``int``.
+
+ - ``directions`` -- list (default: ``None``); a list of directions for
+ each element in the permuted list. Used when constructing permutations
+ from a pre-defined internal state.
+
+ EXAMPLES::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 2, 3, 4]); s
+ [1, 2, 3, 4]
+ sage: s = s.next(); s
+ [1, 2, 4, 3]
+ sage: p = Permutation(s._list, algorithm='sjt', sjt=s)
+ sage: p
+ [1, 2, 4, 3]
+ sage: p.next()
+ [1, 4, 2, 3]
+
+ TESTS::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 3, 2, 4])
+ Traceback (most recent call last):
+ ...
+ ValueError: no internal state directions were given for non-identity
+ starting permutation for Steinhaus-Johnson-Trotter algorithm
+ sage: s = SJT([]); s
+ []
+ sage: s = s.next(); s
+ False
+ """
+ # The permuted list.
+ self._list = l
+
+ # The length of the permuted list. Return early on empty list.
+ self._n = len(l)
+ if self._n == 0:
+ return
+
+ if directions is None:
+ if not all(l[i] <= l[i+1] for i in range(self._n - 1)):
+ raise ValueError("no internal state directions were given for "
+ "non-identity starting permutation for "
+ "Steinhaus-Johnson-Trotter algorithm")
+ self._directions = [-1] * self._n
+
+ # The first element has null direction.
+ self._directions[0] = 0
+ else:
+ self._directions = directions
+
+ def __idx_largest_element_non_zero_direction(self, perm, directions):
+ r"""
+ Find the largest element in ``perm`` with a non null direction.
+ """
+ largest = 0
+ index = None
+ for i in range(self._n):
+ if directions[i] != 0:
+ e = perm[i]
+ if e > largest:
+ index = i
+ largest = e
+
+ return index
+
+ def next(self):
+ r"""
+ Produce the next permutation of ``self`` following the
+ Steinhaus-Johnson-Trotter algorithm.
+
+ OUTPUT: the list of the next permutation
+
+ EXAMPLES::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 2, 3, 4])
+ sage: s = s.next(); s
+ [1, 2, 4, 3]
+ sage: s = s.next(); s
+ [1, 4, 2, 3]
+
+ TESTS::
+
+ sage: from sage.combinat.SJT import SJT
+ sage: s = SJT([1, 2, 3])
+ sage: s.next()
+ [1, 3, 2]
+
+ sage: s = SJT([1])
+ sage: s.next()
+ False
+ """
+ # Return on empty list.
+ if self._n == 0:
+ return False
+
+ # Copying lists of permutation and directions to avoid changing internal
+ # state of the algorithm if ``next()`` is called without reassigning.
+ perm = self._list[:]
+ directions = self._directions[:]
+
+ # Assume that the element to move is n (which will be in most cases).
+ selected_elt = self._n
+ xi = perm.index(selected_elt)
+ direction = directions[xi]
+
+ # If this element has null direction, find the largest whose is
+ # non-null.
+ if direction == 0:
+ xi = self.__idx_largest_element_non_zero_direction(perm, directions)
+ if xi is None:
+ # We have created every permutation. Detected when all elements
+ # have null direction.
+ return False
+ direction = directions[xi]
+ selected_elt = perm[xi]
+
+ new_pos = xi + direction
+
+ # Proceed to transpose elements and corresponding directions.
+ perm[xi], perm[new_pos] = perm[new_pos], perm[xi]
+ directions[xi], directions[new_pos] = \
+ directions[new_pos], directions[xi]
+
+ # If the transposition results in the largest element being on one edge
+ # or if the following element in its direction is greater than it, then
+ # then set its direction to 0
+ if new_pos == 0 or new_pos == self._n - 1 or \
+ perm[new_pos + direction] > selected_elt:
+ directions[new_pos] = 0
+
+ # After each permutation, update each element's direction. If one
+ # element is greater than selected element, change its direction towards
+ # the selected element. This loops has no reason to be if selected
+ # element is n and this will be the case most of the time.
+ if selected_elt != self._n:
+ for i in range(self._n):
+ if perm[i] > selected_elt:
+ if i < new_pos:
+ directions[i] = 1
+ if i > new_pos:
+ directions[i] = -1
+
+ return SJT(perm, directions)
+
+ __next__ = next
diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py
index 11cd2d1b3ab..ae708a195ca 100644
--- a/src/sage/combinat/finite_state_machine_generators.py
+++ b/src/sage/combinat/finite_state_machine_generators.py
@@ -268,8 +268,8 @@ def Word(self, word, input_alphabet=None):
TESTS::
- sage: from sage.rings.integer import is_Integer
- sage: all(is_Integer(s.label()) for s in A.states())
+ sage: from sage.rings.integer import Integer
+ sage: all(isinstance(s.label(), Integer) for s in A.states())
True
"""
letters = list(word)
diff --git a/src/sage/combinat/ncsf_qsym/all.py b/src/sage/combinat/ncsf_qsym/all.py
index 5d61e9a9beb..9ea6d381f82 100644
--- a/src/sage/combinat/ncsf_qsym/all.py
+++ b/src/sage/combinat/ncsf_qsym/all.py
@@ -11,5 +11,10 @@
from sage.misc.namespace_package import install_doc
install_doc(__package__, __doc__)
-from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions
-from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions
+from sage.misc.lazy_import import lazy_import
+
+lazy_import('sage.combinat.ncsf_qsym.qsym', 'QuasiSymmetricFunctions')
+lazy_import('sage.combinat.ncsf_qsym.ncsf', 'NonCommutativeSymmetricFunctions')
+
+del install_doc
+del lazy_import
diff --git a/src/sage/combinat/ncsym/all.py b/src/sage/combinat/ncsym/all.py
index cdeeec1ae41..864a6ac6960 100644
--- a/src/sage/combinat/ncsym/all.py
+++ b/src/sage/combinat/ncsym/all.py
@@ -11,5 +11,10 @@
from sage.misc.namespace_package import install_doc
install_doc(__package__, __doc__)
-from sage.combinat.ncsym.ncsym import SymmetricFunctionsNonCommutingVariables
-from sage.combinat.ncsym.dual import SymmetricFunctionsNonCommutingVariablesDual
+from sage.misc.lazy_import import lazy_import
+
+lazy_import('sage.combinat.ncsym.ncsym', 'SymmetricFunctionsNonCommutingVariables')
+lazy_import('sage.combinat.ncsym.dual', 'SymmetricFunctionsNonCommutingVariablesDual')
+
+del install_doc
+del lazy_import
diff --git a/src/sage/combinat/nu_tamari_lattice.py b/src/sage/combinat/nu_tamari_lattice.py
index 56cfa020194..036de27126d 100644
--- a/src/sage/combinat/nu_tamari_lattice.py
+++ b/src/sage/combinat/nu_tamari_lattice.py
@@ -173,13 +173,13 @@ def delta_swap(p, k, delta):
raise ValueError("the index is greater than the length of the path")
# if delta is None:
# delta = [len(_) for _ in str(p._nu).split(sep='1')[1:]]
- if k == 0 or p[k-1] == 1:
+ if k == 0 or p[k - 1] == 1:
raise ValueError("there is no such covering move")
found = False
i = p[:k].count(1)
j = k
alt = 0
- while not found and j <= p.length()-1:
+ while not found and j <= p.length() - 1:
if p[j]:
alt += delta[i]
i += 1
@@ -188,9 +188,10 @@ def delta_swap(p, k, delta):
if alt == 0:
found = True
j += 1
- q = p[:k-1] + p[k:j] + [p[k-1]] + p[j:]
+ q = p[:k - 1] + p[k:j] + [p[k - 1]] + p[j:]
return NuDyckWord(q, p._nu)
+
def AltNuTamariLattice(nu, delta=None):
r"""
Return the `(\delta,\nu)`-Tamari lattice (or alt `\nu`-Tamari lattice).
@@ -253,12 +254,12 @@ def AltNuTamariLattice(nu, delta=None):
- [CC2023]_
"""
- if not( (isinstance(nu, (list, tuple)) and all(x in [0, 1] for x in nu)) or
- (isinstance(nu, str) and all(x in ['0', '1'] for x in nu)) ):
+ if not ((isinstance(nu, (list, tuple)) and all(x in [0, 1] for x in nu)) or
+ (isinstance(nu, str) and all(x in ['0', '1'] for x in nu))):
raise ValueError("nu must be a list or a string of 0s and 1s")
nu = [int(a) for a in nu]
# transforms nu in a sequence of 0s and 1s if it is a list
- nu = ''.join([str(a) for a in nu])
+ nu = ''.join(str(a) for a in nu)
# produces delta if delta is None, and check that delta is valid otherwise
deltamax = [len(a) for a in nu.split(sep='1')[1:]]
if delta is None:
@@ -270,4 +271,4 @@ def covers(p):
return [delta_swap(p, k, delta=delta) for k in range(1, p.length())
if not p[k - 1] and p[k]]
return LatticePoset({p: covers(p) for p in NuDyckWords(nu)},
- check=False)
\ No newline at end of file
+ check=False)
diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py
index 3621b2d21ec..8f3222f804b 100644
--- a/src/sage/combinat/partition.py
+++ b/src/sage/combinat/partition.py
@@ -710,8 +710,8 @@ def _repr_exp_low(self):
if not self._list:
return '-'
exp = self.to_exp()
- return '%s' % ', '.join('{}{}'.format(m + 1, '' if e == 1 else '^%s' % e)
- for (m,e) in enumerate(exp) if e > 0)
+ return ', '.join('{}{}'.format(m, '' if e == 1 else '^%s' % e)
+ for m, e in enumerate(exp, start=1) if e)
def _repr_exp_high(self):
"""
@@ -731,7 +731,7 @@ def _repr_exp_high(self):
exp = self.to_exp()[::-1] # reversed list of exponents
M = max(self)
return ', '.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e)
- for m, e in enumerate(exp) if e > 0)
+ for m, e in enumerate(exp) if e)
def _repr_compact_low(self):
"""
@@ -748,8 +748,8 @@ def _repr_compact_low(self):
if not self._list:
return '-'
exp = self.to_exp()
- return '%s' % ','.join('{}{}'.format(m + 1, '' if e == 1 else '^%s' % e)
- for (m,e) in enumerate(exp) if e > 0)
+ return ','.join('{}{}'.format(m, '' if e == 1 else '^%s' % e)
+ for m, e in enumerate(exp, start=1) if e)
def _repr_compact_high(self):
"""
@@ -767,8 +767,8 @@ def _repr_compact_high(self):
return '-'
exp = self.to_exp()[::-1] # reversed list of exponents
M = max(self)
- return '%s' % ','.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e)
- for (m,e) in enumerate(exp) if e > 0)
+ return ','.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e)
+ for m, e in enumerate(exp) if e)
def _repr_diagram(self):
r"""
@@ -793,7 +793,7 @@ def _repr_diagram(self):
"""
return self.ferrers_diagram()
- def level(self):
+ def level(self) -> int:
"""
Return the level of ``self``, which is always 1.
@@ -807,7 +807,7 @@ def level(self):
"""
return 1
- def components(self):
+ def components(self) -> list:
"""
Return a list containing the shape of ``self``.
@@ -819,9 +819,9 @@ def components(self):
sage: Partition([3,2]).components()
[[3, 2]]
"""
- return [ self ]
+ return [self]
- def _latex_(self):
+ def _latex_(self) -> str:
r"""
Return a LaTeX version of ``self``.
@@ -870,7 +870,7 @@ def _latex_(self):
"""
return self.parent().options._dispatch(self, '_latex_', 'latex')
- def _latex_young_diagram(self):
+ def _latex_young_diagram(self) -> str:
r"""
LaTeX output as a Young diagram.
@@ -890,9 +890,10 @@ def _latex_young_diagram(self):
return "{\\emptyset}"
from sage.combinat.output import tex_from_array
- return tex_from_array([ ["\\phantom{x}"]*row_size for row_size in self._list ])
+ return tex_from_array([["\\phantom{x}"] * row_size
+ for row_size in self._list])
- def _latex_diagram(self):
+ def _latex_diagram(self) -> str:
r"""
LaTeX output as a Ferrers' diagram.
@@ -913,9 +914,10 @@ def _latex_diagram(self):
entry = self.parent().options("latex_diagram_str")
from sage.combinat.output import tex_from_array
- return tex_from_array([ [entry]*row_size for row_size in self._list ], False)
+ return tex_from_array([[entry] * row_size
+ for row_size in self._list], False)
- def _latex_list(self):
+ def _latex_list(self) -> str:
r"""
LaTeX output as a list.
@@ -928,7 +930,7 @@ def _latex_list(self):
"""
return repr(self._list)
- def _latex_exp_low(self):
+ def _latex_exp_low(self) -> str:
r"""
LaTeX output in exponential notation (lowest first).
@@ -943,7 +945,7 @@ def _latex_exp_low(self):
return "{\\emptyset}"
exp = self.to_exp()
return '%s' % ','.join('{}{}'.format(m + 1, '' if e == 1 else '^{%s}' % e)
- for (m,e) in enumerate(exp) if e > 0)
+ for (m, e) in enumerate(exp) if e > 0)
def _latex_exp_high(self):
r"""
@@ -960,10 +962,10 @@ def _latex_exp_high(self):
return "{\\emptyset}"
exp = self.to_exp()[::-1] # reversed list of exponents
M = max(self)
- return '%s' % ','.join('{}{}'.format(M - m, '' if e == 1 else '^{%s}' % e)
- for (m,e) in enumerate(exp) if e > 0)
+ return ','.join('{}{}'.format(M - m, '' if e == 1 else '^{%s}' % e)
+ for m, e in enumerate(exp) if e)
- def ferrers_diagram(self):
+ def ferrers_diagram(self) -> str:
r"""
Return the Ferrers diagram of ``self``.
@@ -976,18 +978,18 @@ def ferrers_diagram(self):
*****
**
*
- sage: Partitions.options(diagram_str='#')
+ sage: Partitions.options(diagram_str='▉')
sage: print(mu.ferrers_diagram())
- #####
- #####
- ##
- #
+ ▉▉▉▉▉
+ ▉▉▉▉▉
+ ▉▉
+ ▉
sage: Partitions.options.convention="french"
sage: print(mu.ferrers_diagram())
- #
- ##
- #####
- #####
+ ▉
+ ▉▉
+ ▉▉▉▉▉
+ ▉▉▉▉▉
sage: print(Partition([]).ferrers_diagram())
-
sage: Partitions.options(diagram_str='-')
@@ -1000,10 +1002,9 @@ def ferrers_diagram(self):
return '-' if diag_str != '-' else "(/)"
if self.parent().options.convention == "English":
return '\n'.join(diag_str * p for p in self)
- else:
- return '\n'.join(diag_str * p for p in reversed(self))
+ return '\n'.join(diag_str * p for p in reversed(self))
- def pp(self):
+ def pp(self) -> None:
r"""
Print the Ferrers diagram.
@@ -1102,8 +1103,8 @@ def power(self, k):
"""
res = []
for i in self:
- g = gcd(i, k)
- res.extend( [ZZ(i//g)]*int(g) )
+ g = int(gcd(i, k))
+ res.extend([i // g] * g)
res.sort(reverse=True)
return Partition(res)
@@ -1128,16 +1129,16 @@ def __next__(self):
next_p = p[:] + [1]*(n - len(p))
- #Check to see if we are at the last (all ones) partition
- if p == [1]*n:
+ # Check to see if we are at the last (all ones) partition
+ if p == [1] * n:
return False
#
- #If we are not, then run the ZS1 algorithm.
+ # If we are not, then run the ZS1 algorithm.
#
- #Let h be the number of non-one entries in the
- #partition
+ # Let h be the number of non-one entries in the
+ # partition
h = 0
for i in next_p:
if i != 1:
@@ -1251,7 +1252,7 @@ def sign(self):
- :wikipedia:`Zolotarev%27s_lemma`
"""
- return (-1)**(self.size()-self.length())
+ return (-1)**(self.size() - self.length())
def k_size(self, k):
r"""
@@ -1338,8 +1339,7 @@ def horizontal_piece(xy, bdy):
stop_x = bdy[-1][0]
y = start_y # y never changes
h_piece = [(x, y) for x in range(start_x, stop_x)]
- h_piece = list(reversed(h_piece))
- return h_piece
+ return list(reversed(h_piece))
bdy = []
for i, part in enumerate(self):
(cell_x, cell_y) = (part - 1, i)
@@ -1456,7 +1456,7 @@ def k_column_lengths(self, k):
"""
return self.k_boundary(k).column_lengths()
- def has_rectangle(self, h, w):
+ def has_rectangle(self, h, w) -> bool:
r"""
Return ``True`` if the Ferrer's diagram of ``self`` has ``h``
(*or more*) rows of length ``w`` (*exactly*).
@@ -1502,10 +1502,9 @@ def has_rectangle(self, h, w):
"""
assert h >= 1
assert w >= 1
- num_rows_of_len_w = self.to_exp(w)[w - 1]
- return num_rows_of_len_w >= h
+ return self.to_exp(w)[w - 1] >= h
- def has_k_rectangle(self, k):
+ def has_k_rectangle(self, k) -> bool:
r"""
Return ``True`` if the Ferrer's diagram of ``self`` contains `k-i+1`
rows (*or more*) of length `i` (*exactly*) for any `i` in `[1, k]`.
@@ -1552,10 +1551,10 @@ def has_k_rectangle(self, k):
:meth:`is_k_irreducible`, :meth:`is_k_reducible`,
:meth:`has_rectangle`
"""
- return any(self.has_rectangle(a, b) for (a, b) in
- [(k-i+1, i) for i in range(1, k+1)])
+ return any(self.has_rectangle(k - i + 1, i)
+ for i in range(1, k + 1))
- def is_k_bounded(self, k):
+ def is_k_bounded(self, k) -> bool:
r"""
Return ``True`` if the partition ``self`` is bounded by ``k``.
@@ -1824,13 +1823,13 @@ def down(self):
l = len(p)
for i in range(l-1):
if p[i] > p[i+1]:
- yield Partition(p[:i] + [ p[i]-1 ] + p[i+1:])
+ yield Partition(p[:i] + [p[i]-1] + p[i+1:])
if l >= 1:
last = p[-1]
if last == 1:
yield Partition(p[:-1])
else:
- yield Partition(p[:-1] + [ p[-1] - 1 ])
+ yield Partition(p[:-1] + [p[-1] - 1])
def down_list(self):
"""
@@ -2073,7 +2072,7 @@ def frobenius_coordinates(self):
else:
b = [x for x in (val-i-1 for i, val in enumerate(muconj)) if x >= 0]
a = [x for x in (mu[i]-i-1 for i in range(len(b))) if x >= 0]
- return (a,b)
+ return (a, b)
def frobenius_rank(self):
r"""
@@ -2149,9 +2148,9 @@ def beta_numbers(self, length=None):
length = true_length
elif length < true_length:
raise ValueError("length must be at least the length of the partition")
- beta = [l + length - i - 1 for (i, l) in enumerate(self)]
+ beta = [l + length - i for i, l in enumerate(self, start=1)]
if length > true_length:
- beta.extend(list(range(length-true_length-1,-1,-1)))
+ beta.extend(range(length - true_length - 1, -1, -1))
return beta
def crank(self):
@@ -2316,7 +2315,7 @@ def dominates(self, p2):
sum2 = 0
min_length = min(len(p1), len(p2))
if min_length == 0:
- return not p2 # equivalent to len(p1) >= len(p2) = 0
+ return not p2 # equivalent to len(p1) >= len(p2) = 0
for i in range(min_length):
sum1 += p1[i]
@@ -2350,7 +2349,7 @@ def generalized_pochhammer_symbol(self, a, alpha):
12
"""
res = 1
- for (i,j) in self.cells():
+ for (i, j) in self.cells():
res *= (a - (i-1)/alpha + j-1)
return res
@@ -2698,11 +2697,11 @@ def suter_diagonal_slide(self, n, exp=1):
ValueError: the hook length must be less than n
"""
# Check for valid input
- if len(self) > 0 and len(self) + self._list[0] > n: # >, not >=, since we double count the (0,0) cell
+ if len(self) > 0 and len(self) + self._list[0] > n: # >, not >=, since we double count the (0,0) cell
raise ValueError("the hook length must be less than n")
ret = self
# Arbitrary exp
- exp = exp % n # It is at most order n
+ exp = exp % n # It is at most order n
if exp > n / 2:
exp -= n
while exp != 0:
@@ -2717,7 +2716,7 @@ def suter_diagonal_slide(self, n, exp=1):
res += [1] * (n - leng - ret._list[0])
ret = Partition(res)
exp -= 1
- else: # exp < 0 since if exp == 0, we would exit the while loop
+ else: # exp < 0 since if exp == 0, we would exit the while loop
# inverse map \sigma_n^{-1}
if leng == 0: # Taking extra care about the empty partition.
ret = Partition([n - 1])
@@ -2852,13 +2851,13 @@ def garnir_tableau(self, *cell):
raise ValueError('(row+1, col) must be inside the diagram')
g = self.initial_tableau().to_list()
a = g[row][col]
- g[row][col:] = list(range(a+col+1,g[row+1][col]+1))
- g[row+1][:col+1] = list(range(a,a+col+1))
+ g[row][col:] = list(range(a+col+1, g[row+1][col]+1))
+ g[row+1][:col+1] = list(range(a, a+col+1))
g = tableau.Tableau(g)
g._garnir_cell = (row, col)
return g
- def top_garnir_tableau(self,e,cell):
+ def top_garnir_tableau(self, e, cell):
r"""
Return the most dominant *standard* tableau which dominates the
corresponding Garnir tableau and has the same ``e``-residue.
@@ -2916,7 +2915,7 @@ def top_garnir_tableau(self,e,cell):
- [KMR2012]_
"""
- (row,col) = cell
+ (row, col) = cell
if row+1 >= len(self) or col >= self[row+1]:
raise ValueError(f'({row+1},{col})=(row+1,col) must be inside the diagram')
@@ -3070,10 +3069,10 @@ def young_subgroup(self):
gens = []
m = 0
for row in self:
- gens.extend([ (c,c+1) for c in range(m+1,m+row)])
+ gens.extend([(c, c+1) for c in range(m+1, m+row)])
m += row
- gens.append(list(range(1,self.size() + 1))) # to ensure we get a subgroup of Sym_n
- return PermutationGroup( gens )
+ gens.append(list(range(1, self.size() + 1))) # to ensure we get a subgroup of Sym_n
+ return PermutationGroup(gens)
def young_subgroup_generators(self):
r"""
@@ -3097,7 +3096,7 @@ def young_subgroup_generators(self):
gens = []
m = 0
for row in self:
- gens.extend(list(range(m + 1, m + row)))
+ gens.extend(range(m + 1, m + row))
m += row
return gens
@@ -3459,7 +3458,7 @@ def dominated_partitions(self, rows=None):
sage: Partition([3,2,1]).dominated_partitions(rows=3)
[[3, 2, 1], [2, 2, 2]]
"""
- #Naive implementation because iteration is so fast
+ # Naive implementation because iteration is so fast
n = sum(self)
P = Partitions_n(n)
if rows:
@@ -3554,7 +3553,7 @@ def hook_length(self, i, j):
sage: cell = [0,0]; Partition([3,3]).hook_length(*cell)
4
"""
- return self.leg_length(i,j)+self.arm_length(i,j)+1
+ return self.leg_length(i, j) + self.arm_length(i, j) + 1
def hooks(self):
"""
@@ -3995,7 +3994,7 @@ def block(self, e, multicharge=(0,)):
"""
block = {}
Ie = IntegerModRing(e)
- for (r,c) in self.cells():
+ for (r, c) in self.cells():
i = Ie(multicharge[0] + c - r)
block[i] = block.get(i, 0) + 1
return block
@@ -4112,7 +4111,7 @@ def is_restricted(self, e, multicharge=(0,)):
False
"""
return (not self
- or ( self[-1] < e and all(self[r]-self[r+1] < e for r in range(len(self)-1)) ))
+ or (self[-1] < e and all(self[r] - self[r+1] < e for r in range(len(self) - 1))))
def is_regular(self, e, multicharge=(0,)) -> bool:
"""
@@ -4177,7 +4176,7 @@ def corners(self) -> list:
if p.is_empty():
return []
- lcors = [[0,p[0]-1]]
+ lcors = [[0, p[0]-1]]
nn = len(p)
if nn == 1:
return [tuple(c) for c in lcors]
@@ -4187,7 +4186,7 @@ def corners(self) -> list:
if p[i] == p[i-1]:
lcors[lcors_index][0] += 1
else:
- lcors.append([i,p[i]-1])
+ lcors.append([i, p[i]-1])
lcors_index += 1
return [tuple(c) for c in lcors]
@@ -4253,7 +4252,7 @@ def outside_corners(self):
"""
p = self._list
if not p:
- return [(0,0)]
+ return [(0, 0)]
res = [(0, p[0])]
res.extend((n, j) for n, (i, j) in enumerate(zip(p[:-1], p[1:]), start=1) if i != j)
res.append((len(p), 0))
@@ -4445,25 +4444,25 @@ def core(self, length):
[]
"""
p = self
- #Normalize the length
+ # Normalize the length
remainder = len(p) % length
part = p[:] + [0]*remainder
- #Add the canonical vector to the partition
+ # Add the canonical vector to the partition
part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)]
for e in range(length):
k = e
- for i in reversed(range(1,len(part)+1)):
+ for i in reversed(range(1, len(part)+1)):
if part[i-1] % length == e:
part[i-1] = k
k += length
part.sort()
part.reverse()
- #Remove the canonical vector
+ # Remove the canonical vector
part = [part[i-1]-len(part)+i for i in range(1, len(part)+1)]
- #Select the r-core
+ # Select the r-core
return Partition([x for x in part if x != 0])
def quotient(self, length):
@@ -4511,15 +4510,15 @@ def quotient(self, length):
True
"""
p = self
- #Normalize the length
+ # Normalize the length
remainder = len(p) % length
part = p[:] + [0]*(length-remainder)
- #Add the canonical vector to the partition
+ # Add the canonical vector to the partition
part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)]
result = [None]*length
- #Reducing vector
+ # Reducing vector
for e in range(length):
k = e
tmp = []
@@ -4533,7 +4532,7 @@ def quotient(self, length):
result[e] = a
from .partition_tuple import PartitionTuple
- return PartitionTuple(result) #tuple(map(Partition, result))
+ return PartitionTuple(result) # tuple(map(Partition, result))
def is_core(self, k):
r"""
@@ -4632,7 +4631,7 @@ def add_cell(self, i, j=None):
else:
j = self[i]
- if (i,j) in self.outside_corners():
+ if (i, j) in self.outside_corners():
pl = self.to_list()
if i == len(pl):
pl.append(1)
@@ -4668,13 +4667,13 @@ def remove_cell(self, i, j=None):
if j is None:
j = self[i] - 1
- if (i,j) not in self.corners():
- raise ValueError("[%d,%d] is not a corner of the partition" % (i,j))
+ if (i, j) not in self.corners():
+ raise ValueError("[%d,%d] is not a corner of the partition" % (i, j))
if self[i] == 1:
return Partition(self[:-1])
else:
- return Partition(self[:i] + [ self[i:i+1][0] - 1 ] + self[i+1:])
+ return Partition(self[:i] + [self[i:i+1][0] - 1] + self[i+1:])
def k_irreducible(self, k):
r"""
@@ -4704,7 +4703,7 @@ def k_irreducible(self, k):
[2, 1]
"""
pexp = self.to_exp()
- return Partition(sum(([r+1] for r in range(len(pexp)-1,-1,-1) for m in range(pexp[r] % (k-r))),[]))
+ return Partition(sum(([r+1] for r in range(len(pexp)-1, -1, -1) for m in range(pexp[r] % (k-r))), []))
def k_skew(self, k):
r"""
@@ -4732,20 +4731,20 @@ def k_skew(self, k):
"""
if len(self) == 0:
- return SkewPartition([[],[]])
+ return SkewPartition([[], []])
if self[0] > k:
raise ValueError(f"the partition must be {k}-bounded")
- #Find the k-skew diagram of the partition formed
- #by removing the first row
+ # Find the k-skew diagram of the partition formed
+ # by removing the first row
s = Partition(self[1:]).k_skew(k)
s_inner = list(s.inner())
s_outer = list(s.outer())
s_conj_rl = s.conjugate().row_lengths()
- #Find the leftmost column with less than
+ # Find the leftmost column with less than
# or equal to kdiff cells
kdiff = k - self[0]
@@ -4759,9 +4758,9 @@ def k_skew(self, k):
spot = i
break
- outer = [ self[0] + spot ] + s_outer[:]
+ outer = [self[0] + spot] + s_outer[:]
if spot > 0:
- inner = [ spot ] + s_inner[:]
+ inner = [spot] + s_inner[:]
else:
inner = s_inner[:]
@@ -4784,7 +4783,7 @@ def to_core(self, k):
True
"""
from sage.combinat.core import Core
- return Core(self.k_skew(k)[0],k+1)
+ return Core(self.k_skew(k)[0], k+1)
def from_kbounded_to_reduced_word(self, k):
r"""
@@ -4815,9 +4814,9 @@ def from_kbounded_to_reduced_word(self, k):
result = []
while not p.is_empty():
corners = p.corners()
- c = p.content(corners[0][0],corners[0][1]) % (k+1)
+ c = p.content(corners[0][0], corners[0][1]) % (k+1)
result.append(Integer(c))
- list = [x for x in corners if p.content(x[0],x[1]) % (k+1) == c]
+ list = [x for x in corners if p.content(x[0], x[1]) % (k+1) == c]
for x in list:
p = p.remove_cell(x[0])
return result
@@ -4843,7 +4842,7 @@ def from_kbounded_to_grassmannian(self, k):
[0 1 0]
[0 0 1]
"""
- return WeylGroup(['A', k,1 ]).from_reduced_word(self.from_kbounded_to_reduced_word(k))
+ return WeylGroup(['A', k, 1]).from_reduced_word(self.from_kbounded_to_reduced_word(k))
def to_list(self):
r"""
@@ -5070,7 +5069,7 @@ def horizontal_border_strip_cells(self, k):
mapping.append(len(L))
shelf.append(L[-1])
- L.append(0) # add room on the bottom
+ L.append(0) # add room on the bottom
# list all of the positions for cells
# filling each self from the top to bottom
for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter():
@@ -5177,8 +5176,8 @@ def arms_legs_coeff(self, i, j):
QQqt = PolynomialRing(QQ, ['q', 't'])
(q, t) = QQqt.gens()
if i < len(self) and j < self[i]:
- res = (1-q**self.arm_length(i,j) * t**(self.leg_length(i,j)+1))
- res /= (1-q**(self.arm_length(i,j)+1) * t**self.leg_length(i,j))
+ res = 1 - q**self.arm_length(i, j) * t**(self.leg_length(i, j)+1)
+ res /= 1 - q**(self.arm_length(i, j)+1) * t**self.leg_length(i, j)
return res
return ZZ.one()
@@ -5288,7 +5287,7 @@ def jacobi_trudi(self):
sage: jt.det()
h[3, 2, 1] - h[3, 3] - h[4, 1, 1] + h[5, 1]
"""
- return SkewPartition([ self, [] ]).jacobi_trudi()
+ return SkewPartition([self, []]).jacobi_trudi()
def character_polynomial(self):
r"""
@@ -5328,23 +5327,23 @@ def character_polynomial(self):
P = PolynomialRing(QQ, k, 'x')
x = P.gens()
- #Expand s_mu in the power sum basis
+ # Expand s_mu in the power sum basis
from sage.combinat.sf.sf import SymmetricFunctions
Sym = SymmetricFunctions(QQ)
s = Sym.schur()
p = Sym.power()
ps_mu = p(s(self))
- #Replace each p_i by i*x_i-1
- items = ps_mu.monomial_coefficients().items() #items contains a list of (partition, coeff) pairs
- partition_to_monomial = lambda part: prod([ (i*x[i-1]-1) for i in part ])
- res = [ [partition_to_monomial(mc[0]), mc[1]] for mc in items ]
+ # Replace each p_i by i*x_i-1
+ items = ps_mu.monomial_coefficients().items() # items contains a list of (partition, coeff) pairs
+ partition_to_monomial = lambda part: prod([i*x[i-1] - 1 for i in part])
+ res = [[partition_to_monomial(mc[0]), mc[1]] for mc in items]
- #Write things in the monomial basis
- res = [ prod(pair) for pair in res ]
- res = sum( res )
+ # Write things in the monomial basis
+ res = [prod(pair) for pair in res]
+ res = sum(res)
- #Apply the umbral operator and return the result
+ # Apply the umbral operator and return the result
from sage.combinat.misc import umbral_operation
return umbral_operation(res)
@@ -5450,30 +5449,30 @@ def dimension(self, smaller=None, k=1):
def inv_factorial(i):
if i < 0:
return 0
- else:
- return 1/factorial(i)
- len_range = list(range(larger.length()))
+ return 1/factorial(i)
+
+ len_range = range(larger.length())
from sage.matrix.constructor import matrix
- M = matrix(QQ,[[inv_factorial(larger.get_part(i)-smaller.get_part(j)-i+j) for i in len_range] for j in len_range])
+ M = matrix(QQ, [[inv_factorial(larger.get_part(i)-smaller.get_part(j)-i+j) for i in len_range] for j in len_range])
return factorial(larger.size()-smaller.size())*M.determinant()
else:
larger_core = larger.core(k)
smaller_core = smaller.core(k)
- if smaller_core != larger_core: # easy case
+ if smaller_core != larger_core: # easy case
return 0
larger_quotients = larger.quotient(k)
smaller_quotients = smaller.quotient(k)
- def multinomial_with_partitions(sizes,path_counts):
- # count the number of ways of performing the k paths in parallel,
- # if we know the total length allotted for each of the paths (sizes), and the number
- # of paths for each component. A multinomial picks the ordering of the components where
- # each step is taken.
+ def multinomial_with_partitions(sizes, path_counts):
+ # count the number of ways of performing the k paths in parallel,
+ # if we know the total length allotted for each of the paths (sizes), and the number
+ # of paths for each component. A multinomial picks the ordering of the components where
+ # each step is taken.
return prod(path_counts) * multinomial(sizes)
sizes = [larger_quotients[i].size()-smaller_quotients[i].size() for i in range(k)]
path_counts = [larger_quotients[i].dimension(smaller_quotients[i]) for i in range(k)]
- return multinomial_with_partitions(sizes,path_counts)
+ return multinomial_with_partitions(sizes, path_counts)
def plancherel_measure(self):
r"""
@@ -5541,7 +5540,7 @@ def outline(self, variable=None):
outside_contents = [self.content(*c) for c in self.outside_corners()]
inside_contents = [self.content(*c) for c in self.corners()]
return sum(abs(variable+c) for c in outside_contents)\
- - sum(abs(variable+c) for c in inside_contents)
+ - sum(abs(variable+c) for c in inside_contents)
def dual_equivalence_graph(self, directed=False, coloring=None):
r"""
@@ -5829,6 +5828,7 @@ def tabloid_module(self, base_ring=None):
R = SymmetricGroupAlgebra(base_ring, sum(self))
return TabloidModule(R, self)
+
##############
# Partitions #
##############
@@ -6158,7 +6158,7 @@ def __classcall_private__(cls, n=None, **kwargs):
"""
if n == infinity:
raise ValueError("n cannot be infinite")
- if isinstance(n, (int,Integer)):
+ if isinstance(n, (int, Integer)):
if len(kwargs) == 0:
return Partitions_n(n)
@@ -6187,7 +6187,7 @@ def __classcall_private__(cls, n=None, **kwargs):
return RestrictedPartitions_n(n, kwargs['restricted'])
# FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute
- kwargs['name'] = "Partitions of the integer {} satisfying constraints {}".format(n, ", ".join( ["{}={}".format(key, kwargs[key]) for key in sorted(kwargs)] ))
+ kwargs['name'] = "Partitions of the integer {} satisfying constraints {}".format(n, ", ".join(["{}={}".format(key, kwargs[key]) for key in sorted(kwargs)]))
# min_part is at least 1, and it is 1 by default
kwargs['min_part'] = max(1, kwargs.get('min_part', 1))
@@ -6209,7 +6209,7 @@ def __classcall_private__(cls, n=None, **kwargs):
inner = [x for x in kwargs['inner'] if x > 0]
kwargs['floor'] = inner
kwargs['min_length'] = max(len(inner),
- kwargs.get('min_length',0))
+ kwargs.get('min_length', 0))
del kwargs['inner']
return Partitions_with_constraints(n, **kwargs)
elif n is None or n is NN or n is NonNegativeIntegers():
@@ -6345,11 +6345,11 @@ class options(GlobalOptions):
'case_sensitive': False}
diagram_str = {'default': "*",
'description': 'The character used for the cells when printing Ferrers diagrams',
- 'checker': lambda char: isinstance(char,str)}
+ 'checker': lambda char: isinstance(char, str)}
latex_diagram_str = {'default': "\\ast",
'description': 'The character used for the cells when latexing Ferrers diagrams',
- 'checker': lambda char: isinstance(char,str)}
- convention = {'link_to': (tableau.Tableaux.options,'convention')}
+ 'checker': lambda char: isinstance(char, str)}
+ convention = {'link_to': (tableau.Tableaux.options, 'convention')}
notation = {'alt_name': 'convention'}
def __reversed__(self):
@@ -6690,7 +6690,7 @@ def from_zero_one(self, seq):
True
"""
tmp = [i for i in range(len(seq)) if seq[i] == 0]
- return self.element_class(self,[tmp[i]-i for i in range(len(tmp)-1,-1,-1)])
+ return self.element_class(self, [tmp[i]-i for i in range(len(tmp)-1, -1, -1)])
def from_core_and_quotient(self, core, quotient):
"""
@@ -6737,15 +6737,15 @@ def from_core_and_quotient(self, core, quotient):
length = len(components)
k = length*max(len(q) for q in components) + len(core)
# k needs to be large enough. this seems to me like the smallest it can be
- v = [core[i]-i for i in range(len(core))] + [ -i for i in range(len(core),k) ]
- w = [ [x for x in v if (x-i) % length == 0] for i in range(1, length+1) ]
+ v = [core[i]-i for i in range(len(core))] + [-i for i in range(len(core), k)]
+ w = [[x for x in v if (x-i) % length == 0] for i in range(1, length+1)]
new_w = []
for i in range(length):
lw = len(w[i])
lq = len(components[i])
# k needs to be chosen so lw >= lq
- new_w += [ w[i][j] + length*components[i][j] for j in range(lq)]
- new_w += [ w[i][j] for j in range(lq,lw)]
+ new_w += [w[i][j] + length*components[i][j] for j in range(lq)]
+ new_w += [w[i][j] for j in range(lq, lw)]
new_w.sort(reverse=True)
return self.element_class(self, [new_w[i]+i for i in range(len(new_w))])
@@ -6849,7 +6849,7 @@ def __contains__(self, x):
"""
return x in _Partitions and sum(x) == self.n
- def _repr_(self):
+ def _repr_(self) -> str:
"""
Return a string representation of ``self``.
@@ -6878,7 +6878,7 @@ def _an_element_(self):
elif self.n == 1:
lst = [1]
else:
- lst = [self.n-1, 1]
+ lst = [self.n - 1, 1]
return self.element_class(self, lst)
def cardinality(self, algorithm='flint'):
@@ -7047,7 +7047,7 @@ def random_element_uniform(self):
- Florent Hivert (2009-11-23)
"""
n = self.n
- res = [] # A dictionary of multiplicities could be faster.
+ res = [] # A dictionary of multiplicities could be faster.
while n > 0:
# Choose a pair d,j = 1,2..., with d*j <= n with probability
# d*numpart(n-d*j) / n / numpart(n)
@@ -7858,7 +7858,7 @@ def first(self):
mu = list(self._starting) + [1] * (self.n - k)
return next(Partition(mu))
- #if self._starting.size() > self.n:
+ # if self._starting.size() > self.n:
return self.element_class(self, Partitions(self.n, outer=self._starting).first())
def next(self, part):
@@ -8044,7 +8044,7 @@ def __contains__(self, x):
True
"""
return x in _Partitions and len(x) <= self.h \
- and (len(x) == 0 or x[0] <= self.w)
+ and (len(x) == 0 or x[0] <= self.w)
def list(self):
"""
@@ -9444,14 +9444,14 @@ def number_of_partitions_length(n, k, algorithm='hybrid'):
##########
-# trac 14225: Partitions() is frequently used, but only weakly cached. Hence,
-# establish a strong reference to it.
+# issue 14225: Partitions() is frequently used, but only weakly cached.
+# Hence, establish a strong reference to it.
_Partitions = Partitions()
# Rather than caching an under-used function I have cached the default
# number_of_partitions functions which is currently using FLINT.
-# AM trac #13072
+# AM issue #13072
try:
from sage.libs.flint.arith_sage import number_of_partitions as flint_number_of_partitions
cached_number_of_partitions = cached_function(flint_number_of_partitions)
diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py
index 4f0cd8e97df..1ca90eff943 100644
--- a/src/sage/combinat/permutation.py
+++ b/src/sage/combinat/permutation.py
@@ -250,6 +250,7 @@
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
from sage.categories.sets_with_grading import SetsWithGrading
from sage.combinat.backtrack import GenericBacktracker
+from sage.combinat.SJT import SJT
from sage.combinat.combinat import CombinatorialElement, catalan_number
from sage.combinat.combinatorial_map import combinatorial_map
from sage.combinat.composition import Composition
@@ -308,9 +309,22 @@ class Permutation(CombinatorialElement):
the permutation obtained from the pair using the inverse of the
Robinson-Schensted algorithm.
- - ``check`` (boolean) -- whether to check that input is correct. Slows
- the function down, but ensures that nothing bad happens. This is set to
- ``True`` by default.
+ - ``check`` -- boolean (default: ``True``); whether to check that input is
+ correct. Slows the function down, but ensures that nothing bad happens.
+ This is set to ``True`` by default.
+
+ - ``algorithm`` -- string (default: ``lex``); the algorithm used to generate
+ the permutations. Supported algorithms are:
+
+ - ``lex``: lexicographic order generation, this is the default algorithm.
+
+ - ``sjt``: Steinhaus-Johnson-Trotter algorithm to generate permutations
+ using only transposition of two elements in the list. It is highly
+ recommended to set ``check=True`` (default value).
+
+ - ``sjt`` -- SJT (default: ``None``); the ``SJT`` object holding the
+ permutation internal state. This should only be specified when
+ initializing with non-identity permutation.
.. WARNING::
@@ -378,6 +392,27 @@ class Permutation(CombinatorialElement):
sage: type(p)
+ Generate permutations using the Steinhaus-Johnson Trotter algorithm. The
+ output is not in lexicographic order::
+
+ sage: p = Permutation([1, 2, 3, 4], algorithm='sjt'); p
+ [1, 2, 3, 4]
+ sage: p = p.next(); p
+ [1, 2, 4, 3]
+ sage: p = p.next(); p
+ [1, 4, 2, 3]
+ sage: p = Permutation([1, 2, 3], algorithm='sjt')
+ sage: for _ in range(6):
+ ....: p = p.next()
+ sage: p
+ False
+
+ sage: Permutation([1, 3, 2, 4], algorithm='sjt')
+ Traceback (most recent call last):
+ ...
+ ValueError: no internal state directions were given for non-identity
+ starting permutation for Steinhaus-Johnson-Trotter algorithm
+
Construction from a string in cycle notation::
sage: p = Permutation( '(4,5)' ); p
@@ -427,6 +462,11 @@ class Permutation(CombinatorialElement):
sage: Permutation( [1] )
[1]
+ sage: Permutation([1, 2, 3, 4], algorithm='blah')
+ Traceback (most recent call last):
+ ...
+ ValueError: unsupported algorithm blah; expected 'lex' or 'sjt'
+
From a pair of empty tableaux ::
sage: Permutation( ([], []) ) # needs sage.combinat
@@ -436,7 +476,7 @@ class Permutation(CombinatorialElement):
"""
@staticmethod
@rename_keyword(deprecation=35233, check_input='check')
- def __classcall_private__(cls, l, check=True):
+ def __classcall_private__(cls, l, algorithm='lex', sjt=None, check=True):
"""
Return a permutation in the general permutations parent.
@@ -487,10 +527,10 @@ def __classcall_private__(cls, l, check=True):
raise ValueError("cannot convert l (= %s) to a Permutation" % l)
# otherwise, it gets processed by CombinatorialElement's __init__.
- return Permutations()(l, check=check)
+ return Permutations()(l, algorithm, sjt, check)
@rename_keyword(deprecation=35233, check_input='check')
- def __init__(self, parent, l, check=True):
+ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True):
"""
Constructor. Checks that INPUT is not a mess, and calls
:class:`CombinatorialElement`. It should not, because
@@ -500,11 +540,23 @@ def __init__(self, parent, l, check=True):
- ``l`` -- a list of ``int`` variables
- - ``check`` (boolean) -- whether to check that input is
- correct. Slows the function down, but ensures that nothing bad
+ - ``check`` -- boolean (default: ``True``); whether to check that input
+ is correct. Slows the function down, but ensures that nothing bad
happens.
- This is set to ``True`` by default.
+ - ``algorithm`` -- string (default: ``lex``); the algorithm used to
+ generate the permutations. Supported algorithms are:
+
+ - ``lex``: lexicographic order generation, this is the default
+ algorithm.
+
+ - ``sjt``: Steinhaus-Johnson-Trotter algorithm to generate
+ permutations using only transposition of two elements in the list.
+ It is highly recommended to set ``check=True`` (default value).
+
+ - ``sjt`` -- SJT (default: ``None``); the ``SJT`` object holding the
+ permutation internal state. This should only be specified when
+ initializing with non-identity permutation.
TESTS::
@@ -521,12 +573,30 @@ def __init__(self, parent, l, check=True):
sage: Permutation([1,2,4,5])
Traceback (most recent call last):
...
- ValueError: The permutation has length 4 but its maximal element is
+ ValueError: the permutation has length 4 but its maximal element is
5. Some element may be repeated, or an element is missing, but there
is something wrong with its length.
+
+ sage: Permutation([1, 3, 2], algorithm='sjt')
+ Traceback (most recent call last):
+ ...
+ ValueError: no internal state directions were given for non-identity
+ starting permutation for Steinhaus-Johnson-Trotter algorithm
+
+ sage: Permutation([1, 3, 2], algorithm='sjt', check=False)
+ Traceback (most recent call last):
+ ...
+ ValueError: no internal state directions were given for non-identity
+ starting permutation for Steinhaus-Johnson-Trotter algorithm
"""
l = list(l)
+ self._algorithm = algorithm.lower()
+
+ if self._algorithm != "lex" and self._algorithm != "sjt":
+ raise ValueError("unsupported algorithm %s; expected 'lex' or 'sjt'"
+ % self._algorithm)
+
if check and len(l) > 0:
# Make a copy to sort later
lst = list(l)
@@ -538,18 +608,19 @@ def __init__(self, parent, l, check=True):
except TypeError:
raise ValueError("the elements must be integer variables")
if i < 1:
- raise ValueError("the elements must be strictly positive integers")
+ raise ValueError("the elements must be strictly positive "
+ "integers")
lst.sort()
# Is the maximum element of the permutation the length of input,
# or is some integer missing ?
if int(lst[-1]) != len(lst):
- raise ValueError("The permutation has length "+str(len(lst)) +
+ raise ValueError("the permutation has length "+str(len(lst)) +
" but its maximal element is " +
- str(int(lst[-1]))+". Some element " +
- "may be repeated, or an element is missing" +
- ", but there is something wrong with its length.")
+ str(int(lst[-1])) + ". Some element may be " +
+ "repeated, or an element is missing, but " +
+ "there is something wrong with its length.")
# Do the elements appear only once ?
previous = lst[0]-1
@@ -559,6 +630,9 @@ def __init__(self, parent, l, check=True):
raise ValueError("an element appears twice in the input")
previous = i
+ if self._algorithm == "sjt":
+ self._sjt = SJT(l) if sjt is None else sjt
+
CombinatorialElement.__init__(self, parent, l)
def __setstate__(self, state):
@@ -761,9 +835,18 @@ def cycle_string(self, singletons=False) -> str:
def __next__(self):
r"""
- Return the permutation that follows ``self`` in lexicographic order on
- the symmetric group containing ``self``. If ``self`` is the last
- permutation, then ``next`` returns ``False``.
+ Return the permutation that follows ``self`` on the symmetric group
+ containing ``self``. If ``self`` is the last permutation, then ``next``
+ returns ``False``. If the ``algorithm`` parameter is specified, the
+ permutations will be generated according to it. Supported algorithms
+ are:
+
+ - ``lex``: lexicographic order generation, this is the default
+ algorithm.
+
+ - ``sjt``: Steinhaus-Johnson-Trotter algorithm to generate
+ permutations using only transposition of two elements in the list.
+ It is highly recommended to set ``check=True`` (default value).
EXAMPLES::
@@ -773,13 +856,41 @@ def __next__(self):
sage: p = Permutation([4,3,2,1])
sage: next(p)
False
+ sage: p = Permutation([1, 2, 3], algorithm='sjt')
+ sage: p = next(p); p
+ [1, 3, 2]
+ sage: p = next(p); p
+ [3, 1, 2]
TESTS::
sage: p = Permutation([])
sage: next(p)
False
+ sage: p = Permutation([], algorithm='sjt')
+ sage: next(p)
+ False
+ sage: p = Permutation([1], algorithm='sjt')
+ sage: next(p)
+ False
+ sage: l = [1, 2, 3, 4]
+ sage: s = set()
+ sage: p = Permutation(l, algorithm='sjt')
+ sage: for _ in range(factorial(len(l))):
+ ....: s.add(p)
+ ....: p = p.next()
+ sage: p
+ False
+ sage: assert(len(s)) == factorial(len(l))
"""
+ if self._algorithm == "sjt":
+ # Ensure the same permutation is yielded when called multiple times
+ # without reassigning
+ sjt = self._sjt.next()
+ if sjt is False:
+ return False
+ return Permutations()(sjt._list, algorithm='sjt', sjt=sjt)
+
p = self[:]
n = len(self)
first = -1
@@ -818,6 +929,7 @@ def prev(self):
Return the permutation that comes directly before ``self`` in
lexicographic order on the symmetric group containing ``self``.
If ``self`` is the first permutation, then it returns ``False``.
+ Does not support the Steinhaus-Johnson-Trotter algorithm for the moment.
EXAMPLES::
@@ -834,11 +946,26 @@ def prev(self):
sage: p.prev()
False
+ sage: p = Permutation([1,2,3], algorithm='sjt')
+ sage: p.prev()
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: previous permutation for SJT algorithm is not
+ yet implemented
+
Check that :issue:`16913` is fixed::
sage: Permutation([1,4,3,2]).prev()
[1, 4, 2, 3]
+
+ .. TODO::
+
+ Implement the previous permutation for the Steinhaus-Johnson-Trotter
+ algorithm.
"""
+ if self._algorithm == "sjt":
+ raise NotImplementedError("previous permutation for SJT algorithm "
+ "is not yet implemented")
p = self[:]
n = len(self)
diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py
index f56f3f2d3b4..9c5689bcb81 100644
--- a/src/sage/combinat/posets/lattices.py
+++ b/src/sage/combinat/posets/lattices.py
@@ -3615,7 +3615,7 @@ def adjunct(self, other, a, b):
sage: PP.atoms()
[(0, 1), (0, 2), (1, 'a')]
sage: PP.coatoms()
- [(0, 3), (0, 1)]
+ [(0, 1), (0, 3)]
TESTS::
diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py
index 9fdbf6855de..f462becaa17 100644
--- a/src/sage/combinat/posets/posets.py
+++ b/src/sage/combinat/posets/posets.py
@@ -6551,7 +6551,7 @@ def random_maximal_chain(self):
sage: set_random_seed(0) # results are reproduceable
sage: P = posets.BooleanLattice(4)
sage: P.random_maximal_chain()
- [0, 2, 10, 11, 15]
+ [0, 4, 5, 7, 15]
TESTS::
@@ -6618,7 +6618,7 @@ def random_linear_extension(self):
sage: set_random_seed(0) # results are reproduceable
sage: P = posets.BooleanLattice(4)
sage: P.random_linear_extension()
- [0, 2, 8, 1, 9, 4, 5, 10, 6, 12, 14, 13, 3, 7, 11, 15]
+ [0, 4, 1, 2, 3, 8, 10, 5, 12, 9, 13, 11, 6, 14, 7, 15]
TESTS::
diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py
index 9c50eb57af1..bb55e491b44 100644
--- a/src/sage/combinat/root_system/all.py
+++ b/src/sage/combinat/root_system/all.py
@@ -122,9 +122,9 @@
from sage.misc.lazy_import import lazy_import
from sage.combinat.root_system.cartan_type import CartanType
-from sage.combinat.root_system.dynkin_diagram import DynkinDiagram
-from sage.combinat.root_system.cartan_matrix import CartanMatrix
-from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix
+lazy_import('sage.combinat.root_system.dynkin_diagram', 'DynkinDiagram')
+lazy_import('sage.combinat.root_system.cartan_matrix', 'CartanMatrix')
+lazy_import('sage.combinat.root_system.coxeter_matrix', 'CoxeterMatrix')
from sage.combinat.root_system.coxeter_type import CoxeterType
from sage.combinat.root_system.root_system import RootSystem, WeylDim
lazy_import('sage.combinat.root_system.weyl_group', ['WeylGroup',
@@ -138,5 +138,9 @@
'WeightRing'])
from sage.combinat.root_system.branching_rules import BranchingRule, branching_rule_from_plethysm, branching_rule
-lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials')
-lazy_import('sage.combinat.root_system.integrable_representations', 'IntegrableRepresentation')
+lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials',
+ 'NonSymmetricMacdonaldPolynomials')
+lazy_import('sage.combinat.root_system.integrable_representations',
+ 'IntegrableRepresentation')
+del lazy_import
+del install_doc
diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py
index 8c62cfb08df..e70959f8dfc 100644
--- a/src/sage/combinat/sf/jack.py
+++ b/src/sage/combinat/sf/jack.py
@@ -36,7 +36,7 @@
from sage.rings.rational_field import QQ
from sage.arith.misc import gcd
from sage.arith.functions import lcm
-from sage.rings.fraction_field import is_FractionField
+from sage.rings.fraction_field import FractionField_generic
from sage.misc.misc_c import prod
from sage.categories.morphism import SetMorphism
from sage.categories.homset import Hom, End
@@ -481,7 +481,7 @@ def normalize_coefficients(self, c):
6/(t^2 + 3*t + 2)
"""
BR = self.base_ring()
- if is_FractionField(BR) and BR.base_ring() == QQ:
+ if isinstance(BR, FractionField_generic) and BR.base_ring() == QQ:
denom = c.denominator()
numer = c.numerator()
diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py
index ab61f4f37f7..99ef16b740d 100644
--- a/src/sage/combinat/skew_tableau.py
+++ b/src/sage/combinat/skew_tableau.py
@@ -50,6 +50,7 @@
from sage.misc.persist import register_unpickle_override
lazy_import('sage.matrix.special', 'zero_matrix')
+lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup')
class SkewTableau(ClonableList,
@@ -1139,6 +1140,81 @@ def to_list(self):
"""
return [list(row) for row in self]
+ def row_stabilizer(self):
+ """
+ Return the :func:`PermutationGroup` corresponding to the row stabilizer of
+ ``self``.
+
+ This assumes that every integer from `1` to the size of ``self``
+ appears exactly once in ``self``.
+
+ EXAMPLES::
+
+ sage: # needs sage.groups
+ sage: rs = SkewTableau([[None,1,2,3],[4,5]]).row_stabilizer()
+ sage: rs.order() == factorial(3) * factorial(2)
+ True
+ sage: PermutationGroupElement([(1,3,2),(4,5)]) in rs
+ True
+ sage: PermutationGroupElement([(1,4)]) in rs
+ False
+ sage: rs = SkewTableau([[None,1,2],[3]]).row_stabilizer()
+ sage: PermutationGroupElement([(1,2),(3,)]) in rs
+ True
+ sage: rs.one().domain()
+ [1, 2, 3]
+ sage: rs = SkewTableau([[None,None,1],[None,2],[3]]).row_stabilizer()
+ sage: rs.order()
+ 1
+ sage: rs = SkewTableau([[None,None,2,4,5],[1,3]]).row_stabilizer()
+ sage: rs.order()
+ 12
+ sage: rs = SkewTableau([]).row_stabilizer()
+ sage: rs.order()
+ 1
+ """
+ # Ensure that the permutations involve all elements of the
+ # tableau, by including the identity permutation on the set [1..k].
+ k = self.size()
+ gens = [list(range(1, k + 1))]
+ for row in self:
+ for j in range(len(row) - 1):
+ if row[j] is not None:
+ gens.append((row[j], row[j + 1]))
+ return PermutationGroup(gens)
+
+ def column_stabilizer(self):
+ """
+ Return the :func:`PermutationGroup` corresponding to the column stabilizer
+ of ``self``.
+
+ This assumes that every integer from `1` to the size of ``self``
+ appears exactly once in ``self``.
+
+ EXAMPLES::
+
+ sage: # needs sage.groups
+ sage: cs = SkewTableau([[None,2,3],[1,5],[4]]).column_stabilizer()
+ sage: cs.order() == factorial(2) * factorial(2)
+ True
+ sage: PermutationGroupElement([(1,3,2),(4,5)]) in cs
+ False
+ sage: PermutationGroupElement([(1,4)]) in cs
+ True
+ """
+ # Ensure that the permutations involve all elements of the
+ # tableau, by including the identity permutation on the set [1..k].
+ k = self.size()
+ gens = [list(range(1, k + 1))]
+ ell = len(self)
+ while ell > 1:
+ ell -= 1
+ for i, val in enumerate(self[ell]):
+ top_neighbor = self[ell-1][i]
+ if top_neighbor is not None:
+ gens.append((val, top_neighbor))
+ return PermutationGroup(gens)
+
def shuffle(self, t2):
r"""
Shuffle the standard tableaux ``self`` and ``t2``.
diff --git a/src/sage/combinat/specht_module.py b/src/sage/combinat/specht_module.py
index a0c6dad9172..5b8462754ef 100644
--- a/src/sage/combinat/specht_module.py
+++ b/src/sage/combinat/specht_module.py
@@ -850,6 +850,102 @@ def simple_module(self):
return self
return SimpleModule(self)
+ def intrinsic_arrangement(self, base_ring=None):
+ r"""
+ Return the intrinsic arrangement of ``self``.
+
+ Consider the Specht module `S^{\lambda}` with `\lambda` a
+ (integer) partition of `n` (i.e., `S^{\lambda}` is an `S_n`-module).
+ The *intrinsic arrangement* of `S^{\lambda}` is the central hyperplane
+ arrangement in `S^{\lambda}` given by the hyperplanes `H_{\alpha}`,
+ indexed by a set partition `\alpha` of `\{1, \ldots, n\}` of size
+ `\lambda`, defined by
+
+ .. MATH::
+
+ H_{\alpha} := \bigoplus_{\tau \in T_{\alpha}} (S^{\lambda})^{\tau},
+
+ where `T_{\alpha}` is some set of generating transpositions
+ of the Young subgroup `S_{\alpha}` and `V^{\tau}` denotes the
+ `\tau`-invariant subspace of `V`. (These hyperplanes do not
+ depend on the choice of `T_{\alpha}`.)
+
+ This was introduced in [TVY2020]_ as a generalization of the
+ braid arrangement, which is the case when `\lambda = (n-1, 1)`
+ (equivalently, for the irreducible representation of `S_n`
+ given by the type `A_{n-1}` root system).
+
+ EXAMPLES::
+
+ sage: SGA = SymmetricGroupAlgebra(QQ, 4)
+ sage: SM = SGA.specht_module([2, 1, 1])
+ sage: A = SM.intrinsic_arrangement()
+ sage: A.hyperplanes()
+ (Hyperplane T0 - T1 - 3*T2 + 0,
+ Hyperplane T0 - T1 + T2 + 0,
+ Hyperplane T0 + 3*T1 + T2 + 0,
+ Hyperplane 3*T0 + T1 - T2 + 0)
+ sage: A.is_free()
+ False
+
+ We reproduce Example 3 of [TVY2020]_::
+
+ sage: SGA = SymmetricGroupAlgebra(QQ, 5)
+ sage: for la in Partitions(5):
+ ....: SM = SGA.specht_module(la)
+ ....: A = SM.intrinsic_arrangement()
+ ....: print(la, A.characteristic_polynomial())
+ [5] 1
+ [4, 1] x^4 - 10*x^3 + 35*x^2 - 50*x + 24
+ [3, 2] x^5 - 15*x^4 + 90*x^3 - 260*x^2 + 350*x - 166
+ [3, 1, 1] x^6 - 10*x^5 + 45*x^4 - 115*x^3 + 175*x^2 - 147*x + 51
+ [2, 2, 1] x^5 - 10*x^4 + 45*x^3 - 105*x^2 + 120*x - 51
+ [2, 1, 1, 1] x^4 - 5*x^3 + 10*x^2 - 10*x + 4
+ [1, 1, 1, 1, 1] 1
+
+ sage: A = SGA.specht_module([4, 1]).intrinsic_arrangement()
+ sage: A.characteristic_polynomial().factor()
+ (x - 4) * (x - 3) * (x - 2) * (x - 1)
+ """
+ from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements
+ from sage.combinat.set_partition import SetPartitions
+ if base_ring is None:
+ base_ring = self.base_ring()
+
+ if self.dimension() == 1: # corner case
+ HA = HyperplaneArrangements(base_ring, 'T')
+ return HA()
+
+ SGA = self._semigroup_algebra
+ G = self._semigroup
+
+ def t(i, j):
+ ret = [i for i in range(1, SGA.n+1)]
+ ret[i-1] = j
+ ret[j-1] = i
+ return SGA(G(ret))
+
+ # Construct the hyperplanes
+ fixed_spaces = {}
+ norms = []
+ for alpha in SetPartitions(SGA.n, self._diagram.conjugate()):
+ span = []
+ for a in alpha:
+ a = list(a)
+ for i in range(len(a)-1):
+ elt = t(a[i], a[i+1])
+ if elt not in fixed_spaces:
+ fixed_spaces[elt] = self.annihilator_basis([elt - SGA.one()], side='left')
+ span.extend(fixed_spaces[elt])
+ H = self.echelon_form(span)
+ N = matrix([v.to_vector() for v in H]).right_kernel_matrix()
+ assert N.nrows() == 1
+ norms.append(N[0])
+
+ # Convert the data to an arrangement
+ HA = HyperplaneArrangements(base_ring, tuple([f'T{i}' for i in range(self.dimension())]))
+ return HA([[0] + list(N) for N in norms])
+
class MaximalSpechtSubmodule(SymmetricGroupRepresentation, SubmoduleWithBasis):
r"""
diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py
index 963dc8a221b..1706f848f10 100644
--- a/src/sage/combinat/symmetric_group_algebra.py
+++ b/src/sage/combinat/symmetric_group_algebra.py
@@ -18,6 +18,7 @@
from sage.combinat.permutation_cython import (left_action_same_n, right_action_same_n)
from sage.combinat.partition import _Partitions, Partitions, Partitions_n
from sage.combinat.tableau import Tableau, StandardTableaux_size, StandardTableaux_shape, StandardTableaux
+from sage.combinat.skew_tableau import SkewTableau
from sage.algebras.group_algebra import GroupAlgebra_class
from sage.algebras.cellular_basis import CellularBasis
from sage.categories.weyl_groups import WeylGroups
@@ -139,7 +140,7 @@ def SymmetricGroupAlgebra(R, W, category=None):
This allows for mixed expressions::
- sage: x4 = 3*QS4([3, 1, 4, 2])
+ sage: x4 = 3 * QS4([3, 1, 4, 2])
sage: x3 + x4
2*[2, 3, 1, 4] + [3, 1, 2, 4] + 3*[3, 1, 4, 2]
@@ -2367,6 +2368,72 @@ def _row_stabilizer(self, la):
G = self.group()
return self.sum_of_monomials(G(list(w.tuple())) for w in la.young_subgroup())
+ @cached_method
+ def _column_antistabilizer(self, la):
+ """
+ Return the column antistabilizer element of a canonical standard tableau
+ of shape ``la``.
+
+ EXAMPLES::
+
+ sage: SGA = SymmetricGroupAlgebra(QQ, 3)
+ sage: for la in Partitions(3):
+ ....: print(la, SGA._column_antistabilizer(la))
+ [3] [1, 2, 3]
+ [2, 1] [1, 2, 3] - [3, 2, 1]
+ [1, 1, 1] [1, 2, 3] - [1, 3, 2] - [2, 1, 3] + [2, 3, 1] + [3, 1, 2] - [3, 2, 1]
+ """
+ T = []
+ total = 1 # make it 1-based
+ for r in la:
+ T.append(list(range(total, total+r)))
+ total += r
+ T = Tableau(T)
+ G = self.group()
+ R = self.base_ring()
+ return self._from_dict({G(list(w.tuple())): R(w.sign()) for w in T.column_stabilizer()},
+ remove_zeros=False)
+
+ @cached_method
+ def _young_symmetrizer(self, la):
+ """
+ Return the Young symmetrizer of shape ``la`` of ``self``.
+
+ EXAMPLES::
+
+ sage: SGA = SymmetricGroupAlgebra(QQ, 3)
+ sage: for la in Partitions(3):
+ ....: print(la, SGA._young_symmetrizer(la))
+ [3] [1, 2, 3] + [1, 3, 2] + [2, 1, 3] + [2, 3, 1] + [3, 1, 2] + [3, 2, 1]
+ [2, 1] [1, 2, 3] + [2, 1, 3] - [3, 1, 2] - [3, 2, 1]
+ [1, 1, 1] [1, 2, 3] - [1, 3, 2] - [2, 1, 3] + [2, 3, 1] + [3, 1, 2] - [3, 2, 1]
+ """
+ return self._column_antistabilizer(la) * self._row_stabilizer(la)
+
+ def young_symmetrizer(self, la):
+ """
+ Return the Young symmetrizer of shape ``la`` of ``self``.
+
+ EXAMPLES::
+
+ sage: SGA = SymmetricGroupAlgebra(QQ, SymmetricGroup(3))
+ sage: SGA.young_symmetrizer([2,1])
+ () + (1,2) - (1,3,2) - (1,3)
+ sage: SGA = SymmetricGroupAlgebra(QQ, 4)
+ sage: SGA.young_symmetrizer([2,1,1])
+ [1, 2, 3, 4] - [1, 2, 4, 3] + [2, 1, 3, 4] - [2, 1, 4, 3]
+ - [3, 1, 2, 4] + [3, 1, 4, 2] - [3, 2, 1, 4] + [3, 2, 4, 1]
+ + [4, 1, 2, 3] - [4, 1, 3, 2] + [4, 2, 1, 3] - [4, 2, 3, 1]
+ sage: SGA.young_symmetrizer([5,1,1])
+ Traceback (most recent call last):
+ ...
+ ValueError: the partition [5, 1, 1] is not of size 4
+ """
+ la = _Partitions(la)
+ if la.size() != self.n:
+ raise ValueError("the partition {} is not of size {}".format(la, self.n))
+ return self._young_symmetrizer(la)
+
def kazhdan_lusztig_cellular_basis(self):
r"""
Return the Kazhdan-Lusztig basis (at `q = 1`) of ``self``
@@ -2542,23 +2609,32 @@ def pi_ik(itab, ktab):
algebra.
This assumes that ``itab`` and ``ktab`` are tableaux (possibly
- given just as lists of lists) of the same shape.
+ given just as lists of lists) of the same shape. Both
+ tableaux are allowed to be skew.
EXAMPLES::
sage: from sage.combinat.symmetric_group_algebra import pi_ik
sage: pi_ik([[1,3],[2]], [[1,2],[3]])
[1, 3, 2]
+
+ The same with skew tableaux::
+
+ sage: from sage.combinat.symmetric_group_algebra import pi_ik
+ sage: pi_ik([[None,1,3],[2]], [[None,1,2],[3]])
+ [1, 3, 2]
"""
- it = Tableau(itab)
- kt = Tableau(ktab)
+ it = SkewTableau(itab)
+ kt = SkewTableau(ktab)
+ n = kt.size()
- p = [None] * kt.size()
+ p = [None] * n
for i in range(len(kt)):
for j in range(len(kt[i])):
- p[it[i][j] - 1] = kt[i][j]
+ if it[i][j] is not None:
+ p[it[i][j] - 1] = kt[i][j]
- QSn = SymmetricGroupAlgebra(QQ, it.size())
+ QSn = SymmetricGroupAlgebra(QQ, n)
p = Permutation(p)
return QSn(p)
@@ -2637,8 +2713,13 @@ def a(tableau, star=0, base_ring=QQ):
[1, 2, 3, 4, 5] + [1, 3, 2, 4, 5] + [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1]
sage: a([[1,4], [2,3]], base_ring=ZZ)
[1, 2, 3, 4] + [1, 3, 2, 4] + [4, 2, 3, 1] + [4, 3, 2, 1]
+
+ The same with a skew tableau::
+
+ sage: a([[None,1,4], [2,3]], base_ring=ZZ)
+ [1, 2, 3, 4] + [1, 3, 2, 4] + [4, 2, 3, 1] + [4, 3, 2, 1]
"""
- t = Tableau(tableau)
+ t = SkewTableau(tableau)
if star:
t = t.restrict(t.size() - star)
@@ -2654,7 +2735,7 @@ def a(tableau, star=0, base_ring=QQ):
# being [1] rather than [] (which seems to have its origins in
# permutation group code).
# TODO: Fix this.
- if len(tableau) == 0:
+ if n <= 1:
return sgalg.one()
rd = dict((P(h), one) for h in rs)
@@ -2708,6 +2789,11 @@ def b(tableau, star=0, base_ring=QQ):
sage: b([[1, 4], [2, 3]], base_ring=Integers(5))
[1, 2, 3, 4] + 4*[1, 2, 4, 3] + 4*[2, 1, 3, 4] + [2, 1, 4, 3]
+ The same with a skew tableau::
+
+ sage: b([[None, 2, 4], [1, 3], [5]])
+ [1, 2, 3, 4, 5] - [1, 3, 2, 4, 5] - [5, 2, 3, 4, 1] + [5, 3, 2, 4, 1]
+
With the ``l2r`` setting for multiplication, the unnormalized
Young symmetrizer ``e(tableau)`` should be the product
``b(tableau) * a(tableau)`` for every ``tableau``. Let us check
@@ -2717,7 +2803,7 @@ def b(tableau, star=0, base_ring=QQ):
sage: all( e(t) == b(t) * a(t) for t in StandardTableaux(5) )
True
"""
- t = Tableau(tableau)
+ t = SkewTableau(tableau)
if star:
t = t.restrict(t.size() - star)
@@ -2733,7 +2819,7 @@ def b(tableau, star=0, base_ring=QQ):
# being [1] rather than [] (which seems to have its origins in
# permutation group code).
# TODO: Fix this.
- if len(tableau) == 0:
+ if n <= 1:
return sgalg.one()
cd = dict((P(v), v.sign() * one) for v in cs)
@@ -2793,6 +2879,12 @@ def e(tableau, star=0):
sage: QS3.antipode(e([[1,2],[3]]))
[1, 2, 3] + [2, 1, 3] - [2, 3, 1] - [3, 2, 1]
+ And here is an example for a skew tableau::
+
+ sage: e([[None, 2, 1], [4, 3]])
+ [1, 2, 3, 4] + [1, 2, 4, 3] - [1, 3, 2, 4] - [1, 4, 2, 3]
+ + [2, 1, 3, 4] + [2, 1, 4, 3] - [2, 3, 1, 4] - [2, 4, 1, 3]
+
.. SEEALSO::
:func:`e_hat`
@@ -2802,7 +2894,7 @@ def e(tableau, star=0):
# a way to compute them over other base rings as well. Be careful
# with the cache.
- t = Tableau(tableau)
+ t = SkewTableau(tableau)
if star:
t = t.restrict(t.size() - star)
@@ -2830,8 +2922,8 @@ def e(tableau, star=0):
# being [1] rather than [] (which seems to have its origins in
# permutation group code).
# TODO: Fix this.
- if not tableau:
- res = QSn.one()
+ if n <= 1:
+ return QSn.one()
e_cache[t] = res
@@ -2889,7 +2981,10 @@ def e_hat(tab, star=0):
:func:`e`
"""
- t = Tableau(tab)
+ t = SkewTableau(tab)
+ # This is for consistency's sake. This method is NOT meant
+ # to be applied to skew tableaux, since the meaning of
+ # \kappa is unclear in that case.
if star:
t = t.restrict(t.size() - star)
if t in ehat_cache:
@@ -2912,8 +3007,8 @@ def e_ik(itab, ktab, star=0):
sage: e_ik([[1,2,3]], [[1,2,3]], star=1)
[1, 2] + [2, 1]
"""
- it = Tableau(itab)
- kt = Tableau(ktab)
+ it = SkewTableau(itab)
+ kt = SkewTableau(ktab)
if star:
it = it.restrict(it.size() - star)
kt = kt.restrict(kt.size() - star)
diff --git a/src/sage/combinat/words/all.py b/src/sage/combinat/words/all.py
index 8d5798c549c..66a2fa38719 100644
--- a/src/sage/combinat/words/all.py
+++ b/src/sage/combinat/words/all.py
@@ -43,11 +43,16 @@
from sage.misc.namespace_package import install_doc
install_doc(__package__, __doc__)
+from sage.misc.lazy_import import lazy_import
+
from sage.combinat.words.alphabet import Alphabet, build_alphabet
from sage.combinat.words.morphism import WordMorphism
-from sage.combinat.words.paths import WordPaths
+lazy_import('sage.combinat.words.paths', 'WordPaths')
from sage.combinat.words.word import Word
from sage.combinat.words.word_options import WordOptions
from sage.combinat.words.word_generators import words
from sage.combinat.words.words import Words, FiniteWords, InfiniteWords
from sage.combinat.words.lyndon_word import LyndonWord, LyndonWords, StandardBracketedLyndonWords
+
+del install_doc
+del lazy_import
diff --git a/src/sage/databases/symbolic_data.py b/src/sage/databases/symbolic_data.py
index 4d63d26cdc1..0c6c4fbfc0a 100644
--- a/src/sage/databases/symbolic_data.py
+++ b/src/sage/databases/symbolic_data.py
@@ -153,7 +153,7 @@ def _dom2ideal(node):
name = self.__genpath + name + ".xml"
open(name)
except OSError:
- raise AttributeError("No ideal matching '%s' found in database." % orig_name)
+ raise AttributeError(f"no ideal matching '{orig_name}' found in database")
dom = parse(name)
res = _dom2ideal(dom)
@@ -184,7 +184,7 @@ def __getattr__(self, name):
sage: sd.Cyclic5 # optional - database_symbolic_data
Traceback (most recent call last):
...
- AttributeError: No ideal matching 'Cyclic5' found in database.
+ AttributeError: no ideal matching 'Cyclic5' found in database...
sage: sd.Cyclic_5 # optional - database_symbolic_data
Ideal (v + w + x + y + z,
diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py
index 069e03c197d..7e9eab2ff2e 100644
--- a/src/sage/doctest/forker.py
+++ b/src/sage/doctest/forker.py
@@ -1579,6 +1579,7 @@ def report_unexpected_exception(self, out, test, example, exc_info):
EXAMPLES::
+ sage: from sage.interfaces.sage0 import sage0
sage: sage0.quit()
sage: _ = sage0.eval("import doctest, sys, os, multiprocessing, subprocess")
sage: _ = sage0.eval("from sage.doctest.parsing import SageOutputChecker")
diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py
index a1e4bc1700d..2b9dd28b13b 100644
--- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py
+++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py
@@ -45,7 +45,7 @@ class initialization directly.
from sage.rings.integer import Integer
from sage.rings.finite_rings.finite_field_base import FiniteField
from sage.rings.fraction_field import FractionField
-from sage.rings.fraction_field import is_FractionField
+from sage.rings.fraction_field import FractionField_generic
from sage.rings.quotient_ring import is_QuotientRing
from sage.schemes.affine.affine_morphism import SchemeMorphism_polynomial_affine_space
from sage.schemes.affine.affine_morphism import SchemeMorphism_polynomial_affine_space_field
@@ -261,7 +261,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None):
polys = [morphism_or_polys]
PR = get_coercion_model().common_parent(*polys)
- fraction_field = any(is_FractionField(poly.parent()) for poly in polys)
+ fraction_field = any(isinstance(poly.parent(), FractionField_generic) for poly in polys)
if fraction_field:
K = PR.base_ring().fraction_field()
# Replace base ring with its fraction field
diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py
index 4b3ebd0d89a..a04cf57a28d 100644
--- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py
+++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py
@@ -87,8 +87,8 @@ class initialization directly.
from sage.rings.finite_rings.finite_field_base import FiniteField
from sage.rings.finite_rings.finite_field_constructor import GF
from sage.rings.finite_rings.integer_mod_ring import Zmod
-from sage.rings.fraction_field import (FractionField, is_FractionField, FractionField_1poly_field)
-from sage.rings.fraction_field_element import is_FractionFieldElement, FractionFieldElement
+from sage.rings.fraction_field import FractionField, FractionField_generic, FractionField_1poly_field
+from sage.rings.fraction_field_element import FractionFieldElement
from sage.rings.function_field.function_field import is_FunctionField
from sage.rings.integer import Integer
from sage.rings.integer_ring import ZZ
@@ -394,11 +394,11 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None):
# homogenize!
f = morphism_or_polys
aff_CR = f.parent()
- if (not is_PolynomialRing(aff_CR) and not is_FractionField(aff_CR)
+ if (not is_PolynomialRing(aff_CR) and not isinstance(aff_CR, FractionField_generic)
and not (is_MPolynomialRing(aff_CR) and aff_CR.ngens() == 1)):
msg = '{} is not a single variable polynomial or rational function'
raise ValueError(msg.format(f))
- if is_FractionField(aff_CR):
+ if isinstance(aff_CR, FractionField_generic):
polys = [f.numerator(),f.denominator()]
else:
polys = [f, aff_CR(1)]
@@ -889,7 +889,7 @@ def dynatomic_polynomial(self, period):
# do it again to divide out by denominators of coefficients
PHI = QR2[0].sage()
PHI = PHI.numerator()._maxima_().divide(PHI.denominator())[0].sage()
- if not is_FractionFieldElement(PHI):
+ if not isinstance(PHI, FractionFieldElement):
from sage.symbolic.expression_conversions import polynomial
PHI = polynomial(PHI, ring=self.coordinate_ring())
except (TypeError, NotImplementedError): #something Maxima, or the conversion, can't handle
@@ -3533,7 +3533,7 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False):
if hyperplane_found:
break
else:
- if is_PolynomialRing(R) or is_MPolynomialRing(R) or is_FractionField(R):
+ if is_PolynomialRing(R) or is_MPolynomialRing(R) or isinstance(R, FractionField_generic):
# for polynomial rings, we can get an infinite family of hyperplanes
# by increasing the degree
var = R.gen()
@@ -3702,7 +3702,7 @@ def automorphism_group(self, **kwds):
raise NotImplementedError("rational function of degree 1 not implemented")
f = self.dehomogenize(1)
R = PolynomialRing(f.base_ring(),'x')
- if is_FractionFieldElement(f[0]):
+ if isinstance(f[0], FractionFieldElement):
F = (f[0].numerator().univariate_polynomial(R))/f[0].denominator().univariate_polynomial(R)
else:
F = f[0].univariate_polynomial(R)
@@ -4880,7 +4880,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari
if isinstance(R, FractionField_1poly_field) or is_FunctionField(R):
raise NotImplementedError('periodic points not implemented for fraction function fields; '
'clear denominators and use the polynomial ring instead')
- if is_FractionField(R):
+ if isinstance(R, FractionField_generic):
if is_MPolynomialRing(R.ring()):
raise NotImplementedError('periodic points not implemented for fraction function fields; '
'clear denominators and use the polynomial ring instead')
@@ -5784,7 +5784,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point',
X = X.change_ring(F)
else:
F = base_ring
- if is_FractionField(base_ring):
+ if isinstance(base_ring, FractionField_generic):
if is_MPolynomialRing(base_ring.ring()) or is_PolynomialRing(base_ring.ring()):
f.normalize_coordinates()
f_ring = f.change_ring(base_ring.ring())
@@ -5886,7 +5886,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point',
return sigmas
base_ring = dom.base_ring()
- if is_FractionField(base_ring):
+ if isinstance(base_ring, FractionField_generic):
base_ring = base_ring.ring()
if (is_PolynomialRing(base_ring) or is_MPolynomialRing(base_ring)):
base_ring = base_ring.base_ring()
diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py
index 00eb7d473eb..8ceb38d0cec 100644
--- a/src/sage/dynamics/complex_dynamics/mandel_julia.py
+++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py
@@ -51,7 +51,7 @@
from sage.schemes.projective.projective_space import ProjectiveSpace
from sage.misc.prandom import randint
from sage.calculus.var import var
-from sage.rings.fraction_field import is_FractionField
+from sage.rings.fraction_field import FractionField_generic
from sage.categories.function_fields import FunctionFields
lazy_import('sage.dynamics.arithmetic_dynamics.generic_ds', 'DynamicalSystem')
@@ -243,14 +243,14 @@ def mandelbrot_plot(f=None, **kwds):
P = f.parent()
if P.base_ring() is CC or P.base_ring() is CDF:
- if is_FractionField(P):
+ if isinstance(P, FractionField_generic):
raise NotImplementedError("coefficients must be polynomials in the parameter")
gen_list = list(P.gens())
parameter = gen_list.pop(gen_list.index(parameter))
variable = gen_list.pop()
elif P.base_ring().base_ring() is CC or P.base_ring().base_ring() is CDF:
- if is_FractionField(P.base_ring()):
+ if isinstance(P.base_ring(), FractionField_generic):
raise NotImplementedError("coefficients must be polynomials in the parameter")
phi = P.flattening_morphism()
f = phi(f)
diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx
index 2cb446886e1..479589dc0e3 100644
--- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx
+++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx
@@ -34,7 +34,7 @@ from sage.ext.fast_callable import fast_callable
from sage.calculus.all import symbolic_expression
from sage.symbolic.ring import SR
from sage.calculus.var import var
-from sage.rings.fraction_field import is_FractionField
+from sage.rings.fraction_field import FractionField_generic
from sage.categories.function_fields import FunctionFields
from cypari2.handle_error import PariError
from math import sqrt
@@ -709,14 +709,14 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0,
P = f.parent()
if P.base_ring() is CC:
- if is_FractionField(P):
+ if isinstance(P, FractionField_generic):
raise NotImplementedError("coefficients must be polynomials in the parameter")
gen_list = list(P.gens())
parameter = gen_list.pop(gen_list.index(parameter))
variable = gen_list.pop()
elif P.base_ring().base_ring() is CC:
- if is_FractionField(P.base_ring()):
+ if isinstance(P.base_ring(), FractionField_generic):
raise NotImplementedError("coefficients must be polynomials in the parameter")
phi = P.flattening_morphism()
f = phi(f)
diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py
index a5d5ff3c409..df76ec9da99 100644
--- a/src/sage/features/__init__.py
+++ b/src/sage/features/__init__.py
@@ -606,7 +606,7 @@ class FileFeature(Feature):
To work with the file described by the feature, use the method :meth:`absolute_filename`.
A :class:`FeatureNotPresentError` is raised if the file cannot be found::
- sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").absolute_path()
+ sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").absolute_filename()
Traceback (most recent call last):
...
sage.features.FeatureNotPresentError: does-not-exist is not available.
@@ -654,32 +654,6 @@ def absolute_filename(self) -> str:
# the distribution sagemath-environment.
raise NotImplementedError
- def absolute_path(self):
- r"""
- Deprecated alias for :meth:`absolute_filename`.
-
- Deprecated to make way for a method of this name returning a ``Path``.
-
- EXAMPLES::
-
- sage: from sage.features import Executable
- sage: Executable(name="sh", executable="sh").absolute_path()
- doctest:warning...
- DeprecationWarning: method absolute_path has been replaced by absolute_filename
- See https://github.com/sagemath/sage/issues/31292 for details.
- '/...bin/sh'
- """
- try:
- from sage.misc.superseded import deprecation
- except ImportError:
- # The import can fail because sage.misc.superseded is provided by
- # the distribution sagemath-objects, which is not an
- # install-requires of the distribution sagemath-environment.
- pass
- else:
- deprecation(31292, 'method absolute_path has been replaced by absolute_filename')
- return self.absolute_filename()
-
class Executable(FileFeature):
r"""
@@ -764,7 +738,7 @@ def absolute_filename(self) -> str:
A :class:`FeatureNotPresentError` is raised if the file cannot be found::
- sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").absolute_path()
+ sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").absolute_filename()
Traceback (most recent call last):
...
sage.features.FeatureNotPresentError: does-not-exist is not available.
diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py
index afb41e7f227..fd993e90e1b 100644
--- a/src/sage/features/join_feature.py
+++ b/src/sage/features/join_feature.py
@@ -98,36 +98,6 @@ def _is_present(self):
return test
return FeatureTestResult(self, True)
- def is_functional(self):
- r"""
- Test whether the join feature is functional.
-
- This method is deprecated. Use :meth:`Feature.is_present` instead.
-
- EXAMPLES::
-
- sage: from sage.features.latte import Latte
- sage: Latte().is_functional() # optional - latte_int
- doctest:warning...
- DeprecationWarning: method JoinFeature.is_functional; use is_present instead
- See https://github.com/sagemath/sage/issues/33114 for details.
- FeatureTestResult('latte_int', True)
- """
- try:
- from sage.misc.superseded import deprecation
- except ImportError:
- # The import can fail because sage.misc.superseded is provided by
- # the distribution sagemath-objects, which is not an
- # install-requires of the distribution sagemath-environment.
- pass
- else:
- deprecation(33114, 'method JoinFeature.is_functional; use is_present instead')
- for f in self._features:
- test = f.is_functional()
- if not test:
- return test
- return FeatureTestResult(self, True)
-
def hide(self):
r"""
Hide this feature and all its joined features.
diff --git a/src/sage/features/standard.py b/src/sage/features/standard.py
index 94272802aad..c4055263e79 100644
--- a/src/sage/features/standard.py
+++ b/src/sage/features/standard.py
@@ -33,5 +33,6 @@ def all_features():
PythonModule('ptyprocess', spkg='ptyprocess', type='standard'),
PythonModule('pyparsing', spkg='pyparsing', type='standard'),
PythonModule('requests', spkg='requests', type='standard'),
+ PythonModule('rpy2', spkg='rpy2', type='standard'),
PythonModule('scipy', spkg='scipy', type='standard'),
PythonModule('sympy', spkg='sympy', type='standard')]
diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py
index 1c657f5b8b3..3dcb446e706 100644
--- a/src/sage/functions/transcendental.py
+++ b/src/sage/functions/transcendental.py
@@ -28,10 +28,10 @@
lazy_import('sage.combinat.combinat', 'bernoulli_polynomial')
lazy_import('sage.rings.cc', 'CC')
-lazy_import('sage.rings.complex_mpfr', ['ComplexField', 'is_ComplexNumber'])
+lazy_import('sage.rings.complex_mpfr', ['ComplexField', 'ComplexNumber'])
lazy_import('sage.rings.polynomial.polynomial_real_mpfr_dense', 'PolynomialRealDense')
lazy_import('sage.rings.real_double', 'RDF')
-lazy_import('sage.rings.real_mpfr', ['RR', 'RealField', 'is_RealNumber'])
+lazy_import('sage.rings.real_mpfr', ['RR', 'RealField', 'RealNumber'])
lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call')
lazy_import('mpmath', 'zeta', as_='_mpmath_zeta')
@@ -452,7 +452,7 @@ def zeta_symmetric(s):
- I copied the definition of xi from
http://web.viu.ca/pughg/RiemannZeta/RiemannZetaLong.html
"""
- if not (is_ComplexNumber(s) or is_RealNumber(s)):
+ if not (isinstance(s, ComplexNumber) or isinstance(s, RealNumber)):
s = ComplexField()(s)
R = s.parent()
@@ -544,7 +544,7 @@ def _eval_(self, x):
sage: dickman_rho(0) # needs sage.symbolic
1.00000000000000
"""
- if not is_RealNumber(x):
+ if not isinstance(x, RealNumber):
try:
x = RR(x)
except (TypeError, ValueError):
diff --git a/src/sage/game_theory/matching_game.py b/src/sage/game_theory/matching_game.py
index 11c04f6e5b1..8efa2c2acfa 100644
--- a/src/sage/game_theory/matching_game.py
+++ b/src/sage/game_theory/matching_game.py
@@ -1,3 +1,4 @@
+# sage.doctest: needs sage.graphs
"""
Matching games
@@ -124,7 +125,7 @@ class MatchingGame(SageObject):
Matchings have a natural representations as bipartite graphs::
- sage: plot(m)
+ sage: plot(m) # needs sage.plot
Graphics object consisting of 13 graphics primitives
The above plots the bipartite graph associated with the matching.
@@ -508,14 +509,14 @@ def plot(self):
sage: revr = {3: (0, 1),
....: 4: (1, 0)}
sage: g = MatchingGame([suit, revr])
- sage: plot(g)
+ sage: plot(g) # needs sage.plot
Traceback (most recent call last):
...
ValueError: game has not been solved yet
sage: g.solve()
{0: 3, 1: 4}
- sage: plot(g)
+ sage: plot(g) # needs sage.plot
Graphics object consisting of 7 graphics primitives
"""
pl = self.bipartite_graph()
diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py
index e2220fc7f0a..2b1e592c4e8 100644
--- a/src/sage/game_theory/normal_form_game.py
+++ b/src/sage/game_theory/normal_form_game.py
@@ -157,11 +157,11 @@
`(Ay)_i`, ie element in position `i` of the matrix/vector multiplication
`Ay`) ::
- sage: y = var('y')
+ sage: y = var('y') # needs sage.symbolic
sage: A = matrix([[1, -1], [-1, 1]])
- sage: p = plot((A * vector([y, 1 - y]))[0], y, 0, 1, color='blue',
+ sage: p = plot((A * vector([y, 1 - y]))[0], y, 0, 1, color='blue', # needs sage.symbolic
....: legend_label='$u_1(r_1, (y, 1-y))$', axes_labels=['$y$', ''])
- sage: p += plot((A * vector([y, 1 - y]))[1], y, 0, 1, color='red',
+ sage: p += plot((A * vector([y, 1 - y]))[1], y, 0, 1, color='red', # needs sage.symbolic
....: legend_label='$u_1(r_2, (y, 1-y))$'); p
Graphics object consisting of 2 graphics primitives
diff --git a/src/sage/games/all.py b/src/sage/games/all.py
index be1a1f2cbfc..d2b0648440e 100644
--- a/src/sage/games/all.py
+++ b/src/sage/games/all.py
@@ -1,2 +1,6 @@
-from sage.games.sudoku import Sudoku, sudoku
-from sage.games.hexad import Minimog
+
+from sage.misc.lazy_import import lazy_import
+
+lazy_import('sage.games.sudoku', ['Sudoku', 'sudoku'])
+lazy_import('sage.games.hexad', ['Minimog'])
+del lazy_import
diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py
index ccbb9488470..864a9237ee7 100644
--- a/src/sage/geometry/fan.py
+++ b/src/sage/geometry/fan.py
@@ -134,13 +134,13 @@
sage: [cone.ambient_ray_indices() for cone in fan1.cones(2)]
[(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4),
- (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]
+ (2, 4), (3, 4), (0, 5), (1, 5), (3, 5), (4, 5)]
In fact, you do not have to type ``.cones``::
sage: [cone.ambient_ray_indices() for cone in fan1(2)]
[(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4),
- (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]
+ (2, 4), (3, 4), (0, 5), (1, 5), (3, 5), (4, 5)]
You may also need to know the inclusion relations between all of the cones of
the fan. In this case check out
@@ -1914,7 +1914,7 @@ def _subdivide_stellar(self, new_rays, verbose):
sage: C = Cone([(1,0,0), (0,1,0), (1,0,1), (0,1,1)])
sage: F = Fan([C]).make_simplicial()
sage: [cone.ambient_ray_indices() for cone in F]
- [(0, 2, 3), (0, 1, 3)]
+ [(0, 1, 3), (0, 2, 3)]
"""
cones = self.generating_cones()
for n, ray in enumerate(new_rays):
@@ -2139,7 +2139,7 @@ def cone_lattice(self):
....: print([f.ambient_ray_indices() for f in l])
[()]
[(0,), (1,), (2,), (3,)]
- [(0, 2), (1, 2), (0, 3), (1, 3)]
+ [(0, 2), (1, 2), (1, 3), (0, 3)]
Let's also consider the cone lattice of a fan generated by a single
cone::
diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py
index 17ae3a25738..533f7ac1151 100644
--- a/src/sage/geometry/hyperplane_arrangement/arrangement.py
+++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py
@@ -952,11 +952,19 @@ def characteristic_polynomial(self):
....: m_perm = matrix(m_perm).transpose()
....: charpoly = H(m_perm.rows()).characteristic_polynomial()
....: assert charpoly == expected_charpoly
+
+ Check the corner case of the empty arrangement::
+
+ sage: E = H()
+ sage: E.characteristic_polynomial()
+ 1
"""
from sage.rings.polynomial.polynomial_ring import polygen
x = polygen(QQ, 'x')
if self.rank() == 1:
return x**(self.dimension() - 1) * (x - len(self))
+ if self.rank() == 0:
+ return x ** 0
H = self[0]
R = self.restriction(H)
diff --git a/src/sage/geometry/integral_points.pxi b/src/sage/geometry/integral_points.pxi
index 649eb281a1c..327855b6a57 100644
--- a/src/sage/geometry/integral_points.pxi
+++ b/src/sage/geometry/integral_points.pxi
@@ -948,7 +948,7 @@ cdef class Inequality_int:
'integer: (2, 3, 7) x + -5 >= 0'
"""
s = 'integer: ('
- s += ', '.join([str(self.A[i]) for i in range(self.dim)])
+ s += ', '.join(str(self.A[i]) for i in range(self.dim))
s += ') x + ' + str(self.b) + ' >= 0'
return s
diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py
index 8c2d0418595..d37888416b5 100644
--- a/src/sage/geometry/toric_lattice.py
+++ b/src/sage/geometry/toric_lattice.py
@@ -1163,7 +1163,7 @@ def _repr_(self):
"""
s = 'Sublattice '
s += '<'
- s += ', '.join(map(str,self.basis()))
+ s += ', '.join(map(str, self.basis()))
s += '>'
return s
@@ -1186,7 +1186,7 @@ def _latex_(self):
\\left(0,\\,4,\\,8\\right)_{L}\\right\\rangle'
"""
s = '\\left\\langle'
- s += ', '.join([ b._latex_() for b in self.basis() ])
+ s += ', '.join(b._latex_() for b in self.basis())
s += '\\right\\rangle'
return s
diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx
index 770ee23fc68..1f8e5a59c73 100644
--- a/src/sage/graphs/base/c_graph.pyx
+++ b/src/sage/graphs/base/c_graph.pyx
@@ -5022,8 +5022,8 @@ cdef inline bint _reorganize_edge(object v, object u, const int modus) noexcept:
- ``modus`` -- integer representing the modus of the iterator:
- ``0`` -- outgoing edges
- ``1`` -- ingoing edges
- - ``3`` -- unsorted edges of an undirected graph
- - ``4`` -- sorted edges of an undirected graph
+ - ``2`` -- unsorted edges of an undirected graph
+ - ``3`` -- sorted edges of an undirected graph
OUTPUT: Boolean according the modus:
@@ -5034,12 +5034,11 @@ cdef inline bint _reorganize_edge(object v, object u, const int modus) noexcept:
"""
if modus == 0:
return False
- if modus == 1 or modus == 2:
- return True
+ elif modus == 3:
+ try:
+ if v <= u:
+ return False
+ except TypeError:
+ pass
- try:
- if v <= u:
- return False
- except TypeError:
- pass
return True
diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx
index 9aff72e066c..abcd0809af1 100644
--- a/src/sage/graphs/base/dense_graph.pyx
+++ b/src/sage/graphs/base/dense_graph.pyx
@@ -97,6 +97,16 @@ from ``CGraph`` (for explanation, refer to the documentation there)::
It also contains the following variables::
cdef binary_matrix_t edges
+
+.. NOTE::
+
+ As the edges are stored as the adjacency matrix of the graph, enumerating
+ the edges of the graph has complexity `O(n^2)` and enumerating the neighbors
+ of a vertex has complexity `O(n)` (where `n` in the size of the bitset
+ active_vertices).
+ So, the class ``DenseGraph`` should be used for graphs such that the number
+ of edges is close to the square of the number of vertices.
+
"""
# ****************************************************************************
diff --git a/src/sage/graphs/base/sparse_graph.pxd b/src/sage/graphs/base/sparse_graph.pxd
index 540a8827801..b47c5df8210 100644
--- a/src/sage/graphs/base/sparse_graph.pxd
+++ b/src/sage/graphs/base/sparse_graph.pxd
@@ -40,8 +40,9 @@ cdef class SparseGraph(CGraph):
cpdef int out_degree(self, int u) noexcept
cpdef int in_degree(self, int u) noexcept
- cdef int out_neighbors_BTNode_unsafe(self, int u, SparseGraphBTNode *** p_pointers) noexcept
- cdef int in_neighbors_BTNode_unsafe(self, int u, SparseGraphBTNode *** p_pointers) noexcept
+ cdef inline int _neighbors_unsafe (self, int u, bint out, int *neighbors, int size) except -2
+
+ cdef inline int _neighbors_BTNode_unsafe (self, int u, bint out, SparseGraphBTNode **res, int size) except -2
cdef inline SparseGraphBTNode* next_out_neighbor_BTNode_unsafe(self, int u, int v) noexcept:
"""
@@ -50,6 +51,13 @@ cdef class SparseGraph(CGraph):
If ``v`` is ``-1`` return the first neighbor of ``u``.
Return ``NULL`` in case there does not exist such an out-neighbor.
+
+ .. WARNING::
+
+ Repeated calls to this function until NULL is returned DOES NOT
+ yield a linear time algorithm in the number of neighbors of u.
+ To list the neighbors of a vertex in linear time, one should use
+ _neighbors_BTNode_unsafe.
"""
return self.next_neighbor_BTNode_unsafe(self.vertices, u, v)
@@ -60,6 +68,13 @@ cdef class SparseGraph(CGraph):
If ``u`` is ``-1`` return the first neighbor of ``v``.
Return ``NULL`` in case there does not exist such an in-neighbor.
+
+ .. WARNING::
+
+ Repeated calls to this function until NULL is returned DOES NOT
+ yield a linear time algorithm in the number of neighbors of u.
+ To list the neighbors of a vertex in linear time, one should use
+ _neighbors_BTNode_unsafe.
"""
return self.next_neighbor_BTNode_unsafe(self.vertices_rev, v, u)
diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx
index ba230427466..3e736bc6461 100644
--- a/src/sage/graphs/base/sparse_graph.pyx
+++ b/src/sage/graphs/base/sparse_graph.pyx
@@ -135,6 +135,8 @@ It also contains the following variables::
cdef int hash_length
cdef int hash_mask
cdef SparseGraphBTNode **vertices
+ cdef SparseGraphBTNode **vertices_rev
+ cdef bint _directed
For each vertex ``u``, a hash table of length ``hash_length`` is instantiated.
An arc ``(u, v)`` is stored at ``u * hash_length + hash(v)`` of the array
@@ -192,6 +194,7 @@ for both of these uses.
from libc.string cimport memset
from cysignals.memory cimport check_malloc, check_allocarray, sig_free
+from memory_allocator cimport MemoryAllocator
from sage.data_structures.bitset_base cimport *
from sage.data_structures.bitset cimport *
@@ -610,42 +613,35 @@ cdef class SparseGraph(CGraph):
# Neighbor functions
###################################
- cdef int out_neighbors_BTNode_unsafe(self, int u, SparseGraphBTNode *** p_pointers) noexcept:
- """
- List the out-neighbors of a vertex as BTNodes
-
- Technically, this function transforms a binary tree into a list. The
- information it returns is a list of pointers toward a
- ``SparseGraphBTNode``, thus a ``SparseGraphBTNode **``.
-
- INPUT:
-
- - ``u`` -- the vertex to consider
-
- - ``p_pointers`` -- a pointer toward a ``SparseGraphBTNode **``, i.e. a
- ``SparseGraphBTNode ***``. When the function terminates,
- ``p_pointers[0]`` points toward a filled ``SparseGraphBTNode **``. It
- returns the length of this array.
-
- .. NOTE::
+ cdef inline int _neighbors_BTNode_unsafe (self, int u, bint out, SparseGraphBTNode **res, int size) except -2:
+ r"""
+ .. WARNING::
- Don't forget to free ``p_pointers[0]`` !
+ This method is for internal use only.
"""
- cdef int num_nbrs = 0
- cdef int degree = self.out_degrees[u]
- if degree == 0:
- p_pointers[0] = NULL
- return 0
- cdef SparseGraphBTNode **pointers = check_allocarray(degree, sizeof(SparseGraphBTNode *))
- p_pointers[0] = pointers
-
- cdef SparseGraphBTNode* v = self.next_out_neighbor_BTNode_unsafe(u, -1)
- while v:
- pointers[num_nbrs] = v
- num_nbrs += 1
- v = self.next_out_neighbor_BTNode_unsafe(u, v.vertex)
+ cdef SparseGraphBTNode** vertices = self.vertices if out else self.vertices_rev
+ cdef int i
+ cdef int n = 0
+ cdef int nr = 0
+ cdef SparseGraphBTNode *c
- return num_nbrs
+ for i in range(u * self.hash_length, (u+1) * self.hash_length):
+ if not vertices[i]:
+ continue
+ else:
+ res[n] = vertices[i]
+ nr = 1
+ while nr > 0 and n < size:
+ c = res[n]
+ n += 1
+ nr -= 1
+ if c.left:
+ res[n+nr] = c.left
+ nr += 1
+ if c.right:
+ res[n+nr] = c.right
+ nr += 1
+ return -1 if nr > 0 else n
cdef inline int next_out_neighbor_unsafe(self, int u, int v, int* l) except -2:
"""
@@ -656,6 +652,13 @@ cdef class SparseGraph(CGraph):
Return ``-1`` in case there does not exist such an out-neighbor.
Set ``l`` to be the label of the first arc.
+
+ .. WARNING::
+
+ Repeated calls to this function until -1 is returned DOES NOT yield
+ a linear time algorithm in the number of neighbors of v.
+ To list the neighbors of a vertex in linear time, one should use
+ out_neighbors_unsafe.
"""
cdef SparseGraphBTNode* next_bt = self.next_out_neighbor_BTNode_unsafe(u, v)
if next_bt:
@@ -677,6 +680,13 @@ cdef class SparseGraph(CGraph):
If ``vertices`` is ``self.vertices`` the out-neighbor is given.
If ``vertices`` is ``self.vertices_rev`` the in-neighbor is given.
+
+ .. WARNING::
+
+ Repeated calls to this function until NULL is returned DOES NOT
+ yield a linear time algorithm in the number of neighbors of u.
+ To list the neighbors of a vertex in linear time, one should use
+ _neighbors_BTNode_unsafe.
"""
cdef int i
cdef int start_i = (u * self.hash_length) + (v & self.hash_mask)
@@ -732,43 +742,6 @@ cdef class SparseGraph(CGraph):
"""
return self.out_degrees[u]
- cdef int in_neighbors_BTNode_unsafe(self, int v, SparseGraphBTNode *** p_pointers) noexcept:
- """
- List the in-neighbors of a vertex as BTNodes
-
- Technically, this function transforms a binary tree into a list. The
- information it returns is a list of pointers toward a
- ``SparseGraphBTNode``, thus a ``SparseGraphBTNode **``.
-
- INPUT:
-
- - ``u`` -- the vertex to consider
-
- - ``p_pointers`` -- a pointer toward a ``SparseGraphBTNode **``, i.e. a
- ``SparseGraphBTNode ***``. When the function terminates,
- ``p_pointers[0]`` points toward a filled ``SparseGraphBTNode **``. It
- returns the length of this array.
-
- .. NOTE::
-
- Don't forget to free ``p_pointers[0]`` !
- """
- cdef int num_nbrs = 0
- cdef int degree = self.in_degrees[v]
- if degree == 0:
- p_pointers[0] = NULL
- return 0
- cdef SparseGraphBTNode **pointers = check_allocarray(degree, sizeof(SparseGraphBTNode *))
- p_pointers[0] = pointers
-
- cdef SparseGraphBTNode* u = self.next_in_neighbor_BTNode_unsafe(v, -1)
- while u:
- pointers[num_nbrs] = u
- num_nbrs += 1
- u = self.next_in_neighbor_BTNode_unsafe(v, u.vertex)
-
- return num_nbrs
-
cdef inline int next_in_neighbor_unsafe(self, int v, int u, int* l) except -2:
"""
Return the next in-neighbor of ``v`` that is greater than ``u``.
@@ -778,6 +751,13 @@ cdef class SparseGraph(CGraph):
Return ``-1`` in case there does not exist such an in-neighbor.
Set ``l`` to be the label of the first arc.
+
+ .. WARNING::
+
+ Repeated calls to this function until -1 is returned DOES NOT yield
+ a linear time algorithm in the number of neighbors of v.
+ To list the neighbors of a vertex in linear time, one should use
+ in_neighbors_unsafe.
"""
cdef SparseGraphBTNode* next_bt = self.next_in_neighbor_BTNode_unsafe(v, u)
if next_bt:
@@ -789,6 +769,27 @@ cdef class SparseGraph(CGraph):
else:
return -1
+ cdef inline int _neighbors_unsafe(self, int u, bint out, int *neighbors, int size) except -2:
+ r"""
+ .. WARNING::
+
+ This method is for internal use only.
+ """
+ cdef int r
+ cdef SparseGraphBTNode **nodes = check_allocarray(size, sizeof(SparseGraphBTNode *))
+
+ r = self._neighbors_BTNode_unsafe(u, out, nodes, size)
+ for i in range(r if r >= 0 else size):
+ neighbors[i] = nodes[i].vertex
+ sig_free(nodes)
+ return r
+
+ cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
+ return self._neighbors_unsafe(u, 1, neighbors, size)
+
+ cdef int in_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
+ return self._neighbors_unsafe(u, 0, neighbors, size)
+
cpdef int in_degree(self, int v) noexcept:
"""
Returns the in-degree of ``v``
@@ -1449,3 +1450,214 @@ cdef class SparseGraphBackend(CGraphBackend):
if not directed and self._directed and v_int != u_int:
self._cg.del_arc_label(v_int, u_int, ll_int)
self._cg.add_arc_label(v_int, u_int, l_int)
+
+ def _iterator_edges(self, object vertices, const bint labels, const int modus=0):
+ """
+ Iterate over the edges incident to a sequence of vertices.
+
+ INPUT:
+
+ - ``vertices`` -- a list of vertex labels
+
+ - ``labels`` -- boolean, whether to return labels as well
+
+ - ``modus`` -- integer representing the modus of the iterator:
+ - ``0`` -- outgoing edges
+ - ``1`` -- ingoing edges
+ - ``2`` -- unsorted edges of an undirected graph
+ - ``3`` -- sorted edges of an undirected graph
+
+ EXAMPLES::
+
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
+ sage: G.add_edge(1, 2, None, False)
+ sage: list(G._iterator_edges(range(9), False, 3))
+ [(1, 2)]
+ sage: list(G._iterator_edges(range(9), True, 3))
+ [(1, 2, None)]
+
+ ::
+
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
+ sage: G.add_edge(1, 2, None, True)
+ sage: list(G.iterator_in_edges([1], False))
+ []
+ sage: list(G.iterator_in_edges([2], False))
+ [(1, 2)]
+ sage: list(G.iterator_in_edges([2], True))
+ [(1, 2, None)]
+
+ ::
+
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
+ sage: G.add_edge(1, 2, None, True)
+ sage: list(G.iterator_out_edges([2], False))
+ []
+ sage: list(G.iterator_out_edges([1], False))
+ [(1, 2)]
+ sage: list(G.iterator_out_edges([1], True))
+ [(1, 2, None)]
+ """
+ cdef object u, v, l, v_copy
+ cdef int u_int, v_int, l_int, foo
+ cdef CGraph cg = self.cg()
+ cdef list b_vertices_2, all_arc_labels
+ cdef FrozenBitset b_vertices
+ cdef bint out = modus == 0
+
+ cdef int vertices_case
+ cdef object it
+
+ cdef int r
+ cdef int maxdegree = 0
+ cdef int *degrees = NULL
+ if out:
+ degrees = cg.out_degrees
+ else:
+ degrees = cg.in_degrees
+ for v_int in range(cg.active_vertices.size):
+ if bitset_in(cg.active_vertices, v_int):
+ maxdegree = max(degrees[v_int], maxdegree)
+ cdef MemoryAllocator mem = MemoryAllocator()
+ cdef SparseGraphBTNode **neighbors = mem.allocarray(maxdegree, sizeof(SparseGraphBTNode *))
+
+ if not isinstance(vertices, list):
+ # ALL edges
+ it = self.iterator_verts(None)
+ vertices_case = 0
+
+ elif not vertices:
+ return
+
+ elif len(vertices) == 1:
+ # One vertex
+ vertices_case = 1
+ v_int = -1
+
+ else:
+ # Several vertices (nonempty list)
+ vertices_case = 2
+ b_vertices_2 = [self.get_vertex_checked(v) for v in vertices]
+ try:
+ b_vertices = FrozenBitset(foo for foo in b_vertices_2 if foo >= 0)
+ except ValueError:
+ # Avoiding "Bitset must not be empty"
+ # in case none of the vertices is active.
+ return
+ it = iter(b_vertices)
+
+ while True:
+ # Think of this as a loop through ``vertices``.
+ # We pick the next vertex according to three cases.
+
+ if vertices_case == 0:
+ # ALL edges
+ try:
+ v = next(it)
+ v_int = self.get_vertex(v)
+ except StopIteration:
+ return
+
+ elif vertices_case == 1:
+ # One vertex
+ if v_int != -1:
+ # Only visit one vertex once.
+ return
+ v = vertices[0]
+ v_int = self.get_vertex_checked(v)
+ if v_int == -1:
+ return
+
+ else:
+ # Several vertices (nonempty list)
+ try:
+ v_int = -1
+ while v_int == -1:
+ v_int = next(it)
+ v = self.vertex_label(v_int)
+ except StopIteration:
+ return
+
+ # WARNING
+ # If you modify this, you must keep in mind the documentation in the
+ # corresponding method in `generic_graph.py` in the method `edge_iterator`.
+ # E.g. code assumes that you can use an iterator to relabel or delete arcs.
+
+ r = self._cg._neighbors_BTNode_unsafe(v_int, out, neighbors, maxdegree)
+ for i in range(r):
+ u_int = neighbors[i].vertex
+ if neighbors[i].number:
+ l_int = 0
+ else:
+ l_int = neighbors[i].labels.label
+ if (modus < 2 or # Do not delete duplicates.
+ vertices_case == 1 or # Only one vertex, so no duplicates.
+ u_int >= v_int or # We visit if u_int >= v_int ...
+ (vertices_case == 2 and
+ u_int < b_vertices.capacity() and
+ not bitset_in(b_vertices._bitset, u_int))): # ... or if u_int is not in ``vertices``.
+ u = self.vertex_label(u_int)
+ if labels:
+ l = self.edge_labels[l_int] if l_int else None
+
+ # Yield the arc/arcs.
+ v_copy = v
+ if _reorganize_edge(v, u, modus):
+ u, v = v, u
+
+ if not self._multiple_edges:
+ if labels:
+ yield (v, u, l)
+ else:
+ yield (v, u)
+ else:
+ if out:
+ all_arc_labels = cg.all_arcs(v_int, u_int)
+ else:
+ all_arc_labels = cg.all_arcs(u_int, v_int)
+
+ for l_int in all_arc_labels:
+ if labels:
+ l = self.edge_labels[l_int] if l_int else None
+ yield (v, u, l)
+ else:
+ yield (v, u)
+ v = v_copy
+
+##############################
+# Functions to simplify edge iterator.
+##############################
+
+cdef inline bint _reorganize_edge(object v, object u, const int modus) noexcept:
+ """
+ Return ``True`` if ``v`` and ``u`` should be exchanged according to the modus.
+
+ INPUT:
+
+ - ``v`` -- vertex
+
+ - ``u`` -- vertex
+
+ - ``modus`` -- integer representing the modus of the iterator:
+ - ``0`` -- outgoing edges
+ - ``1`` -- ingoing edges
+ - ``2`` -- unsorted edges of an undirected graph
+ - ``3`` -- sorted edges of an undirected graph
+
+ OUTPUT: Boolean according the modus:
+
+ - ``modus == 0`` -- ``False``
+ - ``modus == 1`` -- ``True``
+ - ``modus == 2`` -- ``True
+ - ``modus == 3`` -- ``False if v <= u else True``
+ """
+ if modus == 0:
+ return False
+ elif modus == 3:
+ try:
+ if v <= u:
+ return False
+ except TypeError:
+ pass
+
+ return True
diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx
index f74e1b28dec..898b69568d0 100644
--- a/src/sage/graphs/base/static_sparse_graph.pyx
+++ b/src/sage/graphs/base/static_sparse_graph.pyx
@@ -231,11 +231,13 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled=False,
complexity of some methods. More precisely:
- When set to ``True``, the time complexity for initializing ``g`` is in
- `O(m + m\log{m})` and deciding if ``g`` has edge `(u, v)` can be done 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)` but the time complexity for deciding if ``g`` has
+ 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
diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx
index 575c67b2386..c8a321ece81 100644
--- a/src/sage/graphs/convexity_properties.pyx
+++ b/src/sage/graphs/convexity_properties.pyx
@@ -507,8 +507,11 @@ 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))` and
- space complexity in `O(n + m)`.
+ 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``).
INPUT:
@@ -678,10 +681,10 @@ def is_geodetic(G):
Check whether the input (di)graph is geodetic.
A graph `G` is *geodetic* if there exists only one shortest path between
- every pair of its vertices. This can be checked in time `O(nm)` in
- unweighted (di)graphs with `n` nodes and `m` edges. Examples of geodetic
- graphs are trees, cliques and odd cycles. See the
- :wikipedia:`Geodetic_graph` for more details.
+ every pair of its vertices. This can be checked in time `O(nm)` for
+ ``SparseGraph`` and `O(nm+n^2)` for ``DenseGraph`` in unweighted (di)graphs
+ with `n` nodes and `m` edges. Examples of geodetic graphs are trees, cliques
+ and odd cycles. See the :wikipedia:`Geodetic_graph` for more details.
(Di)graphs with multiple edges are not considered geodetic.
diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py
index 6f4e8cac30c..1b650b73a1b 100644
--- a/src/sage/graphs/digraph.py
+++ b/src/sage/graphs/digraph.py
@@ -1202,8 +1202,31 @@ def neighbor_in_iterator(self, vertex):
....: print(a)
1
4
+
+ TESTS:
+
+ With multiple edges, check that the neighbors are listed only once::
+
+ sage: D = DiGraph([[0, 1, 2], [(0, 1), (0, 1), (1, 2) ]],multiedges=True)
+ sage: list(D.neighbor_in_iterator(0))
+ []
+ sage: list(D.neighbor_in_iterator(1))
+ [0]
+ sage: list(D.neighbor_in_iterator(2))
+ [1]
+
+ Check that the iterator lists ``vertex`` in the presence of loop(s):
+
+ sage: D = DiGraph([[0, 1, 2], [(0, 0), (0, 0), (1, 1)]],multiedges=True, loops=True)
+ sage: list(D.neighbor_in_iterator(0))
+ [0]
+ sage: list(D.neighbor_in_iterator(1))
+ [1]
+ sage: list(D.neighbor_in_iterator(2))
+ []
+
"""
- return iter(set(self._backend.iterator_in_nbrs(vertex)))
+ yield from self._backend.iterator_in_nbrs(vertex)
def neighbors_in(self, vertex):
"""
@@ -1233,8 +1256,31 @@ def neighbor_out_iterator(self, vertex):
1
2
3
+
+ TESTS:
+
+ With multiple edges, check that the neighbors are listed only once::
+
+ sage: D = DiGraph([[0, 1, 2], [(0, 1), (0, 1), (1, 2) ]],multiedges=True)
+ sage: list(D.neighbor_out_iterator(0))
+ [1]
+ sage: list(D.neighbor_out_iterator(1))
+ [2]
+ sage: list(D.neighbor_out_iterator(2))
+ []
+
+ Check that the iterator lists ``vertex`` in the presence of loop(s):
+
+ sage: D = DiGraph([[0, 1, 2], [(0, 0), (0, 0), (1, 1)]],multiedges=True, loops=True)
+ sage: list(D.neighbor_out_iterator(0))
+ [0]
+ sage: list(D.neighbor_out_iterator(1))
+ [1]
+ sage: list(D.neighbor_out_iterator(2))
+ []
+
"""
- return iter(set(self._backend.iterator_out_nbrs(vertex)))
+ yield from self._backend.iterator_out_nbrs(vertex)
def neighbors_out(self, vertex):
"""
@@ -3061,30 +3107,30 @@ def all_simple_cycles(self, starting_vertices=None, rooted=False,
sage: g = graphs.PetersenGraph().to_directed()
sage: g.all_simple_cycles(max_length=4)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
- [2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
+ [2, 7, 2], [3, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7]]
sage: g.all_simple_cycles(max_length=6)
[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],
- [2, 7, 2], [3, 8, 3], [3, 4, 3], [4, 9, 4], [5, 8, 5], [5, 7, 5],
+ [2, 7, 2], [3, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 5],
[6, 8, 6], [6, 9, 6], [7, 9, 7], [0, 1, 2, 3, 4, 0],
[0, 1, 2, 7, 5, 0], [0, 1, 6, 8, 5, 0], [0, 1, 6, 9, 4, 0],
- [0, 4, 9, 6, 1, 0], [0, 4, 9, 7, 5, 0], [0, 4, 3, 8, 5, 0],
- [0, 4, 3, 2, 1, 0], [0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0],
- [0, 5, 7, 9, 4, 0], [0, 5, 7, 2, 1, 0], [1, 2, 3, 8, 6, 1],
+ [0, 4, 3, 2, 1, 0], [0, 4, 3, 8, 5, 0], [0, 4, 9, 6, 1, 0],
+ [0, 4, 9, 7, 5, 0], [0, 5, 7, 2, 1, 0], [0, 5, 7, 9, 4, 0],
+ [0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0], [1, 2, 3, 8, 6, 1],
[1, 2, 7, 9, 6, 1], [1, 6, 8, 3, 2, 1], [1, 6, 9, 7, 2, 1],
- [2, 3, 8, 5, 7, 2], [2, 3, 4, 9, 7, 2], [2, 7, 9, 4, 3, 2],
- [2, 7, 5, 8, 3, 2], [3, 8, 6, 9, 4, 3], [3, 4, 9, 6, 8, 3],
- [5, 8, 6, 9, 7, 5], [5, 7, 9, 6, 8, 5], [0, 1, 2, 3, 8, 5, 0],
+ [2, 3, 4, 9, 7, 2], [2, 3, 8, 5, 7, 2], [2, 7, 5, 8, 3, 2],
+ [2, 7, 9, 4, 3, 2], [3, 4, 9, 6, 8, 3], [3, 8, 6, 9, 4, 3],
+ [5, 7, 9, 6, 8, 5], [5, 8, 6, 9, 7, 5], [0, 1, 2, 3, 8, 5, 0],
[0, 1, 2, 7, 9, 4, 0], [0, 1, 6, 8, 3, 4, 0],
- [0, 1, 6, 9, 7, 5, 0], [0, 4, 9, 6, 8, 5, 0],
- [0, 4, 9, 7, 2, 1, 0], [0, 4, 3, 8, 6, 1, 0],
- [0, 4, 3, 2, 7, 5, 0], [0, 5, 8, 3, 2, 1, 0],
- [0, 5, 8, 6, 9, 4, 0], [0, 5, 7, 9, 6, 1, 0],
- [0, 5, 7, 2, 3, 4, 0], [1, 2, 3, 4, 9, 6, 1],
+ [0, 1, 6, 9, 7, 5, 0], [0, 4, 3, 2, 7, 5, 0],
+ [0, 4, 3, 8, 6, 1, 0], [0, 4, 9, 6, 8, 5, 0],
+ [0, 4, 9, 7, 2, 1, 0], [0, 5, 7, 2, 3, 4, 0],
+ [0, 5, 7, 9, 6, 1, 0], [0, 5, 8, 3, 2, 1, 0],
+ [0, 5, 8, 6, 9, 4, 0], [1, 2, 3, 4, 9, 6, 1],
[1, 2, 7, 5, 8, 6, 1], [1, 6, 8, 5, 7, 2, 1],
[1, 6, 9, 4, 3, 2, 1], [2, 3, 8, 6, 9, 7, 2],
- [2, 7, 9, 6, 8, 3, 2], [3, 8, 5, 7, 9, 4, 3],
- [3, 4, 9, 7, 5, 8, 3]]
+ [2, 7, 9, 6, 8, 3, 2], [3, 4, 9, 7, 5, 8, 3],
+ [3, 8, 5, 7, 9, 4, 3]]
The complete graph (without loops) on `4` vertices::
@@ -3102,52 +3148,52 @@ def all_simple_cycles(self, starting_vertices=None, rooted=False,
sage: g = graphs.CompleteGraph(20).to_directed()
sage: g.all_simple_cycles(max_length=2)
- [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0],
- [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 0],
- [0, 12, 0], [0, 13, 0], [0, 14, 0], [0, 15, 0], [0, 16, 0],
- [0, 17, 0], [0, 18, 0], [0, 19, 0], [1, 2, 1], [1, 3, 1],
- [1, 4, 1], [1, 5, 1], [1, 6, 1], [1, 7, 1], [1, 8, 1], [1, 9, 1],
- [1, 10, 1], [1, 11, 1], [1, 12, 1], [1, 13, 1], [1, 14, 1],
- [1, 15, 1], [1, 16, 1], [1, 17, 1], [1, 18, 1], [1, 19, 1],
- [2, 3, 2], [2, 4, 2], [2, 5, 2], [2, 6, 2], [2, 7, 2], [2, 8, 2],
- [2, 9, 2], [2, 10, 2], [2, 11, 2], [2, 12, 2], [2, 13, 2],
- [2, 14, 2], [2, 15, 2], [2, 16, 2], [2, 17, 2], [2, 18, 2],
- [2, 19, 2], [3, 4, 3], [3, 5, 3], [3, 6, 3], [3, 7, 3], [3, 8, 3],
- [3, 9, 3], [3, 10, 3], [3, 11, 3], [3, 12, 3], [3, 13, 3],
- [3, 14, 3], [3, 15, 3], [3, 16, 3], [3, 17, 3], [3, 18, 3],
- [3, 19, 3], [4, 5, 4], [4, 6, 4], [4, 7, 4], [4, 8, 4], [4, 9, 4],
- [4, 10, 4], [4, 11, 4], [4, 12, 4], [4, 13, 4], [4, 14, 4],
- [4, 15, 4], [4, 16, 4], [4, 17, 4], [4, 18, 4], [4, 19, 4],
- [5, 6, 5], [5, 7, 5], [5, 8, 5], [5, 9, 5], [5, 10, 5],
- [5, 11, 5], [5, 12, 5], [5, 13, 5], [5, 14, 5], [5, 15, 5],
- [5, 16, 5], [5, 17, 5], [5, 18, 5], [5, 19, 5], [6, 7, 6],
- [6, 8, 6], [6, 9, 6], [6, 10, 6], [6, 11, 6], [6, 12, 6],
- [6, 13, 6], [6, 14, 6], [6, 15, 6], [6, 16, 6], [6, 17, 6],
- [6, 18, 6], [6, 19, 6], [7, 8, 7], [7, 9, 7], [7, 10, 7],
- [7, 11, 7], [7, 12, 7], [7, 13, 7], [7, 14, 7], [7, 15, 7],
- [7, 16, 7], [7, 17, 7], [7, 18, 7], [7, 19, 7], [8, 9, 8],
- [8, 10, 8], [8, 11, 8], [8, 12, 8], [8, 13, 8], [8, 14, 8],
- [8, 15, 8], [8, 16, 8], [8, 17, 8], [8, 18, 8], [8, 19, 8],
- [9, 10, 9], [9, 11, 9], [9, 12, 9], [9, 13, 9], [9, 14, 9],
- [9, 15, 9], [9, 16, 9], [9, 17, 9], [9, 18, 9], [9, 19, 9],
- [10, 11, 10], [10, 12, 10], [10, 13, 10], [10, 14, 10],
- [10, 15, 10], [10, 16, 10], [10, 17, 10], [10, 18, 10],
- [10, 19, 10], [11, 12, 11], [11, 13, 11], [11, 14, 11],
- [11, 15, 11], [11, 16, 11], [11, 17, 11], [11, 18, 11],
- [11, 19, 11], [12, 13, 12], [12, 14, 12], [12, 15, 12],
+ [[0, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],
+ [0, 3, 0], [0, 19, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0], [0, 7, 0],
+ [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 0], [0, 12, 0],
+ [0, 13, 0], [0, 14, 0], [0, 15, 0], [1, 16, 1], [1, 17, 1],
+ [1, 2, 1], [1, 18, 1], [1, 3, 1], [1, 19, 1], [1, 4, 1], [1, 5, 1],
+ [1, 6, 1], [1, 7, 1], [1, 8, 1], [1, 9, 1], [1, 10, 1], [1, 11, 1],
+ [1, 12, 1], [1, 13, 1], [1, 14, 1], [1, 15, 1], [2, 16, 2],
+ [2, 17, 2], [2, 18, 2], [2, 3, 2], [2, 19, 2], [2, 4, 2],
+ [2, 5, 2], [2, 6, 2], [2, 7, 2], [2, 8, 2], [2, 9, 2], [2, 10, 2],
+ [2, 11, 2], [2, 12, 2], [2, 13, 2], [2, 14, 2], [2, 15, 2],
+ [3, 16, 3], [3, 17, 3], [3, 18, 3], [3, 19, 3], [3, 4, 3],
+ [3, 5, 3], [3, 6, 3], [3, 7, 3], [3, 8, 3], [3, 9, 3], [3, 10, 3],
+ [3, 11, 3], [3, 12, 3], [3, 13, 3], [3, 14, 3], [3, 15, 3],
+ [4, 16, 4], [4, 17, 4], [4, 18, 4], [4, 19, 4], [4, 5, 4],
+ [4, 6, 4], [4, 7, 4], [4, 8, 4], [4, 9, 4], [4, 10, 4], [4, 11, 4],
+ [4, 12, 4], [4, 13, 4], [4, 14, 4], [4, 15, 4], [5, 16, 5],
+ [5, 17, 5], [5, 18, 5], [5, 19, 5], [5, 6, 5], [5, 7, 5],
+ [5, 8, 5], [5, 9, 5], [5, 10, 5], [5, 11, 5], [5, 12, 5],
+ [5, 13, 5], [5, 14, 5], [5, 15, 5], [6, 16, 6], [6, 17, 6],
+ [6, 18, 6], [6, 19, 6], [6, 7, 6], [6, 8, 6], [6, 9, 6],
+ [6, 10, 6], [6, 11, 6], [6, 12, 6], [6, 13, 6], [6, 14, 6],
+ [6, 15, 6], [7, 16, 7], [7, 17, 7], [7, 18, 7], [7, 19, 7],
+ [7, 8, 7], [7, 9, 7], [7, 10, 7], [7, 11, 7], [7, 12, 7],
+ [7, 13, 7], [7, 14, 7], [7, 15, 7], [8, 16, 8], [8, 17, 8],
+ [8, 18, 8], [8, 19, 8], [8, 9, 8], [8, 10, 8], [8, 11, 8],
+ [8, 12, 8], [8, 13, 8], [8, 14, 8], [8, 15, 8], [9, 16, 9],
+ [9, 17, 9], [9, 18, 9], [9, 19, 9], [9, 10, 9], [9, 11, 9],
+ [9, 12, 9], [9, 13, 9], [9, 14, 9], [9, 15, 9], [10, 16, 10],
+ [10, 17, 10], [10, 18, 10], [10, 19, 10], [10, 11, 10],
+ [10, 12, 10], [10, 13, 10], [10, 14, 10], [10, 15, 10],
+ [11, 16, 11], [11, 17, 11], [11, 18, 11], [11, 19, 11],
+ [11, 12, 11], [11, 13, 11], [11, 14, 11], [11, 15, 11],
[12, 16, 12], [12, 17, 12], [12, 18, 12], [12, 19, 12],
- [13, 14, 13], [13, 15, 13], [13, 16, 13], [13, 17, 13],
- [13, 18, 13], [13, 19, 13], [14, 15, 14], [14, 16, 14],
- [14, 17, 14], [14, 18, 14], [14, 19, 14], [15, 16, 15],
- [15, 17, 15], [15, 18, 15], [15, 19, 15], [16, 17, 16],
- [16, 18, 16], [16, 19, 16], [17, 18, 17], [17, 19, 17],
- [18, 19, 18]]
+ [12, 13, 12], [12, 14, 12], [12, 15, 12], [13, 16, 13],
+ [13, 17, 13], [13, 18, 13], [13, 19, 13], [13, 14, 13],
+ [13, 15, 13], [14, 16, 14], [14, 17, 14], [14, 18, 14],
+ [14, 19, 14], [14, 15, 14], [15, 16, 15], [15, 17, 15],
+ [15, 18, 15], [15, 19, 15], [16, 17, 16], [16, 18, 16],
+ [16, 19, 16], [17, 18, 17], [17, 19, 17], [18, 19, 18]]
+
sage: g = graphs.CompleteGraph(20).to_directed()
sage: g.all_simple_cycles(max_length=2, starting_vertices=[0])
- [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0],
+ [[0, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],
+ [0, 3, 0], [0, 19, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0],
[0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 0],
- [0, 12, 0], [0, 13, 0], [0, 14, 0], [0, 15, 0], [0, 16, 0],
- [0, 17, 0], [0, 18, 0], [0, 19, 0]]
+ [0, 12, 0], [0, 13, 0], [0, 14, 0], [0, 15, 0]]
One may prefer to distinguish equivalent cycles having distinct starting
vertices (compare the following examples)::
diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py
index 7d89a1ce02f..7ae9fe248fa 100644
--- a/src/sage/graphs/digraph_generators.py
+++ b/src/sage/graphs/digraph_generators.py
@@ -78,9 +78,9 @@ class DiGraphGenerators:
A class consisting of constructors for several common digraphs,
including orderly generation of isomorphism class representatives.
- A list of all graphs and graph structures in this database is
- available via tab completion. Type "digraphs." and then hit tab to
- see which graphs are available.
+ A list of all graphs and graph structures in this database is available via
+ tab completion. Type ``digraphs.`` and then hit :kbd:`Tab` to see which
+ digraphs are available.
The docstrings include educational information about each named
digraph with the hopes that this class can be used as a reference.
@@ -567,7 +567,7 @@ def tournaments_nauty(self, n,
- ``options`` -- string; anything else that should be forwarded as input
to Nauty's genbg. See its documentation for more information :
- ``_.
+ ``_.
EXAMPLES::
@@ -639,7 +639,7 @@ def nauty_directg(self, graphs, options="", debug=False):
r"""
Return an iterator yielding digraphs using nauty's ``directg`` program.
- Description from directg --help:
+ Description from ``directg --help``:
Read undirected graphs and orient their edges in all possible ways.
Edges can be oriented in either or both directions (3 possibilities).
Isomorphic directed graphs derived from the same input are suppressed.
@@ -651,8 +651,8 @@ def nauty_directg(self, graphs, options="", debug=False):
:class:`Graph`. The graph6 string of these graphs is used as an input
for ``directg``.
- - ``options`` (str) -- a string passed to directg as if it was run at
- a system command line. Available options from directg --help::
+ - ``options`` -- a string passed to ``directg`` as if it was run at
+ a system command line. Available options from ``directg --help``::
-e | -e: specify a value or range of the total number of arcs
-o orient each edge in only one direction, never both
@@ -664,8 +664,8 @@ def nauty_directg(self, graphs, options="", debug=False):
the part number (first is 0) and the second is the number of
parts. Splitting is done per input graph independently.
- - ``debug`` -- boolean (default: ``False``); if ``True``
- directg standard error and standard output are displayed.
+ - ``debug`` -- boolean (default: ``False``); if ``True`` ``directg``
+ standard error and standard output are displayed.
EXAMPLES::
@@ -807,7 +807,8 @@ def Circuit(self, n):
r"""
Return the circuit on `n` vertices.
- The circuit is an oriented ``CycleGraph``.
+ The circuit is an oriented
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CycleGraph`.
EXAMPLES:
@@ -838,8 +839,8 @@ def Circulant(self, n, integers):
- ``n`` -- integer; number of vertices
- ``integers`` -- iterable container (list, set, etc.) of integers such
- that there is an edge from `i` to `j` if and only if ``(j-i)%n in
- integers``
+ that there is an edge from `i` to `j` if and only if `(j-i) \pmod{n}`
+ is an integer
EXAMPLES::
diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx
index ea70f890005..85a1d1ee263 100644
--- a/src/sage/graphs/distances_all_pairs.pyx
+++ b/src/sage/graphs/distances_all_pairs.pyx
@@ -1750,6 +1750,11 @@ def diameter(G, algorithm=None, source=None):
error if the initial vertex is not in `G`. This parameter is not used
when ``algorithm=='standard'``.
+ .. NOTE::
+ As the graph is first converted to a short_digraph, all complexity
+ have an extra `O(m+n)` for ``SparseGraph`` and `O(n^2)` for
+ ``DenseGraph``.
+
EXAMPLES::
sage: from sage.graphs.distances_all_pairs import diameter
@@ -2278,6 +2283,14 @@ 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]_::
@@ -2351,7 +2364,7 @@ def szeged_index(G, algorithm=None):
if G.is_directed() and not G.is_strongly_connected():
raise ValueError("the Szeged index is defined for "
"strongly connected digraphs only")
- if G.is_directed() and algorithm is "low":
+ if G.is_directed() and algorithm == "low":
raise ValueError("the 'low' algorithm cannot be used on digraphs")
if algorithm is None:
@@ -2360,7 +2373,7 @@ def szeged_index(G, algorithm=None):
elif algorithm not in ["low", "high"]:
raise ValueError(f"unknown algorithm '{algorithm}'")
- if algorithm is "low" and (G.has_loops() or G.has_multiple_edges()):
+ if algorithm == "low" and (G.has_loops() or G.has_multiple_edges()):
raise ValueError("the 'low' algorithm is for simple connected "
"undirected graphs only")
@@ -2370,7 +2383,7 @@ def szeged_index(G, algorithm=None):
cdef short_digraph sd
cdef uint64_t s
- if algorithm is "low":
+ 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:
diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py
index 1d542bc17f6..9776b561748 100644
--- a/src/sage/graphs/generators/basic.py
+++ b/src/sage/graphs/generators/basic.py
@@ -101,7 +101,7 @@ def ButterflyGraph():
.. SEEALSO::
- - :meth:`GraphGenerators.FriendshipGraph`
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.FriendshipGraph`
EXAMPLES:
@@ -161,7 +161,7 @@ def CircularLadderGraph(n):
displayed as an inner and outer cycle pair, with the first `n` nodes drawn
on the inner circle. The first (0) node is drawn at the top of the
inner-circle, moving clockwise after that. The outer circle is drawn with
- the `(n+1)`th node at the top, then counterclockwise as well.
+ the `(n+1)`-th node at the top, then counterclockwise as well.
When `n == 2`, we rotate the outer circle by an angle of `\pi/8` to ensure
that all edges are visible (otherwise the 4 vertices of the graph would be
placed on a single line).
@@ -401,15 +401,28 @@ def CompleteGraph(n):
G.add_edges((i, j) for i in range(n) for j in range(i + 1, n))
return G
+
def CorrelationGraph(seqs, alpha, include_anticorrelation):
- """
- Constructs and returns a correlation graph with a node corresponding to each sequence in `seqs`.
+ r"""
+ Return a correlation graph with a node per sequence in ``seqs``.
- Edges are added between nodes where the corresponding sequences have a correlation coeffecient greater than alpha.
+ Edges are added between nodes where the corresponding sequences have a
+ correlation coeffecient greater than alpha.
- If include_anticorrelation is true, then edges are also added between nodes with correlation coeffecient less than -alpha.
+ If ``include_anticorrelation`` is ``True``, then edges are also added
+ between nodes with correlation coefficient less than ``-alpha``.
- EXAMPLES:
+ INPUT:
+
+ - ``seqs`` -- list of sequences, taht is a list of lists
+
+ - ``alpha`` -- float; threshold on the correlation coefficient between two
+ sequences for adding an edge
+
+ - ``include_anticorrelation`` -- boolean; whether to add edges between nodes
+ with correlation coefficient less than ``-alpha`` or not
+
+ EXAMPLES::
sage: # needs numpy
sage: from sage.graphs.generators.basic import CorrelationGraph
@@ -423,7 +436,6 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation):
[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
sage: CG3.edges(sort=False)
[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)]
-
"""
from numpy import corrcoef
from sage.matrix.constructor import Matrix
@@ -442,6 +454,7 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation):
# call graph constructor
return Graph(adjacency_matrix, format="adjacency_matrix", name="Correlation Graph")
+
def CompleteBipartiteGraph(p, q, set_position=True):
r"""
Return a Complete Bipartite Graph on `p + q` vertices.
@@ -858,7 +871,6 @@ def Toroidal6RegularGrid2dGraph(p, q):
...
ValueError: parameters p and q must be integers larger than 3
"""
-
if p <= 3 or q <= 3:
raise ValueError("parameters p and q must be integers larger than 3")
@@ -1148,6 +1160,90 @@ def LadderGraph(n):
return G
+def MoebiusLadderGraph(n):
+ r"""
+ Return a Möbius ladder graph with `2n` nodes
+
+ A Möbius ladder graph of order `2n` is a ladder graph of the same order
+ that is connected at the ends with a single twist, i.e., a ladder graph
+ bent around so that top meets bottom with a single twist. Alternatively,
+ it can be described as a single cycle graph (of order `2n`) with the
+ addition of edges (called `rungs`) joining the antipodal pairs of nodes.
+ Also, note that the Möbius ladder graph ``graphs.MoebiusLadderGraph(n)`` is
+ precisely the same graph as the circulant graph
+ ``graphs.CirculantGraph(2 * n, [1, n])``.
+
+ PLOTTING:
+
+ Upon construction, the position dictionary is filled to override the
+ spring-layout algorithm. By convention, each Möbius ladder graph will be
+ displayed with the first (0) node at the top, with the rest following in a
+ counterclockwise manner.
+
+ INPUT:
+
+ - ``n`` -- a non negative integer; number of nodes is `2n`
+
+ OUTPUT:
+
+ - ``G`` -- a Möbius ladder graph of order `2n`; note that a
+ :class:`ValueError` is returned if `n < 0`
+
+ EXAMPLES:
+
+ Construct and show a Möbius ladder graph with 26 nodes::
+
+ sage: g = graphs.MoebiusLadderGraph(13)
+ sage: g.show() # long time # needs sage.plot
+
+ Create several Möbius ladder graphs in a Sage graphics array::
+
+ sage: # needs sage.plots
+ sage: g = []
+ sage: j = []
+ sage: for i in range(9):
+ ....: k = graphs.MoebiusLadderGraph(i+3)
+ ....: g.append(k)
+ sage: for i in range(3):
+ ....: n = []
+ ....: for m in range(3):
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
+ ....: j.append(n)
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
+
+ TESTS:
+
+ The input parameter must be a non negative integer::
+
+ sage: G = graphs.MoebiusLadderGraph(-1)
+ Traceback (most recent call last):
+ ...
+ ValueError: parameter n must be a non negative integer
+
+ REFERENCES:
+
+ - :wikipedia:`Möbius_ladder`
+
+ .. SEEALSO::
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.LadderGraph`,
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CircularLadderGraph`,
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CirculantGraph`
+
+ AUTHORS:
+
+ - Janmenjaya Panda (2024-05-26)
+ """
+ if n < 0:
+ raise ValueError("parameter n must be a non negative integer")
+
+ G = Graph(2 * n, name="Moebius ladder graph")
+ G._circle_embedding(list(range(2 * n)), angle=pi/2)
+ G.add_cycle(list(range(2 * n)))
+ G.add_edges((i, i + n) for i in range(n))
+ return G
+
+
def PathGraph(n, pos=None):
r"""
Return a path graph with `n` nodes.
diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx
index 79828c57e98..23a52f57e5d 100644
--- a/src/sage/graphs/generators/distance_regular.pyx
+++ b/src/sage/graphs/generators/distance_regular.pyx
@@ -591,8 +591,9 @@ def UstimenkoGraph(const int m, const int q):
Return the Ustimenko graph with parameters `(m, q)`.
This is the distance 1 or 2 graph of the dual polar graph `C_{m-1}(q)`.
- The graph is distance-regular with classical with parameters
- `(d,q^2, qbinom(3,1,q) -1, qbinom(m+1,1,q) -1)`
+ The graph is distance-regular with parameters
+ `(d,q^2, \binom{3}{1}_q -1, \binom{m+1}{1}_q -1)`,
+ where `\binom{n}{k}_q` is the `q`-binomial coefficient.
INPUT:
@@ -833,7 +834,7 @@ def HermitianFormsGraph(const int n, const int r):
r"""
Return the Hermitian forms graph with the given parameters.
- We build a graph whose vertices are all ``n``x``n`` Hermitian matrices
+ We build a graph whose vertices are all `n \times n` Hermitian matrices
over ``GF(r^2)``. Two vertices are adjacent if the difference of the two
vertices has rank 1.
diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py
index 724d94eedeb..c7e1c031ebf 100644
--- a/src/sage/graphs/generators/families.py
+++ b/src/sage/graphs/generators/families.py
@@ -414,16 +414,16 @@ def EgawaGraph(p, s):
def HammingGraph(n, q, X=None):
r"""
- Returns the Hamming graph with parameters ``n``, ``q`` over ``X``.
+ Return the Hamming graph with parameters `n`, `q` over `X`.
Hamming graphs are graphs over the cartesian product of n copies
- of ``X``, where `q = |X|`, where the vertices, labelled with the
+ of `X`, where `q = |X|`, where the vertices, labelled with the
corresponding tuple in `X^n`, are connected if the Hamming distance
between their labels is 1. All Hamming graphs are regular,
vertex-transitive and distance-regular.
Hamming graphs with parameters `(1,q)` represent the complete graph
- with q vertices over the set ``X``.
+ with q vertices over the set `X`.
INPUT:
@@ -443,8 +443,7 @@ def HammingGraph(n, q, X=None):
EXAMPLES:
- Every Hamming graph is distance-regular, regular and
- vertex-transitive. ::
+ Every Hamming graph is distance-regular, regular and vertex-transitive::
sage: g = graphs.HammingGraph(3, 7)
sage: g.is_distance_regular()
@@ -454,15 +453,15 @@ def HammingGraph(n, q, X=None):
sage: g.is_vertex_transitive() # needs sage.groups
True
- A Hamming graph with parameters (1,q) is isomorphic to the
- Complete graph with parameter q. ::
+ A Hamming graph with parameters `(1,q)` is isomorphic to the
+ Complete graph with parameter `q`::
sage: g = graphs.HammingGraph(1, 23)
sage: g.is_isomorphic(graphs.CompleteGraph(23))
True
- If a parameter ``q`` is provided which is not equal to ``X``'s
- cardinality, an exception is raised. ::
+ If a parameter `q` is provided which is not equal to `X`'s
+ cardinality, an exception is raised::
sage: X = ['a','b','c','d','e']
sage: g = graphs.HammingGraph(2, 3, X)
@@ -597,11 +596,12 @@ def BalancedTree(r, h):
def BarbellGraph(n1, n2):
r"""
- Returns a barbell graph with ``2*n1 + n2`` nodes. The argument ``n1``
- must be greater than or equal to 2.
+ Returns a barbell graph with `2*n_1 + n_2` nodes.
+
+ The argument `n_1` must be greater than or equal to 2.
A barbell graph is a basic structure that consists of a path graph
- of order ``n2`` connecting two complete graphs of order ``n1`` each.
+ of order `n_2` connecting two complete graphs of order `n_1` each.
INPUT:
@@ -613,8 +613,8 @@ def BarbellGraph(n1, n2):
OUTPUT:
- A barbell graph of order ``2*n1 + n2``. A :class:`ValueError` is
- returned if ``n1 < 2`` or ``n2 < 0``.
+ A barbell graph of order `2*n_1 + n_2`. A :class:`ValueError` is
+ returned if `n_1 < 2` or `n_2 < 0`.
PLOTTING:
@@ -622,9 +622,9 @@ def BarbellGraph(n1, n2):
override the spring-layout algorithm. By convention, each barbell
graph will be displayed with the two complete graphs in the
lower-left and upper-right corners, with the path graph connecting
- diagonally between the two. Thus the ``n1``-th node will be drawn at a
+ diagonally between the two. Thus the `n_1`-th node will be drawn at a
45 degree angle from the horizontal right center of the first
- complete graph, and the ``n1 + n2 + 1``-th node will be drawn 45
+ complete graph, and the `n_1 + n_2 + 1`-th node will be drawn 45
degrees below the left horizontal center of the second complete graph.
EXAMPLES:
@@ -635,9 +635,9 @@ def BarbellGraph(n1, n2):
Barbell graph: Graph on 22 vertices
sage: g.show() # long time # needs sage.plot
- An ``n1 >= 2``, ``n2 >= 0`` barbell graph has order ``2*n1 + n2``. It
- has the complete graph on ``n1`` vertices as a subgraph. It also has
- the path graph on ``n2`` vertices as a subgraph. ::
+ An `n_1 \geq 2`, `n_2 \geq 0` barbell graph has order `2*n_1 + n_2`. It
+ has the complete graph on `n_1` vertices as a subgraph. It also has
+ the path graph on `n_2` vertices as a subgraph. ::
sage: n1 = randint(2, 2*10^2)
sage: n2 = randint(0, 2*10^2)
@@ -669,7 +669,7 @@ def BarbellGraph(n1, n2):
sage: g.girth() == 3
True
- The input ``n1`` must be `\geq 2`::
+ The input `n_1` must be `\geq 2`::
sage: graphs.BarbellGraph(1, randint(0, 10^6))
Traceback (most recent call last):
@@ -680,7 +680,7 @@ def BarbellGraph(n1, n2):
...
ValueError: invalid graph description, n1 should be >= 2
- The input ``n2`` must be `\geq 0`::
+ The input `n_2` must be `\geq 0`::
sage: graphs.BarbellGraph(randint(2, 10^6), -1)
Traceback (most recent call last):
@@ -714,14 +714,14 @@ def BarbellGraph(n1, n2):
def LollipopGraph(n1, n2):
r"""
- Returns a lollipop graph with n1+n2 nodes.
+ Returns a lollipop graph with `n_1 + n_2` nodes.
- A lollipop graph is a path graph (order n2) connected to a complete
- graph (order n1). (A barbell graph minus one of the bells).
+ A lollipop graph is a path graph (order `n_2`) connected to a complete
+ graph (order `n_1`). (A barbell graph minus one of the bells).
PLOTTING: Upon construction, the position dictionary is filled to
override the spring-layout algorithm. By convention, the complete
- graph will be drawn in the lower-left corner with the (n1)th node
+ graph will be drawn in the lower-left corner with the `n_1`-th node
at a 45 degree angle above the right horizontal center of the
complete graph, leading directly into the path graph.
@@ -752,14 +752,14 @@ def LollipopGraph(n1, n2):
sage: graphs.LollipopGraph(0, 0).is_isomorphic(graphs.EmptyGraph())
True
- The input ``n1`` must be `\geq 0`::
+ The input `n_1` must be `\geq 0`::
sage: graphs.LollipopGraph(-1, randint(0, 10^6))
Traceback (most recent call last):
...
ValueError: invalid graph description, n1 should be >= 0
- The input ``n2`` must be `\geq 0`::
+ The input `n_2` must be `\geq 0`::
sage: graphs.LollipopGraph(randint(2, 10^6), -1)
Traceback (most recent call last):
@@ -787,14 +787,14 @@ def LollipopGraph(n1, n2):
def TadpoleGraph(n1, n2):
r"""
- Return a tadpole graph with n1+n2 nodes.
+ Return a tadpole graph with `n_1 + n_2` nodes.
- A tadpole graph is a path graph (order n2) connected to a cycle graph
- (order n1).
+ A tadpole graph is a path graph (order `n_2`) connected to a cycle graph
+ (order `n_1`).
PLOTTING: Upon construction, the position dictionary is filled to override
the spring-layout algorithm. By convention, the cycle graph will be drawn
- in the lower-left corner with the (n1)th node at a 45 degree angle above
+ in the lower-left corner with the `n_1`-th node at a 45 degree angle above
the right horizontal center of the cycle graph, leading directly into the
path graph.
@@ -819,14 +819,14 @@ def TadpoleGraph(n1, n2):
sage: graphs.TadpoleGraph(n1, 0).is_isomorphic(graphs.CycleGraph(n1))
True
- The input ``n1`` must be `\geq 3`::
+ The input `n_1` must be `\geq 3`::
sage: graphs.TadpoleGraph(2, randint(0, 10^6))
Traceback (most recent call last):
...
ValueError: invalid graph description, n1 should be >= 3
- The input ``n2`` must be `\geq 0`::
+ The input `n_2` must be `\geq 0`::
sage: graphs.TadpoleGraph(randint(2, 10^6), -1)
Traceback (most recent call last):
@@ -1068,17 +1068,17 @@ def chang_graphs():
def CirculantGraph(n, adjacency):
r"""
- Returns a circulant graph with n nodes.
+ Returns a circulant graph with `n` nodes.
A circulant graph has the property that the vertex `i` is connected
- with the vertices `i+j` and `i-j` for each j in ``adjacency``.
+ with the vertices `i+j` and `i-j` for each `j` in ``adjacency``.
INPUT:
- ``n`` -- number of vertices in the graph
- - ``adjacency`` -- the list of j values
+ - ``adjacency`` -- the list of `j` values
PLOTTING: Upon construction, the position dictionary is filled to
@@ -1086,12 +1086,12 @@ def CirculantGraph(n, adjacency):
graph will be displayed with the first (0) node at the top, with
the rest following in a counterclockwise manner.
- Filling the position dictionary in advance adds O(n) to the
+ Filling the position dictionary in advance adds `O(n)` to the
constructor.
.. SEEALSO::
- * :meth:`sage.graphs.generic_graph.GenericGraph.is_circulant`
+ * :meth:`~sage.graphs.generic_graph.GenericGraph.is_circulant`
-- checks whether a (di)graph is circulant, and/or returns
all possible sets of parameters.
@@ -1909,12 +1909,12 @@ def RoseWindowGraph(n, a, r):
PLOTTING: Upon construction, the position dictionary is filled to override
the spring-layout algorithm. By convention, the rose window graphs are
- displayed as an inner and outer cycle pair, with the first n nodes drawn on
- the outer circle. The first (0) node is drawn at the top of the
+ displayed as an inner and outer cycle pair, with the first `n` nodes drawn
+ on the outer circle. The first (0) node is drawn at the top of the
outer-circle, moving counterclockwise after that. The inner circle is drawn
- with the (n)th node at the top, then counterclockwise as well. Vertices in
+ with the (`n`)th node at the top, then counterclockwise as well. Vertices in
the outer circle are connected in the circular manner, vertices in the inner
- circle are connected when their label have difference `r` (mod n). Vertices
+ circle are connected when their label have difference `r \pmod{n}`. Vertices
on the outer rim are connected with the vertices on the inner rim when they
are at the same position and when they are `a` apart.
@@ -2003,12 +2003,12 @@ def TabacjnGraph(n, a, b, r):
PLOTTING: Upon construction, the position dictionary is filled to override
the spring-layout algorithm. By convention, the rose window graphs are
- displayed as an inner and outer cycle pair, with the first n nodes drawn on
- the outer circle. The first (0) node is drawn at the top of the
+ displayed as an inner and outer cycle pair, with the first `n` nodes drawn
+ on the outer circle. The first (0) node is drawn at the top of the
outer-circle, moving counterclockwise after that. The inner circle is drawn
- with the (n)th node at the top, then counterclockwise as well. Vertices in
+ with the (`n`)th node at the top, then counterclockwise as well. Vertices in
the outer circle are connected in the circular manner, vertices in the inner
- circle are connected when their label have difference `r` (mod n). Vertices
+ circle are connected when their label have difference `r \pmod{n}`. Vertices
on the outer rim are connected with the vertices on the inner rim when they
are at the same position and when they are `a` and `b` apart.
@@ -2099,8 +2099,7 @@ def HararyGraph(k, n):
Harary graphs are minimal `k`-connected graphs on `n` vertices.
The construction provided uses the method CirculantGraph. For more
- details, see the book D. B. West, Introduction to Graph Theory, 2nd
- Edition, Prentice Hall, 2001, p. 150--151; or the `MathWorld article on
+ details, see the book [West2001]_ or the `MathWorld article on
Harary graphs `_.
EXAMPLES:
@@ -2223,26 +2222,26 @@ def LCFGraph(n, shift_list, repeats):
r"""
Return the cubic graph specified in LCF notation.
- LCF (Lederberg-Coxeter-Fruchte) notation is a concise way of
- describing cubic Hamiltonian graphs. The way a graph is constructed
- is as follows. Since there is a Hamiltonian cycle, we first create
- a cycle on n nodes. The variable shift_list = [s_0, s_1, ...,
- s_k-1] describes edges to be created by the following scheme: for
- each i, connect vertex i to vertex (i + s_i). Then, repeats
- specifies the number of times to repeat this process, where on the
- jth repeat we connect vertex (i + j\*len(shift_list)) to vertex (
- i + j\*len(shift_list) + s_i).
+ LCF (Lederberg-Coxeter-Fruchte) notation is a concise way of describing
+ cubic Hamiltonian graphs. The way a graph is constructed is as
+ follows. Since there is a Hamiltonian cycle, we first create a cycle on `n`
+ nodes. The variable ``shift_list`` = `[s_0, s_1, ..., s_{k-1}]` describes
+ edges to be created by the following scheme: for each `i \in \{0, 1, \dots,
+ k-1\}`, connect vertex `i` to vertex `(i + s_i) \pmod{n}`. Then, ``repeats``
+ specifies the number of times to repeat this process, where on the `j`-th
+ repeat we connect vertex `(i + j k) \pmod{n}` to vertex `(i + j k + s_i)
+ \pmod{n}`.
- INPUT:
+ For more details, see the :wikipedia:`LCF_notation` and [Fru1977]_,
+ [Gru2003]_ pp. 357-365, and [Led1965]_.
+ INPUT:
- ``n`` -- the number of nodes.
- ``shift_list`` -- a list of integer shifts mod `n`.
- - ``repeats`` -- the number of times to repeat the
- process.
-
+ - ``repeats`` -- the number of times to repeat the process.
EXAMPLES::
@@ -2273,23 +2272,8 @@ def LCFGraph(n, shift_list, repeats):
3
sage: G.show() # long time # needs sage.plot
- PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the
+ PLOTTING: LCF Graphs are plotted as an `n`-cycle with edges in the
middle, as described above.
-
- REFERENCES:
-
- - [1] Frucht, R. "A Canonical Representation of Trivalent
- Hamiltonian Graphs." J. Graph Th. 1, 45-60, 1976.
-
- - [2] Grunbaum, B. Convex Polytope es. New York: Wiley,
- pp. 362-364, 1967.
-
- - [3] Lederberg, J. 'DENDRAL-64: A System for Computer
- Construction, Enumeration and Notation of Organic Molecules
- as Tree Structures and Cyclic Graphs. Part II. Topology of
- Cyclic Graphs.' Interim Report to the National Aeronautics
- and Space Administration. Grant NsG 81-60. December 15,
- 1965. http://profiles.nlm.nih.gov/BB/A/B/I/U/_/bbabiu.pdf.
"""
import networkx
G = Graph(networkx.LCF_graph(n, shift_list, repeats), name="LCF Graph")
@@ -2319,6 +2303,8 @@ def MycielskiGraph(k=1, relabel=True):
`w_i`-vertices. Finally, vertex `w_i` is adjacent to vertex
`v_j` iff `v_i` is adjacent to `v_j`.
+ For more details, see the :wikipedia:`Mycielskian`.
+
INPUT:
- ``k`` Number of steps in the construction process.
@@ -2342,13 +2328,6 @@ def MycielskiGraph(k=1, relabel=True):
sage: g = graphs.MycielskiGraph(4)
sage: g.is_isomorphic(graphs.GrotzschGraph())
True
-
- REFERENCES:
-
- - [1] Weisstein, Eric W. "Mycielski Graph."
- From MathWorld--A Wolfram Web Resource.
- http://mathworld.wolfram.com/MycielskiGraph.html
-
"""
g = Graph()
g.name("Mycielski Graph " + str(k))
@@ -2418,21 +2397,21 @@ def MycielskiStep(g):
def NKStarGraph(n, k):
r"""
- Returns the (n,k)-star graph.
+ Returns the `(n,k)`-star graph.
- The vertices of the (n,k)-star graph are the set of all arrangements of
- n symbols into labels of length k. There are two adjacency rules for
- the (n,k)-star graph. First, two vertices are adjacent if one can be
- obtained from the other by swapping the first symbol with another
- symbol. Second, two vertices are adjacent if one can be obtained from
- the other by swapping the first symbol with an external symbol (a
- symbol not used in the original label).
+ The vertices of the `(n,k)`-star graph are the set of all arrangements of
+ `n` symbols into labels of length `k`. There are two adjacency rules for the
+ `(n,k)`-star graph. First, two vertices are adjacent if one can be obtained
+ from the other by swapping the first symbol with another symbol. Second, two
+ vertices are adjacent if one can be obtained from the other by swapping the
+ first symbol with an external symbol (a symbol not used in the original
+ label).
INPUT:
- - ``n``
+ - ``n`` -- integer; number of symbols
- - ``k``
+ - ``k`` -- integer; length of the labels of the vertices
EXAMPLES::
@@ -2442,9 +2421,7 @@ def NKStarGraph(n, k):
REFERENCES:
- - Wei-Kuo, Chiang, and Chen Rong-Jaye. "The (n, k)-star graph: A
- generalized star graph." Information Processing Letters 56,
- no. 5 (December 8, 1995): 259-264.
+ [CC1995]_
AUTHORS:
@@ -2483,15 +2460,15 @@ def NKStarGraph(n, k):
def NStarGraph(n):
r"""
- Returns the n-star graph.
+ Returns the `n`-star graph.
- The vertices of the n-star graph are the set of permutations on n
+ The vertices of the `n`-star graph are the set of permutations on `n`
symbols. There is an edge between two vertices if their labels differ
only in the first and one other position.
INPUT:
- - ``n``
+ - ``n`` -- integer; number of symbols
EXAMPLES::
@@ -2501,9 +2478,7 @@ def NStarGraph(n):
REFERENCES:
- - S.B. Akers, D. Horel and B. Krishnamurthy, The star graph: An
- attractive alternative to the previous n-cube. In: Proc. Internat.
- Conf. on Parallel Processing (1987), pp. 393--400.
+ [AHK1994]_
AUTHORS:
@@ -2706,7 +2681,7 @@ def SquaredSkewHadamardMatrixGraph(n):
def SwitchedSquaredSkewHadamardMatrixGraph(n):
r"""
A strongly regular graph in Seidel switching class of
- `SquaredSkewHadamardMatrixGraph`
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.SquaredSkewHadamardMatrixGraph`.
A strongly regular graph in the :meth:`Seidel switching
` class of the disjoint union of a 1-vertex graph
@@ -3437,9 +3412,9 @@ def WheelGraph(n):
displayed with the first (0) node in the center, the second node at the top,
and the rest following in a counterclockwise manner.
- With the wheel graph, we see that it doesn't take a very large n at all for
- the spring-layout to give a counter-intuitive display. (See Graphics Array
- examples below).
+ With the wheel graph, we see that it doesn't take a very large `n` at all
+ for the spring-layout to give a counter-intuitive display. (See Graphics
+ Array examples below).
EXAMPLES:
@@ -3779,7 +3754,7 @@ def RingedTree(k, vertex_labels=True):
More precisely, in each layer of the binary tree (i.e. a layer is the set of
vertices `[2^i...2^{i+1}-1]`) two vertices `u,v` are adjacent if `u=v+1` or
- if `u=2^i` and `v=`2^{i+1}-1`.
+ if `u=2^i` and `v=2^{i+1}-1`.
Ringed trees are defined in [CFHM2013]_.
diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py
index 64a5da536c1..6faf8e2c838 100644
--- a/src/sage/graphs/generators/random.py
+++ b/src/sage/graphs/generators/random.py
@@ -660,9 +660,9 @@ def RandomBoundedToleranceGraph(n, seed=None):
def RandomGNM(n, m, dense=False, seed=None):
- """
- Returns a graph randomly picked out of all graphs on n vertices
- with m edges.
+ r"""
+ Return a graph randomly picked out of all graphs on `n` vertices with `m`
+ edges.
INPUT:
@@ -683,7 +683,7 @@ def RandomGNM(n, m, dense=False, seed=None):
sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # needs networkx
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- We plot a random graph on 12 nodes with m = 12::
+ We plot a random graph on 12 nodes and 12 edges::
sage: gnm = graphs.RandomGNM(12, 12) # needs networkx
sage: gnm.show() # long time # needs networkx sage.plot
@@ -1216,9 +1216,9 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s
.. SEEALSO::
- - :meth:`~sage.graphs.graph_generators.growing_subtrees`
- - :meth:`~sage.graphs.graph_generators.connecting_nodes`
- - :meth:`~sage.graphs.graph_generators.pruned_tree`
+ - :meth:`~sage.graphs.generators.random.growing_subtrees`
+ - :meth:`~sage.graphs.generators.random.connecting_nodes`
+ - :meth:`~sage.graphs.generators.random.pruned_tree`
- :wikipedia:`Chordal_graph`
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_chordal`
- :meth:`~sage.graphs.graph_generators.GraphGenerators.IntersectionGraph`
@@ -1280,12 +1280,12 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s
def RandomLobster(n, p, q, seed=None):
- """
- Returns a random lobster.
+ r"""
+ Return a random lobster.
A lobster is a tree that reduces to a caterpillar when pruning all
leaf vertices. A caterpillar is a tree that reduces to a path when
- pruning all leaf vertices (q=0).
+ pruning all leaf vertices (`q=0`).
INPUT:
@@ -1336,14 +1336,14 @@ def RandomTree(n, seed=None):
Returns a random tree on `n` nodes numbered `0` through `n-1`.
By Cayley's theorem, there are `n^{n-2}` trees with vertex
- set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly
+ set `\{0,1,\dots,n-1\}`. This constructor chooses one of these uniformly
at random.
ALGORITHM:
The algorithm works by generating an `(n-2)`-long
random sequence of numbers chosen independently and uniformly
- from `\{0,1,\ldots,n-1\}` and then applies an inverse
+ from `\{0,1,\dots,n-1\}` and then applies an inverse
Prufer transformation.
INPUT:
@@ -1733,16 +1733,19 @@ def RandomToleranceGraph(n, seed=None):
Return a random tolerance graph.
The random tolerance graph is built from a random tolerance representation
- by using the function `ToleranceGraph`. This representation is a list
- `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = n-1` and
- `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random positive
- value. The width of the representation is limited to `n^2 * 2^n`.
+ by using the function
+ :meth:`~sage.graphs.generators.intersection.ToleranceGraph`. This
+ representation is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ...,
+ (l_k,r_k,t_k))` where `k = n-1` and `I_i = (l_i,r_i)` denotes a random
+ interval and `t_i` a random positive value. The width of the representation
+ is limited to `n^2 * 2^n`.
.. NOTE::
- The vertices are named 0, 1, ..., n-1. The tolerance representation used
- to create the graph is saved with the graph and can be recovered using
- ``get_vertex()`` or ``get_vertices()``.
+ The vertices are named `0, 1, \cdots, n-1`. The tolerance representation
+ used to create the graph is saved with the graph and can be recovered
+ using :meth:`~sage.graphs.generic_graph.GenericGraph.get_vertex` or
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_vertices`.
INPUT:
diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py
index f1eaa816d6c..50b1905b7b0 100644
--- a/src/sage/graphs/generators/smallgraphs.py
+++ b/src/sage/graphs/generators/smallgraphs.py
@@ -2925,8 +2925,8 @@ def GritsenkoGraph():
r"""
Return SRG(65, 32, 15, 16) constructed by Gritsenko.
- We took the adjacency matrix from O.Gritsenko's [Gri2021]_ and extracted orbits
- of the automorphism group on the edges.
+ We took the adjacency matrix from O. Gritsenko's [Gri2021]_ and extracted
+ orbits of the automorphism group on the edges.
EXAMPLES::
diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py
index d3d6a4e8b0c..063931ae274 100644
--- a/src/sage/graphs/generic_graph.py
+++ b/src/sage/graphs/generic_graph.py
@@ -4572,8 +4572,9 @@ def eulerian_orientation(self):
has no non-oriented edge (this vertex must have odd degree), the walk
resumes at another vertex of odd degree, if any.
- This algorithm has complexity `O(m)`, where `m` is the number of edges
- in the graph.
+ This algorithm has complexity `O(n+m)` for ``SparseGraph`` and `O(n^2)`
+ for ``DenseGraph``, where `m` is the number of edges in the graph and
+ `n` is the number of vertices in the graph.
EXAMPLES:
@@ -14905,7 +14906,8 @@ def is_chordal(self, certificate=False, algorithm="B"):
ALGORITHM:
This method implements the algorithm proposed in [RT1975]_ for the
- recognition of chordal graphs with time complexity in `O(m)`. The
+ recognition of chordal graphs. The time complexity of this algorithm is
+ `O(n+m)` for ``SparseGraph`` and `O(n^2)` for ``DenseGraph``. The
algorithm works through computing a Lex BFS on the graph, then checking
whether the order is a Perfect Elimination Order by computing for each
vertex `v` the subgraph induced by its non-deleted neighbors, then
@@ -19040,13 +19042,13 @@ def depth_first_search(self, start, ignore_direction=False,
sage: D.add_path([22, 23, 24, 5])
sage: D.add_path([5, 33, 34, 35])
sage: list(D.depth_first_search(5, neighbors=D.neighbors_in))
- [5, 4, 3, 2, 1, 0, 24, 23, 22]
+ [5, 24, 23, 22, 4, 3, 2, 1, 0]
sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in))
- [5, 24, 4, 23, 3, 22, 2, 1, 0]
+ [5, 4, 24, 3, 23, 2, 22, 1, 0]
sage: list(D.depth_first_search(5, neighbors=D.neighbors_out))
- [5, 6, 7, 8, 9, 33, 34, 35]
+ [5, 33, 34, 35, 6, 7, 8, 9]
sage: list(D.breadth_first_search(5, neighbors=D.neighbors_out))
- [5, 33, 6, 34, 7, 35, 8, 9]
+ [5, 6, 33, 7, 34, 8, 35, 9]
You can get edges of the DFS tree instead of the vertices using the
``edges`` parameter::
diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py
index 4069c6a079d..3eda130f4d8 100644
--- a/src/sage/graphs/graph.py
+++ b/src/sage/graphs/graph.py
@@ -3047,7 +3047,8 @@ def strong_orientation(self):
.. NOTE::
- This method assumes the graph is connected.
- - This algorithm works in O(m).
+ - This time complexity is `O(n+m)` for ``SparseGraph`` and `O(n^2)`
+ for ``DenseGraph`` .
.. SEEALSO::
diff --git a/src/sage/graphs/graph_decompositions/clique_separators.pyx b/src/sage/graphs/graph_decompositions/clique_separators.pyx
index ed86654f595..0bd02e3b5db 100644
--- a/src/sage/graphs/graph_decompositions/clique_separators.pyx
+++ b/src/sage/graphs/graph_decompositions/clique_separators.pyx
@@ -172,6 +172,12 @@ 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.
diff --git a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
index 3644edf6ac7..886859e8d74 100644
--- a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
+++ b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
@@ -4,8 +4,8 @@
#include