diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8d936616077..ada020d8722 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -103,12 +103,24 @@ jobs:
run: pyright
working-directory: ./worktree-image
- - name: Build (fallback to non-incremental)
- id: build
+ - name: Clean (fallback to non-incremental)
+ id: clean
if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success'
run: |
set -ex
- ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status && make build
+ ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status
+ working-directory: ./worktree-image
+ env:
+ MAKE: make -j2
+ SAGE_NUM_THREADS: 2
+
+ - name: Build
+ # This step is needed because building the modularized distributions installs some optional packages,
+ # so the editable install of sagelib needs to build the corresponding optional extension modules.
+ id: build
+ if: always() && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success')
+ run: |
+ make build
working-directory: ./worktree-image
env:
MAKE: make -j2
@@ -125,14 +137,14 @@ jobs:
COLUMNS: 120
- name: Test all files (sage -t --all --long)
- if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success')
+ if: always() && steps.build.outcome == 'success'
run: |
../sage -python -m pip install coverage
../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303
working-directory: ./worktree-image/src
- name: Prepare coverage results
- if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success')
+ if: always() && steps.build.outcome == 'success'
run: |
./venv/bin/python3 -m coverage combine src/.coverage/
./venv/bin/python3 -m coverage xml
@@ -140,7 +152,7 @@ jobs:
working-directory: ./worktree-image
- name: Upload coverage to codecov
- if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success')
+ if: always() && steps.build.outcome == 'success'
uses: codecov/codecov-action@v3
with:
files: ./worktree-image/coverage.xml
diff --git a/CITATION.cff b/CITATION.cff
index 6f4f46a6d8a..8e536719607 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -4,8 +4,8 @@ title: SageMath
abstract: SageMath is a free open-source mathematics software system.
authors:
- name: "The SageMath Developers"
-version: 10.1.beta8
+version: 10.1.beta9
doi: 10.5281/zenodo.593563
-date-released: 2023-07-30
+date-released: 2023-08-05
repository-code: "https://github.com/sagemath/sage"
url: "https://www.sagemath.org/"
diff --git a/README.md b/README.md
index 9982460cd78..2e5419541af 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@ your Windows. Make sure you allocate WSL sufficient RAM; 5GB is known to work, w
Then all instructions for installation in Linux apply.
As an alternative, you can also run Linux on Windows using Docker (see
-above) or other virtualization solutions.
+below) or other virtualization solutions.
[macOS] Preparing the Platform
------------------------------
@@ -416,6 +416,18 @@ You need to install `sage_conf`, a wheelhouse of various python packages. You ca
**NOTE:** You can find `sage` and `sagemath` pip packages but with these packages, you will encounter `ModuleNotFoundError`.
+SageMath Docker images
+----------------------
+
+[![Docker Status](http://dockeri.co/image/sagemath/sagemath)](https://hub.docker.com/r/sagemath/sagemath)
+
+SageMath is available on Docker Hub and can be downloaded by:
+``` bash
+docker pull sagemath/sagemath
+```
+
+Currently, only stable versions are kept up to date.
+
Troubleshooting
---------------
diff --git a/VERSION.txt b/VERSION.txt
index d9562f0204a..3a158e5f21f 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-SageMath version 10.1.beta8, Release Date: 2023-07-30
+SageMath version 10.1.beta9, Release Date: 2023-08-05
diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini
index e489dd26d2e..ba8597088cd 100644
--- a/build/pkgs/configure/checksums.ini
+++ b/build/pkgs/configure/checksums.ini
@@ -1,4 +1,4 @@
tarball=configure-VERSION.tar.gz
-sha1=5930a5bb8c0164176122d6ffb1143df61b990213
-md5=b70ab1eaa247dce59a59910ec8e89051
-cksum=3869087595
+sha1=0c03cb79520ba7f484e811aeb10ce528b3ea97d5
+md5=499635417f054c55dc90c9aca9494d61
+cksum=3916950255
diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt
index 33340576bb6..1d722817b70 100644
--- a/build/pkgs/configure/package-version.txt
+++ b/build/pkgs/configure/package-version.txt
@@ -1 +1 @@
-79dc3510abb05344ac7ef23d42d1228f186b7493
+ffdd9f8e55c138555338187b059d80ceecc2abaf
diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt
index 308956090b6..76fd774f5f4 100644
--- a/build/pkgs/sage_conf/install-requires.txt
+++ b/build/pkgs/sage_conf/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sage-conf ~= 10.1b8
+sage-conf ~= 10.1b9
diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt
index f2408da3bef..49a89420880 100644
--- a/build/pkgs/sage_docbuild/install-requires.txt
+++ b/build/pkgs/sage_docbuild/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sage-docbuild ~= 10.1b8
+sage-docbuild ~= 10.1b9
diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt
index 3fb4f9bd897..c222b9cdd2f 100644
--- a/build/pkgs/sage_setup/install-requires.txt
+++ b/build/pkgs/sage_setup/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sage-setup ~= 10.1b8
+sage-setup ~= 10.1b9
diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt
index 5705cd5cef9..4486a67ed75 100644
--- a/build/pkgs/sage_sws2rst/install-requires.txt
+++ b/build/pkgs/sage_sws2rst/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sage-sws2rst ~= 10.1b8
+sage-sws2rst ~= 10.1b9
diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt
index 09ddf8e9f0e..74089ecdd65 100644
--- a/build/pkgs/sagelib/install-requires.txt
+++ b/build/pkgs/sagelib/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-standard ~= 10.1b8
+sagemath-standard ~= 10.1b9
diff --git a/build/pkgs/sagemath_bliss/install-requires.txt b/build/pkgs/sagemath_bliss/install-requires.txt
index 175856b245f..7e7c708066a 100644
--- a/build/pkgs/sagemath_bliss/install-requires.txt
+++ b/build/pkgs/sagemath_bliss/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-bliss ~= 10.1b8
+sagemath-bliss ~= 10.1b9
diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt
index 2bc854cfebc..21f5efa6dd8 100644
--- a/build/pkgs/sagemath_categories/install-requires.txt
+++ b/build/pkgs/sagemath_categories/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-categories ~= 10.1b8
+sagemath-categories ~= 10.1b9
diff --git a/build/pkgs/sagemath_coxeter3/install-requires.txt b/build/pkgs/sagemath_coxeter3/install-requires.txt
index 7576be637d3..174264f9c2d 100644
--- a/build/pkgs/sagemath_coxeter3/install-requires.txt
+++ b/build/pkgs/sagemath_coxeter3/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-coxeter3 ~= 10.1b8
+sagemath-coxeter3 ~= 10.1b9
diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt
index ac5083c4105..3a2a2e06ca5 100644
--- a/build/pkgs/sagemath_environment/install-requires.txt
+++ b/build/pkgs/sagemath_environment/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-environment ~= 10.1b8
+sagemath-environment ~= 10.1b9
diff --git a/build/pkgs/sagemath_mcqd/install-requires.txt b/build/pkgs/sagemath_mcqd/install-requires.txt
index 211e612c18e..5012bc30606 100644
--- a/build/pkgs/sagemath_mcqd/install-requires.txt
+++ b/build/pkgs/sagemath_mcqd/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-mcqd ~= 10.1b8
+sagemath-mcqd ~= 10.1b9
diff --git a/build/pkgs/sagemath_meataxe/install-requires.txt b/build/pkgs/sagemath_meataxe/install-requires.txt
index 1ca467ef1b7..d9c67ecdcb4 100644
--- a/build/pkgs/sagemath_meataxe/install-requires.txt
+++ b/build/pkgs/sagemath_meataxe/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-meataxe ~= 10.1b8
+sagemath-meataxe ~= 10.1b9
diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt
index c8da8347647..cdaa97d1f23 100644
--- a/build/pkgs/sagemath_objects/install-requires.txt
+++ b/build/pkgs/sagemath_objects/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-objects ~= 10.1b8
+sagemath-objects ~= 10.1b9
diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt
index da36117bd6e..d8fa592fcc2 100644
--- a/build/pkgs/sagemath_repl/install-requires.txt
+++ b/build/pkgs/sagemath_repl/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-repl ~= 10.1b8
+sagemath-repl ~= 10.1b9
diff --git a/build/pkgs/sagemath_sirocco/install-requires.txt b/build/pkgs/sagemath_sirocco/install-requires.txt
index 417fc0e71cf..743cd19995b 100644
--- a/build/pkgs/sagemath_sirocco/install-requires.txt
+++ b/build/pkgs/sagemath_sirocco/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-sirocco ~= 10.1b8
+sagemath-sirocco ~= 10.1b9
diff --git a/build/pkgs/sagemath_tdlib/install-requires.txt b/build/pkgs/sagemath_tdlib/install-requires.txt
index 949a775737d..40c4589d4b3 100644
--- a/build/pkgs/sagemath_tdlib/install-requires.txt
+++ b/build/pkgs/sagemath_tdlib/install-requires.txt
@@ -1,2 +1,2 @@
# This file is updated on every release by the sage-update-version script
-sagemath-tdlib ~= 10.1b8
+sagemath-tdlib ~= 10.1b9
diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sage-conf/VERSION.txt
+++ b/pkgs/sage-conf/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sage-conf_pypi/VERSION.txt
+++ b/pkgs/sage-conf_pypi/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sage-docbuild/VERSION.txt
+++ b/pkgs/sage-docbuild/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sage-setup/VERSION.txt
+++ b/pkgs/sage-setup/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sage-sws2rst/VERSION.txt
+++ b/pkgs/sage-sws2rst/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-bliss/MANIFEST.in b/pkgs/sagemath-bliss/MANIFEST.in
index 689b87560e0..6d981b9d30e 100644
--- a/pkgs/sagemath-bliss/MANIFEST.in
+++ b/pkgs/sagemath-bliss/MANIFEST.in
@@ -1,5 +1,3 @@
-global-include all__sagemath_bliss.py
-
include VERSION.txt
graft sage/graphs/bliss_cpp
@@ -7,6 +5,9 @@ graft sage/graphs/bliss_cpp
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_bliss.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-bliss/VERSION.txt
+++ b/pkgs/sagemath-bliss/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4
index 361132e0cfa..b2e35673ec0 100644
--- a/pkgs/sagemath-categories/MANIFEST.in.m4
+++ b/pkgs/sagemath-categories/MANIFEST.in.m4
@@ -3,7 +3,6 @@ prune sage
include VERSION.txt
-global-include all__sagemath_categories.py
graft sage/categories
# Exclude what is already shipped in sagemath-objects
exclude sage/categories/action.*
@@ -42,6 +41,9 @@ graft sage/typeset # dep of sage.categories.tensor
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_categories.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-categories/VERSION.txt
+++ b/pkgs/sagemath-categories/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-coxeter3/MANIFEST.in b/pkgs/sagemath-coxeter3/MANIFEST.in
index 003ab8d5180..a69f2e71363 100644
--- a/pkgs/sagemath-coxeter3/MANIFEST.in
+++ b/pkgs/sagemath-coxeter3/MANIFEST.in
@@ -1,7 +1,5 @@
prune sage
-global-include all__sagemath_coxeter3.py
-
include VERSION.txt
graft sage/libs/coxeter3
@@ -9,6 +7,9 @@ graft sage/libs/coxeter3
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_coxeter3.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-coxeter3/VERSION.txt
+++ b/pkgs/sagemath-coxeter3/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-environment/MANIFEST.in b/pkgs/sagemath-environment/MANIFEST.in
index 36f8fae1845..ca4266e2bf4 100644
--- a/pkgs/sagemath-environment/MANIFEST.in
+++ b/pkgs/sagemath-environment/MANIFEST.in
@@ -1,7 +1,5 @@
prune sage
-global-include all__sagemath_environment.py
-
include sage/env.py
include sage/version.py
include sage/misc/package.py
@@ -12,4 +10,14 @@ graft sage/features
include VERSION.txt
+global-exclude all__*.py
+global-include all__sagemath_environment.py
+
+global-exclude __pycache__
global-exclude *.py[co]
+global-exclude *.bak
+global-exclude *.so
+global-exclude *~
+prune .tox
+prune build
+prune dist
diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-environment/VERSION.txt
+++ b/pkgs/sagemath-environment/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-mcqd/MANIFEST.in b/pkgs/sagemath-mcqd/MANIFEST.in
index 392d97b78e0..801e1b3e48d 100644
--- a/pkgs/sagemath-mcqd/MANIFEST.in
+++ b/pkgs/sagemath-mcqd/MANIFEST.in
@@ -1,7 +1,5 @@
prune sage
-global-include all__sagemath_mcqd.py
-
include VERSION.txt
include sage/graphs/mcqd.p*
@@ -9,6 +7,9 @@ include sage/graphs/mcqd.p*
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_mcqd.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-mcqd/VERSION.txt
+++ b/pkgs/sagemath-mcqd/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-meataxe/MANIFEST.in b/pkgs/sagemath-meataxe/MANIFEST.in
index 4cf78dd5d02..c69ce68fc40 100644
--- a/pkgs/sagemath-meataxe/MANIFEST.in
+++ b/pkgs/sagemath-meataxe/MANIFEST.in
@@ -1,7 +1,5 @@
prune sage
-global-include all__sagemath_meataxe.py
-
include VERSION.txt
include sage/libs/meataxe.p*
@@ -10,6 +8,9 @@ include sage/matrix/matrix_gfpn_dense.p*
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_meataxe.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-meataxe/README.rst b/pkgs/sagemath-meataxe/README.rst
index 088ce86478b..659edb3cf9f 100644
--- a/pkgs/sagemath-meataxe/README.rst
+++ b/pkgs/sagemath-meataxe/README.rst
@@ -28,8 +28,8 @@ About this pip-installable source distribution
This pip-installable source distribution ``sagemath-meataxe`` is a small
optional distribution for use with ``sagemath-standard``.
-This distribution provides the SageMath modules :mod:`sage.libs.meataxe`
-and :mod:`sage.matrix.matrix_gfpn_dense`.
+This distribution provides the SageMath modules ``sage.libs.meataxe``
+and ``sage.matrix.matrix_gfpn_dense``.
It provides a specialized implementation of matrices over the finite field F_q, where
q <= 255, using the `SharedMeatAxe `
diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-meataxe/VERSION.txt
+++ b/pkgs/sagemath-meataxe/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in
index 00c5e0dc4a1..98b6910849a 100644
--- a/pkgs/sagemath-objects/MANIFEST.in
+++ b/pkgs/sagemath-objects/MANIFEST.in
@@ -3,8 +3,6 @@ graft sage/cpython
include VERSION.txt
-global-include all__sagemath_objects.py
-
graft sage/structure
include sage/categories/action.*
include sage/categories/algebra_functor.*
@@ -85,6 +83,8 @@ graft sage/libs/gmp
include sage/misc/misc.* # some_tuples used in sage.misc.sage_unittest
include sage/misc/timing.p* # walltime, cputime used in sage.doctest
+global-exclude all__*.py
+global-include all__sagemath_objects.py
global-exclude *.c
global-exclude *.cpp
diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-objects/VERSION.txt
+++ b/pkgs/sagemath-objects/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in
index c54f63b15ee..ba331ec2931 100644
--- a/pkgs/sagemath-repl/MANIFEST.in
+++ b/pkgs/sagemath-repl/MANIFEST.in
@@ -1,7 +1,5 @@
prune sage
-global-include all__sagemath_repl.py
-
graft sage/doctest
graft sage/repl
include sage/misc/banner.py
@@ -11,6 +9,9 @@ include sage/misc/sage_eval.py
include VERSION.txt
+global-exclude all__*.py
+global-include all__sagemath_repl.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-repl/VERSION.txt
+++ b/pkgs/sagemath-repl/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-sirocco/MANIFEST.in b/pkgs/sagemath-sirocco/MANIFEST.in
index 7fab4dffc5d..815a868524d 100644
--- a/pkgs/sagemath-sirocco/MANIFEST.in
+++ b/pkgs/sagemath-sirocco/MANIFEST.in
@@ -1,10 +1,11 @@
-global-include all__sagemath_sirocco.py
-
include VERSION.txt
global-exclude *.c
global-exclude *.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_sirocco.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-sirocco/VERSION.txt
+++ b/pkgs/sagemath-sirocco/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/pkgs/sagemath-tdlib/MANIFEST.in b/pkgs/sagemath-tdlib/MANIFEST.in
index f3fbc97a588..614186d89ab 100644
--- a/pkgs/sagemath-tdlib/MANIFEST.in
+++ b/pkgs/sagemath-tdlib/MANIFEST.in
@@ -1,5 +1,3 @@
-global-include all__sagemath_tdlib.py
-
include VERSION.txt
global-exclude *.c
@@ -7,6 +5,9 @@ global-exclude *.cpp
include sage/graphs/graph_decompositions/sage_tdlib.cpp
+global-exclude all__sagemath_*.*
+global-include all__sagemath_tdlib.py
+
global-exclude __pycache__
global-exclude *.py[co]
global-exclude *.bak
diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/pkgs/sagemath-tdlib/VERSION.txt
+++ b/pkgs/sagemath-tdlib/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/src/MANIFEST.in b/src/MANIFEST.in
index 0f6e2a37890..bbed8838199 100644
--- a/src/MANIFEST.in
+++ b/src/MANIFEST.in
@@ -21,7 +21,6 @@ global-exclude *.cpp
include sage/cpython/debugimpl.c
include sage/graphs/base/boost_interface.cpp
include sage/graphs/cliquer/cl.c
-include sage/graphs/graph_decompositions/sage_tdlib.cpp
include sage/libs/eclib/wrap.cpp
include sage/libs/linkages/padics/relaxed/flint_helper.c
include sage/misc/inherit_comparison_impl.c
@@ -45,7 +44,21 @@ include sage/geometry/triangulation/data.cc
include sage/geometry/triangulation/functions.cc
# Exclude extension modules shipped by optional packages
-exclude sage/graphs/bliss.pyx
+exclude sage/graphs/bliss.p*
+prune sage/graphs/bliss_cpp
+prune sage/libs/coxeter3
+exclude sage/graphs/mcqd.p*
+exclude sage/libs/meataxe.p*
+exclude sage/matrix/matrix_gfpn_dense.p*
+exclude sage/graphs/graph_decomposition/tdlib.p*
+
+# Exclude all__*.py files belonging to distributions related to optional packages
+global-exclude all__sagemath_bliss.py
+global-exclude all__sagemath_coxeter3.py
+global-exclude all__sagemath_mcqd.py
+global-exclude all__sagemath_meataxe.py
+global-exclude all__sagemath_sirocco.py
+global-exclude all__sagemath_tdlib.py
global-exclude __pycache__
global-exclude *.py[co]
diff --git a/src/VERSION.txt b/src/VERSION.txt
index d06eca61e5a..6730b33848c 100644
--- a/src/VERSION.txt
+++ b/src/VERSION.txt
@@ -1 +1 @@
-10.1.beta8
+10.1.beta9
diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests
index 0c06d448887..50387881ad3 100755
--- a/src/bin/sage-fixdoctests
+++ b/src/bin/sage-fixdoctests
@@ -40,7 +40,7 @@ import sys
from argparse import ArgumentParser, FileType
from pathlib import Path
-from sage.doctest.control import skipfile
+from sage.doctest.control import DocTestDefaults, DocTestController
from sage.doctest.parsing import parse_file_optional_tags, parse_optional_tags, unparse_optional_tags, update_optional_tags
from sage.env import SAGE_ROOT
from sage.features import PythonModule
@@ -189,8 +189,12 @@ def process_block(block, src_in_lines, file_optional_tags):
return
# Error testing.
- if m := re.search(r"ModuleNotFoundError: No module named '([^']*)'", block):
- module = m.group(1)
+ if m := re.search(r"(?:ModuleNotFoundError: No module named|ImportError: cannot import name '([^']*)' from) '([^']*)'", block):
+ if m.group(1):
+ # "ImportError: cannot import name 'function_field_polymod' from 'sage.rings.function_field' (unknown location)"
+ module = m.group(2) + '.' + m.group(1)
+ else:
+ module = m.group(2)
asked_why = re.search('#.*(why|explain)', src_in_lines[first_line_num - 1])
optional = module_feature(module)
if optional and optional.name not in file_optional_tags:
@@ -224,6 +228,8 @@ def process_block(block, src_in_lines, file_optional_tags):
# NameError from top level, so keep it brief
if m := re.match("NameError: name '(.*)'", got[index_NameError:]):
name = m.group(1)
+ if name == 'x': # Don't mark it '# needs sage.symbolic'; that's almost always wrong
+ return
if feature := name_feature(name):
add_tags = [feature.name]
else:
@@ -305,17 +311,21 @@ def process_block(block, src_in_lines, file_optional_tags):
# set input and output files
-if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite:
- inputs, outputs = [args.filename[0]], [args.filename[1]]
- print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; "
- "this is deprecated. To pass two input filenames, use the option --overwrite.")
-elif args.no_overwrite:
- inputs, outputs = args.filename, [input + ".fixed" for input in args.filename]
-else:
- inputs = outputs = args.filename
+def output_filename(filename):
+ if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite:
+ if args.filename[0] == filename:
+ return args.filename[1]
+ else:
+ return None
+ return filename + ".fixed"
+ if args.no_overwrite:
+ return filename + ".fixed"
+ return filename
# Test the doctester, putting the output of the test into sage's temporary directory
-if not args.no_test:
+if args.no_test:
+ doc_out = ''
+else:
executable = f'{os.path.relpath(args.venv)}/bin/sage' if args.venv else 'sage'
environment_args = f'--environment {args.environment} ' if args.environment != runtest_default_environment else ''
long_args = f'--long ' if args.long else ''
@@ -329,38 +339,61 @@ if not args.no_test:
if status := os.waitstatus_to_exitcode(os.system(f'{cmdline} > {shlex.quote(doc_file)}')):
print(f'Doctester exited with error status {status}')
sys.exit(status)
+ # Run the doctester, putting the output of the test into sage's temporary directory
+ if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite:
+ print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; "
+ "this is deprecated. To pass two input filenames, use the option --overwrite.")
-for input, output in zip(inputs, outputs):
- if (skipfile_result := skipfile(input, True, log=print)) is True:
- continue
-
- if args.no_test:
- doc_out = ''
+ input_filenames = [args.filename[0]]
else:
- # Run the doctester, putting the output of the test into sage's temporary directory
- cmdline = f'{shlex.quote(executable)} -t {environment_args}{long_args}{probe_args}{lib_args}{shlex.quote(input)}'
- print(f'Running "{cmdline}"')
- os.system(f'{cmdline} > {shlex.quote(doc_file)}')
+ input_filenames = args.filename
+ input_args = " ".join(shlex.quote(f) for f in input_filenames)
+ cmdline = f'{shlex.quote(executable)} -t -p {environment_args}{long_args}{probe_args}{lib_args}{input_args}'
+ print(f'Running "{cmdline}"')
+ os.system(f'{cmdline} > {shlex.quote(doc_file)}')
- with open(doc_file, 'r') as doc:
- doc_out = doc.read()
+ with open(doc_file, 'r') as doc:
+ doc_out = doc.read()
# echo control messages
for m in re.finditer('^Skipping .*', doc_out, re.MULTILINE):
print('sage-runtests: ' + m.group(0))
- break
- else:
- sep = "**********************************************************************\n"
- doctests = doc_out.split(sep)
+
+sep = "**********************************************************************\n"
+doctests = doc_out.split(sep)
+
+seen = set()
+
+def block_filename(block):
+ if not (m := re.match('File "([^"]*)", line ([0-9]+), in ', block)):
+ return None
+ return m.group(1)
+
+def expanded_filename_args():
+ DD = DocTestDefaults(optional='all', warn_long=10000)
+ DC = DocTestController(DD, input_filenames)
+ DC.add_files()
+ DC.expand_files_into_sources()
+ for source in DC.sources:
+ yield source.path
+
+def process_grouped_blocks(grouped_iterator):
+
+ for input, blocks in grouped_iterator:
+
+ if not input: # Blocks of noise
+ continue
+ if input in seen:
+ continue
+ seen.add(input)
with open(input, 'r') as test_file:
src_in = test_file.read()
src_in_lines = src_in.splitlines()
shallow_copy_of_src_in_lines = list(src_in_lines)
-
file_optional_tags = set(parse_file_optional_tags(enumerate(src_in_lines)))
- for block in doctests:
+ for block in blocks:
process_block(block, src_in_lines, file_optional_tags)
# Now source line numbers do not matter any more, and lines can be real lines again
@@ -392,20 +425,26 @@ for input, output in zip(inputs, outputs):
persistent_optional_tags = {}
if src_in_lines != shallow_copy_of_src_in_lines:
- with open(output, 'w') as test_output:
- for line in src_in_lines:
- if line is None:
- continue
- test_output.write(line)
- test_output.write('\n')
-
- # Show summary of changes
- if input != output:
- print("The fixed doctests have been saved as '{0}'.".format(output))
+ if (output := output_filename(input)) is None:
+ print(f"Not saving modifications made in '{input}'")
else:
- relative = os.path.relpath(output, SAGE_ROOT)
- print(f"The input file '{output}' has been overwritten.")
- if not relative.startswith('..'):
- subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT)
+ with open(output, 'w') as test_output:
+ for line in src_in_lines:
+ if line is None:
+ continue
+ test_output.write(line)
+ test_output.write('\n')
+ # Show summary of changes
+ if input != output :
+ print("The fixed doctests have been saved as '{0}'.".format(output))
+ else:
+ relative = os.path.relpath(output, SAGE_ROOT)
+ print(f"The input file '{output}' has been overwritten.")
+ if not relative.startswith('..'):
+ subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT)
else:
print(f"No fixes made in '{input}'")
+
+process_grouped_blocks(
+ itertools.chain(itertools.groupby(doctests, block_filename),
+ ((filename, []) for filename in expanded_filename_args())))
diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests
index 4d606c5a3a8..01b7ca44868 100755
--- a/src/bin/sage-runtests
+++ b/src/bin/sage-runtests
@@ -175,13 +175,18 @@ if __name__ == "__main__":
pytest_options = []
if args.verbose:
pytest_options.append("-v")
- # #31924: Do not run pytest on individual Python files unless
- # they match the pytest file pattern. However, pass names
- # of directories. We use 'not os.path.isfile(f)' for this so that
- # we do not silently hide typos.
- filenames = [f for f in args.filenames
- if f.endswith("_test.py") or not os.path.isfile(f)]
- if filenames or not args.filenames:
+
+ # #35999: no filename in arguments defaults to "src"
+ if not args.filenames:
+ filenames = [SAGE_SRC]
+ else:
+ # #31924: Do not run pytest on individual Python files unless
+ # they match the pytest file pattern. However, pass names
+ # of directories. We use 'not os.path.isfile(f)' for this so that
+ # we do not silently hide typos.
+ filenames = [f for f in args.filenames
+ if f.endswith("_test.py") or not os.path.isfile(f)]
+ if filenames:
print(f"Running pytest on {filenames} with options {pytest_options}")
exit_code_pytest = pytest.main(filenames + pytest_options)
if exit_code_pytest == 5:
diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh
index 1800ec2771f..8c1a833ccb2 100644
--- a/src/bin/sage-version.sh
+++ b/src/bin/sage-version.sh
@@ -4,6 +4,6 @@
# which stops "setup.py develop" from rewriting it as a Python file.
:
# This file is auto-generated by the sage-update-version script, do not edit!
-SAGE_VERSION='10.1.beta8'
-SAGE_RELEASE_DATE='2023-07-30'
-SAGE_VERSION_BANNER='SageMath version 10.1.beta8, Release Date: 2023-07-30'
+SAGE_VERSION='10.1.beta9'
+SAGE_RELEASE_DATE='2023-08-05'
+SAGE_VERSION_BANNER='SageMath version 10.1.beta9, Release Date: 2023-08-05'
diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst
index a4f05a0fdc7..92ae74b30db 100644
--- a/src/doc/en/reference/combinat/module_list.rst
+++ b/src/doc/en/reference/combinat/module_list.rst
@@ -143,7 +143,6 @@ Comprehensive Module List
sage/combinat/integer_vector_weighted
sage/combinat/integer_vectors_mod_permgroup
sage/combinat/interval_posets
- sage/combinat/k_regular_sequence
sage/combinat/k_tableau
sage/combinat/kazhdan_lusztig
sage/combinat/key_polynomial
@@ -206,6 +205,7 @@ Comprehensive Module List
sage/combinat/quickref
sage/combinat/ranker
sage/combinat/recognizable_series
+ sage/combinat/regular_sequence
sage/combinat/restricted_growth
sage/combinat/ribbon
sage/combinat/ribbon_shaped_tableau
diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py
index 6ffe90f7dda..34abf305f70 100644
--- a/src/sage/calculus/calculus.py
+++ b/src/sage/calculus/calculus.py
@@ -80,23 +80,23 @@
::
- sage: f(x,y)=x^2*y+y^2+y
- sage: f.diff() # gradient
+ sage: f(x,y) = x^2*y + y^2 + y
+ sage: f.diff() # gradient
(x, y) |--> (2*x*y, x^2 + 2*y + 1)
- sage: solve(list(f.diff()),[x,y])
+ sage: solve(list(f.diff()), [x,y])
[[x == -I, y == 0], [x == I, y == 0], [x == 0, y == (-1/2)]]
sage: H=f.diff(2); H # Hessian matrix
[(x, y) |--> 2*y (x, y) |--> 2*x]
[(x, y) |--> 2*x (x, y) |--> 2]
- sage: H(x=0,y=-1/2)
+ sage: H(x=0, y=-1/2)
[-1 0]
[ 0 2]
- sage: H(x=0,y=-1/2).eigenvalues()
+ sage: H(x=0, y=-1/2).eigenvalues()
[-1, 2]
Here we calculate the Jacobian for the polar coordinate transformation::
- sage: T(r,theta)=[r*cos(theta),r*sin(theta)]
+ sage: T(r,theta) = [r*cos(theta),r*sin(theta)]
sage: T
(r, theta) |--> (r*cos(theta), r*sin(theta))
sage: T.diff() # Jacobian matrix
@@ -117,7 +117,7 @@
ValueError: No differentiation variable specified.
Simplifying symbolic sums is also possible, using the
-sum command, which also uses Maxima in the background::
+:func:`sum` command, which also uses Maxima in the background::
sage: k, m = var('k, m')
sage: sum(1/k^4, k, 1, oo)
@@ -182,19 +182,19 @@
sage: f(x=pi)
0
-We can also make a ``CallableSymbolicExpression``,
-which is a ``SymbolicExpression`` that is a function of
+We can also make a :class:`CallableSymbolicExpression`,
+which is a :class:`SymbolicExpression` that is a function of
specified variables in a fixed order. Each
-``SymbolicExpression`` has a
+:class:`SymbolicExpression` has a
``function(...)`` method that is used to create a
-``CallableSymbolicExpression``, as illustrated below::
+:class:`CallableSymbolicExpression`, as illustrated below::
sage: u = log((2-x)/(y+5))
sage: f = u.function(x, y); f
(x, y) |--> log(-(x - 2)/(y + 5))
There is an easier way of creating a
-``CallableSymbolicExpression``, which relies on the
+:class:`CallableSymbolicExpression`, which relies on the
Sage preparser.
::
@@ -267,7 +267,8 @@
sage: CC(f)
1.12762596520638 + 1.17520119364380*I
sage: ComplexField(200)(f)
- 1.1276259652063807852262251614026720125478471180986674836290 + 1.1752011936438014568823818505956008151557179813340958702296*I
+ 1.1276259652063807852262251614026720125478471180986674836290
+ + 1.1752011936438014568823818505956008151557179813340958702296*I
sage: ComplexField(100)(f)
1.1276259652063807852262251614 + 1.1752011936438014568823818506*I
@@ -286,8 +287,9 @@
We can, of course, substitute::
- sage: f(n9=9,n7=n6)
- 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + 387420490/387420489
+ sage: f(n9=9, n7=n6)
+ 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8
+ + 387420490/387420489
TESTS:
@@ -317,7 +319,7 @@
sage: maxima.eval('expand((x+y)^3)')
'27'
-If the copy of maxima used by the symbolic calculus package were
+If the copy of Maxima used by the symbolic calculus package were
the same as the default one, then the following would return 27,
which would be very confusing indeed!
@@ -446,27 +448,27 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False):
INPUT:
- - ``expression`` - a symbolic expression
+ - ``expression`` -- a symbolic expression
- - ``v`` - a variable or variable name
+ - ``v`` -- a variable or variable name
- - ``a`` - lower endpoint of the sum
+ - ``a`` -- lower endpoint of the sum
- - ``b`` - upper endpoint of the sum
+ - ``b`` -- upper endpoint of the sum
- - ``algorithm`` - (default: ``'maxima'``) one of
+ - ``algorithm`` -- (default: ``'maxima'``) one of
- - ``'maxima'`` - use Maxima (the default)
+ - ``'maxima'`` -- use Maxima (the default)
- - ``'maple'`` - (optional) use Maple
+ - ``'maple'`` -- (optional) use Maple
- - ``'mathematica'`` - (optional) use Mathematica
+ - ``'mathematica'`` -- (optional) use Mathematica
- - ``'giac'`` - (optional) use Giac
+ - ``'giac'`` -- (optional) use Giac
- - ``'sympy'`` - use SymPy
+ - ``'sympy'`` -- use SymPy
- - ``hold`` - (default: ``False``) if ``True`` don't evaluate
+ - ``hold`` -- (default: ``False``) if ``True``, don't evaluate
EXAMPLES::
@@ -493,13 +495,13 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False):
And some truncations thereof::
sage: assume(n>1)
- sage: symbolic_sum(binomial(n,k),k,1,n)
+ sage: symbolic_sum(binomial(n,k), k, 1, n)
2^n - 1
- sage: symbolic_sum(binomial(n,k),k,2,n)
+ sage: symbolic_sum(binomial(n,k), k, 2, n)
2^n - n - 1
- sage: symbolic_sum(binomial(n,k),k,0,n-1)
+ sage: symbolic_sum(binomial(n,k), k, 0, n-1)
2^n - 1
- sage: symbolic_sum(binomial(n,k),k,1,n-1)
+ sage: symbolic_sum(binomial(n,k), k, 1, n-1)
2^n - 2
The binomial theorem::
@@ -556,22 +558,22 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False):
...
ValueError: Sum is divergent.
sage: forget()
- sage: assumptions() # check the assumptions were really forgotten
+ sage: assumptions() # check the assumptions were really forgotten
[]
A summation performed by Mathematica::
- sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'mathematica') # optional - mathematica
+ sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='mathematica') # optional - mathematica
pi*coth(pi)
An example of this summation with Giac::
- sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'giac')
+ sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='giac')
(pi*e^(2*pi) - pi*e^(-2*pi))/(e^(2*pi) + e^(-2*pi) - 2)
The same summation is solved by SymPy::
- sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'sympy')
+ sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='sympy')
pi/tanh(pi)
SymPy and Maxima 5.39.0 can do the following (see
@@ -584,7 +586,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False):
Use Maple as a backend for summation::
- sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm = 'maple') # optional - maple
+ sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm='maple') # optional - maple
(x + 1)^n
If you don't want to evaluate immediately give the ``hold`` keyword::
@@ -686,17 +688,17 @@ def nintegral(ex, x, a, b,
INPUT:
- - ``x`` - variable to integrate with respect to
+ - ``x`` -- variable to integrate with respect to
- - ``a`` - lower endpoint of integration
+ - ``a`` -- lower endpoint of integration
- - ``b`` - upper endpoint of integration
+ - ``b`` -- upper endpoint of integration
- - ``desired_relative_error`` - (default: '1e-8') the
+ - ``desired_relative_error`` -- (default: ``1e-8``) the
desired relative error
- - ``maximum_num_subintervals`` - (default: 200)
- maxima number of subintervals
+ - ``maximum_num_subintervals`` -- (default: 200)
+ maximal number of subintervals
OUTPUT:
@@ -709,26 +711,26 @@ def nintegral(ex, x, a, b,
- an error code:
- - ``0`` - no problems were encountered
+ - ``0`` -- no problems were encountered
- - ``1`` - too many subintervals were done
+ - ``1`` -- too many subintervals were done
- - ``2`` - excessive roundoff error
+ - ``2`` -- excessive roundoff error
- - ``3`` - extremely bad integrand behavior
+ - ``3`` -- extremely bad integrand behavior
- - ``4`` - failed to converge
+ - ``4`` -- failed to converge
- - ``5`` - integral is probably divergent or slowly
+ - ``5`` -- integral is probably divergent or slowly
convergent
- - ``6`` - the input is invalid; this includes the case of
- desired_relative_error being too small to be achieved
+ - ``6`` -- the input is invalid; this includes the case of
+ ``desired_relative_error`` being too small to be achieved
- ALIAS: nintegrate is the same as nintegral
+ ALIAS: :func:`nintegrate` is the same as :func:`nintegral`
REMARK: There is also a function
- ``numerical_integral`` that implements numerical
+ :func:`numerical_integral` that implements numerical
integration using the GSL C library. It is potentially much faster
and applies to arbitrary user defined functions.
@@ -741,7 +743,7 @@ def nintegral(ex, x, a, b,
::
sage: f = x
- sage: f.nintegral(x,0,1,1e-14)
+ sage: f.nintegral(x, 0, 1, 1e-14)
(0.0, 0.0, 0, 6)
EXAMPLES::
@@ -750,7 +752,7 @@ def nintegral(ex, x, a, b,
sage: f.nintegral(x, 0, 1)
(0.5284822353142306, 4.163...e-11, 231, 0)
- We can also use the ``numerical_integral`` function,
+ We can also use the :func:`numerical_integral` function,
which calls the GSL C library.
::
@@ -785,7 +787,7 @@ def nintegral(ex, x, a, b,
sage: f.nintegrate(x,0,1)
(-480.000000000000..., 5.32907051820075...e-12, 21, 0)
- It is just because every floating point evaluation of return -480.0
+ It is just because every floating point evaluation of `f` returns `-480.0`
in floating point.
Important note: using PARI/GP one can compute numerical integrals
@@ -831,25 +833,25 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False):
INPUT:
- - ``expression`` - a symbolic expression
+ - ``expression`` -- a symbolic expression
- - ``v`` - a variable or variable name
+ - ``v`` -- a variable or variable name
- - ``a`` - lower endpoint of the product
+ - ``a`` -- lower endpoint of the product
- - ``b`` - upper endpoint of the prduct
+ - ``b`` -- upper endpoint of the prduct
- - ``algorithm`` - (default: ``'maxima'``) one of
+ - ``algorithm`` -- (default: ``'maxima'``) one of
- - ``'maxima'`` - use Maxima (the default)
+ - ``'maxima'`` -- use Maxima (the default)
- - ``'giac'`` - use Giac
+ - ``'giac'`` -- use Giac
- - ``'sympy'`` - use SymPy
+ - ``'sympy'`` -- use SymPy
- - ``'mathematica'`` - (optional) use Mathematica
+ - ``'mathematica'`` -- (optional) use Mathematica
- - ``hold`` - (default: ``False``) if ``True`` don't evaluate
+ - ``hold`` - (default: ``False``) if ``True``, don't evaluate
EXAMPLES::
@@ -935,50 +937,50 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False):
def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
r"""
- Return the minimal polynomial of self, if possible.
+ Return the minimal polynomial of ``self``, if possible.
INPUT:
- - ``var`` - polynomial variable name (default 'x')
+ - ``var`` -- polynomial variable name (default 'x')
- - ``algorithm`` - 'algebraic' or 'numerical' (default
+ - ``algorithm`` -- ``'algebraic'`` or ``'numerical'`` (default
both, but with numerical first)
- - ``bits`` - the number of bits to use in numerical
+ - ``bits`` -- the number of bits to use in numerical
approx
- - ``degree`` - the expected algebraic degree
+ - ``degree`` -- the expected algebraic degree
- - ``epsilon`` - return without error as long as
+ - ``epsilon`` -- return without error as long as
f(self) epsilon, in the case that the result cannot be proven.
- All of the above parameters are optional, with epsilon=0, bits and
- degree tested up to 1000 and 24 by default respectively. The
+ All of the above parameters are optional, with epsilon=0, ``bits`` and
+ ``degree`` tested up to 1000 and 24 by default respectively. The
numerical algorithm will be faster if bits and/or degree are given
explicitly. The algebraic algorithm ignores the last three
parameters.
- OUTPUT: The minimal polynomial of self. If the numerical algorithm
- is used then it is proved symbolically when epsilon=0 (default).
+ OUTPUT: The minimal polynomial of ``self``. If the numerical algorithm
+ is used, then it is proved symbolically when ``epsilon=0`` (default).
If the minimal polynomial could not be found, two distinct kinds of
errors are raised. If no reasonable candidate was found with the
- given bit/degree parameters, a ``ValueError`` will be
+ given ``bits``/``degree`` parameters, a :class:`ValueError` will be
raised. If a reasonable candidate was found but (perhaps due to
limits in the underlying symbolic package) was unable to be proved
- correct, a ``NotImplementedError`` will be raised.
+ correct, a :class:`NotImplementedError` will be raised.
ALGORITHM: Two distinct algorithms are used, depending on the
algorithm parameter. By default, the numerical algorithm is
attempted first, then the algebraic one.
- Algebraic: Attempt to evaluate this expression in QQbar, using
+ Algebraic: Attempt to evaluate this expression in ``QQbar``, using
cyclotomic fields to resolve exponential and trig functions at
- rational multiples of pi, field extensions to handle roots and
+ rational multiples of `\pi`, field extensions to handle roots and
rational exponents, and computing compositums to represent the full
expression as an element of a number field where the minimal
- polynomial can be computed exactly. The bits, degree, and epsilon
+ polynomial can be computed exactly. The ``bits``, ``degree``, and ``epsilon``
parameters are ignored.
Numerical: Computes a numerical approximation of
@@ -989,8 +991,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
vanishing. If this fails, and ``epsilon`` is non-zero,
return `f` if and only if
`f(\mathtt{self}) < \mathtt{epsilon}`.
- Otherwise raise a ``ValueError`` (if no suitable
- candidate was found) or a ``NotImplementedError`` (if a
+ Otherwise raise a :class:`ValueError` (if no suitable
+ candidate was found) or a :class:`NotImplementedError` (if a
likely candidate was found but could not be proved correct).
EXAMPLES: First some simple examples::
@@ -1014,7 +1016,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
sage: sin(pi/7).minpoly()
x^6 - 7/4*x^4 + 7/8*x^2 - 7/64
sage: minpoly(exp(I*pi/17))
- x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
+ x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8
+ - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
Here we verify it gives the same result as the abstract number
field.
@@ -1027,14 +1030,15 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
sage: (a+b+a*b).absolute_minpoly()
x^4 - 22*x^2 - 48*x - 23
- The minpoly function is used implicitly when creating
+ The :func:`minpoly` function is used implicitly when creating
number fields::
sage: x = var('x')
sage: eqn = x^3 + sqrt(2)*x + 5 == 0
sage: a = solve(eqn, x)[0].rhs()
sage: QQ[a]
- Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 with a = 0.7185272465828846? - 1.721353471724806?*I
+ Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25
+ with a = 0.7185272465828846? - 1.721353471724806?*I
Here we solve a cubic and then recover it from its complicated
radical expansion.
@@ -1043,7 +1047,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
sage: f = x^3 - x + 1
sage: a = f.solve(x)[0].rhs(); a
- -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)
+ -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1)
+ - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)
sage: a.minpoly()
x^3 - x + 1
@@ -1056,7 +1061,9 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
sage: f = a.minpoly(); f
x^8 - 40*x^6 + 352*x^4 - 960*x^2 + 576
sage: f(a)
- (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + 576
+ (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6
+ + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2
+ + 576
sage: f(a).expand()
0
@@ -1083,9 +1090,11 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
::
sage: cos(pi/33).minpoly(algorithm='algebraic')
- x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024
+ x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5
+ - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024
sage: cos(pi/33).minpoly(algorithm='numerical')
- x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024
+ x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5
+ - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024
Sometimes it fails, as it must given that some numbers aren't algebraic::
@@ -1162,12 +1171,12 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv):
INPUT:
- - ``dir`` - (default: None); dir may have the value
- 'plus' (or '+' or 'right' or 'above') for a limit from above,
- 'minus' (or '-' or 'left' or 'below') for a limit from below, or may be omitted
+ - ``dir`` -- (default: ``None``); may have the value
+ ``'plus'`` (or ``'+'`` or ``'right'`` or ``'above'``) for a limit from above,
+ ``'minus'`` (or ``'-'`` or ``'left'`` or ``'below'``) for a limit from below, or may be omitted
(implying a two-sided limit is to be computed).
- - ``taylor`` - (default: False); if True, use Taylor
+ - ``taylor`` -- (default: ``False``); if ``True``, use Taylor
series, which allows more limits to be computed (but may also
crash in some obscure cases due to bugs in Maxima).
@@ -1175,8 +1184,8 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv):
.. note::
- The output may also use 'und' (undefined), 'ind'
- (indefinite but bounded), and 'infinity' (complex
+ The output may also use ``und`` (undefined), ``ind``
+ (indefinite but bounded), and ``infinity`` (complex
infinity).
EXAMPLES::
@@ -1488,7 +1497,7 @@ def mma_free_limit(expression, v, a, dir=None):
- ``expression`` -- symbolic expression
- ``v`` -- variable
- ``a`` -- value where the variable goes to
- - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default:``None``)
+ - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default: ``None``)
EXAMPLES::
@@ -1547,19 +1556,19 @@ def laplace(ex, t, s, algorithm='maxima'):
INPUT:
- - ``ex`` - a symbolic expression
+ - ``ex`` -- a symbolic expression
- - ``t`` - independent variable
+ - ``t`` -- independent variable
- - ``s`` - transform parameter
+ - ``s`` -- transform parameter
- - ``algorithm`` - (default: ``'maxima'``) one of
+ - ``algorithm`` -- (default: ``'maxima'``) one of
- - ``'maxima'`` - use Maxima (the default)
+ - ``'maxima'`` -- use Maxima (the default)
- - ``'sympy'`` - use SymPy
+ - ``'sympy'`` -- use SymPy
- - ``'giac'`` - use Giac
+ - ``'giac'`` -- use Giac
.. NOTE::
@@ -1622,7 +1631,7 @@ def laplace(ex, t, s, algorithm='maxima'):
Next we form the augmented matrix of the above system::
- sage: A = matrix([[s, 16, 270],[1, s, 90+1/s]])
+ sage: A = matrix([[s, 16, 270], [1, s, 90+1/s]])
sage: E = A.echelon_form()
sage: xt = E[0,2].inverse_laplace(s,t)
sage: yt = E[1,2].inverse_laplace(s,t)
@@ -1630,11 +1639,11 @@ def laplace(ex, t, s, algorithm='maxima'):
-91/2*e^(4*t) + 629/2*e^(-4*t) + 1
sage: yt
91/8*e^(4*t) + 629/8*e^(-4*t)
- sage: p1 = plot(xt,0,1/2,rgbcolor=(1,0,0))
- sage: p2 = plot(yt,0,1/2,rgbcolor=(0,1,0))
+ sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # needs sage.plot
+ sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # needs sage.plot
sage: import tempfile
- sage: with tempfile.NamedTemporaryFile(suffix=".png") as f:
- ....: (p1+p2).save(f.name)
+ sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot
+ ....: (p1 + p2).save(f.name)
Another example::
@@ -1789,19 +1798,19 @@ def inverse_laplace(ex, s, t, algorithm='maxima'):
INPUT:
- - ``ex`` - a symbolic expression
+ - ``ex`` -- a symbolic expression
- - ``s`` - transform parameter
+ - ``s`` -- transform parameter
- - ``t`` - independent variable
+ - ``t`` -- independent variable
- - ``algorithm`` - (default: ``'maxima'``) one of
+ - ``algorithm`` -- (default: ``'maxima'``) one of
- - ``'maxima'`` - use Maxima (the default)
+ - ``'maxima'`` -- use Maxima (the default)
- - ``'sympy'`` - use SymPy
+ - ``'sympy'`` -- use SymPy
- - ``'giac'`` - use Giac
+ - ``'giac'`` -- use Giac
.. SEEALSO::
@@ -1843,9 +1852,11 @@ def inverse_laplace(ex, s, t, algorithm='maxima'):
Transform a rational expression::
- sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, algorithm='giac')
- -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) +
- e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2)
+ sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t,
+ ....: algorithm='giac')
+ -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1))
+ - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + e^(-t + 1))*heaviside(t - 1)
+ + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2)
sage: inverse_laplace(1/(s - 1), s, x)
e^x
@@ -1955,7 +1966,7 @@ def at(ex, *args, **kwds):
We do not import ``at`` at the top level, but we can use it
as a synonym for substitution if we import it::
- sage: g = x^3-3
+ sage: g = x^3 - 3
sage: from sage.calculus.calculus import at
sage: at(g, x=1)
-2
@@ -1970,15 +1981,16 @@ def at(ex, *args, **kwds):
u(h + x)
sage: diff(u(x+h), x)
D[0](u)(h + x)
- sage: taylor(u(x+h),h,0,4)
- 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x)
+ sage: taylor(u(x+h), h, 0, 4)
+ 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x)
+ + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x)
We compute a Laplace transform::
sage: var('s,t')
(s, t)
- sage: f=function('f')(t)
- sage: f.diff(t,2)
+ sage: f = function('f')(t)
+ sage: f.diff(t, 2)
diff(f(t), t, t)
sage: f.diff(t,2).laplace(t,s)
s^2*laplace(f(t), t, s) - s*f(0) - D[0](f)(0)
@@ -2078,7 +2090,7 @@ def dummy_laplace(*args):
sage: from sage.calculus.calculus import dummy_laplace
sage: s,t = var('s,t')
sage: f = function('f')
- sage: dummy_laplace(f(t),t,s)
+ sage: dummy_laplace(f(t), t, s)
laplace(f(t), t, s)
"""
return _laplace(args[0], var(repr(args[1])), var(repr(args[2])))
@@ -2086,7 +2098,7 @@ def dummy_laplace(*args):
def dummy_inverse_laplace(*args):
"""
- This function is called to create formal wrappers of inverse laplace
+ This function is called to create formal wrappers of inverse Laplace
transforms that Maxima can't compute:
EXAMPLES::
@@ -2094,7 +2106,7 @@ def dummy_inverse_laplace(*args):
sage: from sage.calculus.calculus import dummy_inverse_laplace
sage: s,t = var('s,t')
sage: F = function('F')
- sage: dummy_inverse_laplace(F(s),s,t)
+ sage: dummy_inverse_laplace(F(s), s, t)
ilt(F(s), s, t)
"""
return _inverse_laplace(args[0], var(repr(args[1])), var(repr(args[2])))
@@ -2108,7 +2120,7 @@ def dummy_pochhammer(*args):
sage: from sage.calculus.calculus import dummy_pochhammer
sage: s,t = var('s,t')
- sage: dummy_pochhammer(s,t)
+ sage: dummy_pochhammer(s, t)
gamma(s + t)/gamma(s)
"""
x, y = args
@@ -2224,12 +2236,12 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima):
INPUT:
- - ``x`` - a string
+ - ``x`` -- a string
- - ``equals_sub`` - (default: False) if True, replace
+ - ``equals_sub`` -- (default: ``False``) if ``True``, replace
'=' by '==' in self
- - ``maxima`` - (default: the calculus package's
+ - ``maxima`` -- (default: the calculus package's copy of
Maxima) the Maxima interpreter to use.
EXAMPLES::
@@ -2415,7 +2427,7 @@ def mapped_opts(v):
INPUT:
- - ``v`` - an object
+ - ``v`` -- an object
OUTPUT: a string.
@@ -2548,13 +2560,13 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars
INPUT:
- - ``s`` - a string
+ - ``s`` -- a string
- - ``syms`` - (default: {}) dictionary of
- strings to be regarded as symbols or functions ;
+ - ``syms`` -- (default: ``{}``) dictionary of
+ strings to be regarded as symbols or functions;
keys are pairs (string, number of arguments)
- - ``accept_sequence`` - (default: False) controls whether
+ - ``accept_sequence`` -- (default: ``False``) controls whether
to allow a (possibly nested) set of lists and tuples
as input
@@ -2562,23 +2574,25 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars
EXAMPLES::
+ sage: from sage.calculus.calculus import symbolic_expression_from_string
sage: y = var('y')
- sage: sage.calculus.calculus.symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]',syms={('spam',0):y},accept_sequence=True)
+ sage: symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]',
+ ....: syms={('spam',0): y}, accept_sequence=True)
[0, 3*y + e^pi]
TESTS:
Check that the precision is preserved (:trac:`28814`)::
- sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(1/3)))
+ sage: symbolic_expression_from_string(str(RealField(100)(1/3)))
0.3333333333333333333333333333
- sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(10^-500/3)))
+ sage: symbolic_expression_from_string(str(RealField(100)(10^-500/3)))
3.333333333333333333333333333e-501
The Giac interface uses a different parser (:trac:`30133`)::
sage: from sage.calculus.calculus import SR_parser_giac
- sage: sage.calculus.calculus.symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac)
+ sage: symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac)
e
"""
if syms is None:
diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py
index 6dabb5b1121..afe63ccb954 100644
--- a/src/sage/calculus/desolvers.py
+++ b/src/sage/calculus/desolvers.py
@@ -874,8 +874,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"):
::
- sage: P1 = plot([solx,soly], (0,1))
- sage: P2 = parametric_plot((solx,soly), (0,1))
+ sage: P1 = plot([solx,soly], (0,1)) # needs sage.plot
+ sage: P2 = parametric_plot((solx,soly), (0,1)) # needs sage.plot
Now type ``show(P1)``, ``show(P2)`` to view these plots.
@@ -892,7 +892,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"):
sage: desolve_system([de1, de2], [x1, x2], ics=[1,1], ivar=t)
Traceback (most recent call last):
...
- ValueError: Initial conditions aren't complete: number of vars is different from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)]
+ ValueError: Initial conditions aren't complete: number of vars is different
+ from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)]
Check that :trac:`9825` is fixed::
@@ -1013,9 +1014,9 @@ def eulers_method(f, x0, y0, h, x1, algorithm="table"):
::
sage: pts = eulers_method(5*x+y-5,0,1,1/2,1,algorithm="none")
- sage: P1 = list_plot(pts)
- sage: P2 = line(pts)
- sage: (P1+P2).show()
+ sage: P1 = list_plot(pts) # needs sage.plot
+ sage: P2 = line(pts) # needs sage.plot
+ sage: (P1 + P2).show() # needs sage.plot
AUTHORS:
@@ -1163,7 +1164,7 @@ def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1):
sage: from sage.calculus.desolvers import eulers_method_2x2_plot
sage: f = lambda z : z[2]; g = lambda z : -sin(z[1])
- sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0)
+ sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # needs sage.plot
"""
from sage.plot.line import line
@@ -1430,13 +1431,14 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1
Lotka Volterra system::
sage: from sage.calculus.desolvers import desolve_system_rk4
- sage: x,y,t=var('x y t')
- sage: P=desolve_system_rk4([x*(1-y),-y*(1-x)],[x,y],ics=[0,0.5,2],ivar=t,end_points=20)
- sage: Q=[ [i,j] for i,j,k in P]
- sage: LP=list_plot(Q)
+ sage: x,y,t = var('x y t')
+ sage: P = desolve_system_rk4([x*(1-y),-y*(1-x)], [x,y], ics=[0,0.5,2],
+ ....: ivar=t, end_points=20)
+ sage: Q = [[i,j] for i,j,k in P]
+ sage: LP = list_plot(Q) # needs sage.plot
- sage: Q=[ [j,k] for i,j,k in P]
- sage: LP=list_plot(Q)
+ sage: Q = [[j,k] for i,j,k in P]
+ sage: LP = list_plot(Q) # needs sage.plot
ALGORITHM:
@@ -1570,49 +1572,52 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=()
Lotka Volterra Equations::
sage: from sage.calculus.desolvers import desolve_odeint
- sage: x,y=var('x,y')
- sage: f=[x*(1-y),-y*(1-x)]
- sage: sol=desolve_odeint(f,[0.5,2],srange(0,10,0.1),[x,y])
- sage: p=line(zip(sol[:,0],sol[:,1]))
- sage: p.show()
+ sage: x,y = var('x,y')
+ sage: f = [x*(1-y), -y*(1-x)]
+ sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # needs scipy
+ sage: p = line(zip(sol[:,0],sol[:,1])) # needs scipy sage.plot
+ sage: p.show() # needs scipy sage.plot
Lorenz Equations::
- sage: x,y,z=var('x,y,z')
+ sage: x,y,z = var('x,y,z')
sage: # Next we define the parameters
- sage: sigma=10
- sage: rho=28
- sage: beta=8/3
+ sage: sigma = 10
+ sage: rho = 28
+ sage: beta = 8/3
sage: # The Lorenz equations
- sage: lorenz=[sigma*(y-x),x*(rho-z)-y,x*y-beta*z]
+ sage: lorenz = [sigma*(y-x),x*(rho-z)-y,x*y-beta*z]
sage: # Time and initial conditions
- sage: times=srange(0,50.05,0.05)
- sage: ics=[0,1,1]
- sage: sol=desolve_odeint(lorenz,ics,times,[x,y,z],rtol=1e-13,atol=1e-14)
+ sage: times = srange(0,50.05,0.05)
+ sage: ics = [0,1,1]
+ sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # needs scipy
+ ....: rtol=1e-13, atol=1e-14)
One-dimensional stiff system::
- sage: y= var('y')
- sage: epsilon=0.01
- sage: f=y^2*(1-y)
- sage: ic=epsilon
- sage: t=srange(0,2/epsilon,1)
- sage: sol=desolve_odeint(f,ic,t,y,rtol=1e-9,atol=1e-10,compute_jac=True)
- sage: p=points(zip(t,sol[:,0]))
- sage: p.show()
+ sage: y = var('y')
+ sage: epsilon = 0.01
+ sage: f = y^2*(1-y)
+ sage: ic = epsilon
+ sage: t = srange(0,2/epsilon,1)
+ sage: sol = desolve_odeint(f, ic, t, y, # needs scipy
+ ....: rtol=1e-9, atol=1e-10, compute_jac=True)
+ sage: p = points(zip(t,sol[:,0])) # needs scipy sage.plot
+ sage: p.show() # needs scipy sage.plot
Another stiff system with some optional parameters with no
default value::
- sage: y1,y2,y3=var('y1,y2,y3')
- sage: f1=77.27*(y2+y1*(1-8.375*1e-6*y1-y2))
- sage: f2=1/77.27*(y3-(1+y1)*y2)
- sage: f3=0.16*(y1-y3)
- sage: f=[f1,f2,f3]
- sage: ci=[0.2,0.4,0.7]
- sage: t=srange(0,10,0.01)
- sage: v=[y1,y2,y3]
- sage: sol=desolve_odeint(f,ci,t,v,rtol=1e-3,atol=1e-4,h0=0.1,hmax=1,hmin=1e-4,mxstep=1000,mxords=17)
+ sage: y1,y2,y3 = var('y1,y2,y3')
+ sage: f1 = 77.27*(y2+y1*(1-8.375*1e-6*y1-y2))
+ sage: f2 = 1/77.27*(y3-(1+y1)*y2)
+ sage: f3 = 0.16*(y1-y3)
+ sage: f = [f1,f2,f3]
+ sage: ci = [0.2,0.4,0.7]
+ sage: t = srange(0,10,0.01)
+ sage: v = [y1,y2,y3]
+ sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # needs scipy
+ ....: h0=0.1, hmax=1, hmin=1e-4, mxstep=1000, mxords=17)
AUTHOR:
diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py
index 2f769a8f327..03ea8bbd294 100644
--- a/src/sage/calculus/functional.py
+++ b/src/sage/calculus/functional.py
@@ -1,3 +1,4 @@
+# sage.doctest: needs sage.symbolic
"""
Functional notation support for common calculus methods
diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py
index 6c47b0d2fc9..11a23aac323 100644
--- a/src/sage/calculus/functions.py
+++ b/src/sage/calculus/functions.py
@@ -1,9 +1,12 @@
+# sage.doctest: needs sage.symbolic
r"""
Calculus functions
"""
-from sage.matrix.constructor import matrix
+from sage.misc.lazy_import import lazy_import
from sage.structure.element import is_Matrix, is_Vector, Expression
+lazy_import('sage.matrix.constructor', 'matrix')
+
from .functional import diff
diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx
index 04ef352a906..19b2dc2e4c8 100644
--- a/src/sage/calculus/integration.pyx
+++ b/src/sage/calculus/integration.pyx
@@ -1,3 +1,4 @@
+# sage.doctest: needs sage.symbolic
"""
Numerical Integration
diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx
index e31d3606cc4..21b82388461 100644
--- a/src/sage/calculus/interpolation.pyx
+++ b/src/sage/calculus/interpolation.pyx
@@ -55,9 +55,9 @@ cdef class Spline:
This example is in the GSL documentation::
- sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)]
+ sage: v = [(i + RDF(i).sin()/2, i + RDF(i^2).cos()) for i in range(10)]
sage: s = spline(v)
- sage: show(point(v) + plot(s,0,9, hue=.8))
+ sage: show(point(v) + plot(s,0,9, hue=.8)) # needs sage.plot
We compute the area underneath the spline::
@@ -77,13 +77,13 @@ cdef class Spline:
We compute the first and second-order derivatives at a few points::
sage: s.derivative(5)
- -0.16230085261803...
+ -0.1623008526180...
sage: s.derivative(6)
- 0.20997986285714...
+ 0.2099798628571...
sage: s.derivative(5, order=2)
- -3.08747074561380...
+ -3.0874707456138...
sage: s.derivative(6, order=2)
- 2.61876848274853...
+ 2.6187684827485...
Only the first two derivatives are supported::
@@ -118,7 +118,7 @@ cdef class Spline:
Replace `0`-th point, which changes the spline::
- sage: S[0]=(0,1); S
+ sage: S[0] = (0,1); S
[(0, 1), (2, 3), (4, 5)]
sage: S(1.5)
2.5
diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx
index ded37516d62..fb057f0fc2e 100644
--- a/src/sage/calculus/interpolators.pyx
+++ b/src/sage/calculus/interpolators.pyx
@@ -1,3 +1,4 @@
+# sage.doctest: needs numpy
"""
Complex Interpolation
@@ -49,9 +50,10 @@ def polygon_spline(pts):
sage: ps = polygon_spline(pts)
sage: fx = lambda x: ps.value(x).real
sage: fy = lambda x: ps.value(x).imag
- sage: show(parametric_plot((fx, fy), (0, 2*pi)))
- sage: m = Riemann_Map([lambda x: ps.value(real(x))], [lambda x: ps.derivative(real(x))],0)
- sage: show(m.plot_colored() + m.plot_spiderweb())
+ sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot
+ sage: m = Riemann_Map([lambda x: ps.value(real(x))],
+ ....: [lambda x: ps.derivative(real(x))], 0)
+ sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot
Polygon approximation of an circle::
@@ -119,7 +121,7 @@ cdef class PSpline:
sage: ps = polygon_spline(pts)
sage: ps.value(.5)
(-0.363380227632...-1j)
- sage: ps.value(0) - ps.value(2*pi)
+ sage: ps.value(0) - ps.value(2*RDF.pi())
0j
sage: ps.value(10)
(0.26760455264...+1j)
@@ -152,6 +154,7 @@ cdef class PSpline:
sage: ps = polygon_spline(pts)
sage: ps.derivative(1 / 3)
(1.27323954473...+0j)
+ sage: from math import pi
sage: ps.derivative(0) - ps.derivative(2*pi)
0j
sage: ps.derivative(10)
@@ -171,7 +174,7 @@ def complex_cubic_spline(pts):
INPUT:
- - ``pts`` A list or array of complex numbers, or tuples of the form
+ - ``pts`` -- A list or array of complex numbers, or tuples of the form
`(x,y)`.
EXAMPLES:
@@ -182,13 +185,16 @@ def complex_cubic_spline(pts):
sage: cs = complex_cubic_spline(pts)
sage: fx = lambda x: cs.value(x).real
sage: fy = lambda x: cs.value(x).imag
- sage: show(parametric_plot((fx, fy), (0, 2*pi)))
- sage: m = Riemann_Map([lambda x: cs.value(real(x))], [lambda x: cs.derivative(real(x))], 0)
- sage: show(m.plot_colored() + m.plot_spiderweb())
+ sage: from math import pi
+ sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot
+ sage: m = Riemann_Map([lambda x: cs.value(real(x))],
+ ....: [lambda x: cs.derivative(real(x))], 0)
+ sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot
Polygon approximation of a circle::
- sage: pts = [e^(I*t / 25) for t in range(25)]
+ sage: from cmath import exp
+ sage: pts = [exp(1j * t / 25) for t in range(25)]
sage: cs = complex_cubic_spline(pts)
sage: cs.derivative(2)
(-0.0497765406583...+0.151095006434...j)
@@ -273,6 +279,7 @@ cdef class CCSpline:
sage: cs = complex_cubic_spline(pts)
sage: cs.value(4 / 7)
(-0.303961332787...-1.34716728183...j)
+ sage: from math import pi
sage: cs.value(0) - cs.value(2*pi)
0j
sage: cs.value(-2.73452)
@@ -304,6 +311,7 @@ cdef class CCSpline:
sage: cs = complex_cubic_spline(pts)
sage: cs.derivative(3 / 5)
(1.40578892327...-0.225417136326...j)
+ sage: from math import pi
sage: cs.derivative(0) - cs.derivative(2 * pi)
0j
sage: cs.derivative(-6)
diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx
index 74bac5b0811..a7fbb87dffb 100644
--- a/src/sage/calculus/ode.pyx
+++ b/src/sage/calculus/ode.pyx
@@ -109,30 +109,31 @@ cdef int c_f(double t,double* y, double* dydt,void *params):
class ode_solver():
r"""
- :meth:`ode_solver` is a class that wraps the GSL libraries ode
- solver routines To use it instantiate a class,::
+ :meth:`ode_solver` is a class that wraps the GSL library's ode solver routines.
- sage: T=ode_solver()
+ To use it, instantiate the class::
- To solve a system of the form ``dy_i/dt=f_i(t,y)``, you must
+ sage: T = ode_solver()
+
+ To solve a system of the form `dy_i/dt=f_i(t,y)`, you must
supply a vector or tuple/list valued function ``f`` representing
- ``f_i``. The functions ``f`` and the jacobian should have the
+ `f_i`. The functions `f` and the jacobian should have the
form ``foo(t,y)`` or ``foo(t,y,params)``. ``params`` which is
optional allows for your function to depend on one or a tuple of
parameters. Note if you use it, ``params`` must be a tuple even
if it only has one component. For example if you wanted to solve
- `y''+y=0`. You need to write it as a first order system::
+ `y''+y=0`, you would need to write it as a first order system::
y_0' = y_1
y_1' = -y_0
In code::
- sage: f = lambda t,y:[y[1],-y[0]]
- sage: T.function=f
+ sage: f = lambda t, y: [y[1], -y[0]]
+ sage: T.function = f
- For some algorithms the jacobian must be supplied as well, the
- form of this should be a function return a list of lists of the
+ For some algorithms, the jacobian must be supplied as well, the
+ form of this should be a function returning a list of lists of the
form ``[ [df_1/dy_1,...,df_1/dy_n], ...,
[df_n/dy_1,...,df_n,dy_n], [df_1/dt,...,df_n/dt] ]``.
@@ -143,45 +144,45 @@ class ode_solver():
There are a variety of algorithms available for different types of systems. Possible algorithms are
- - ``rkf45`` - runga-kutta-felhberg (4,5)
+ - ``'rkf45'`` -- Runge-Kutta-Fehlberg (4,5)
- - ``rk2`` - embedded runga-kutta (2,3)
+ - ``'rk2'`` -- embedded Runge-Kutta (2,3)
- - ``rk4`` - 4th order classical runga-kutta
+ - ``'rk4'`` -- 4th order classical Runge-Kutta
- - ``rk8pd`` - runga-kutta prince-dormand (8,9)
+ - ``'rk8pd'`` -- Runge-Kutta Prince-Dormand (8,9)
- - ``rk2imp`` - implicit 2nd order runga-kutta at gaussian points
+ - ``'rk2imp'`` -- implicit 2nd order Runge-Kutta at gaussian points
- - ``rk4imp`` - implicit 4th order runga-kutta at gaussian points
+ - ``'rk4imp'`` -- implicit 4th order Runge-Kutta at gaussian points
- - ``bsimp`` - implicit burlisch-stoer (requires jacobian)
+ - ``'bsimp'`` -- implicit Burlisch-Stoer (requires jacobian)
- - ``gear1`` - M=1 implicit gear
+ - ``'gear1'`` -- M=1 implicit gear
- - ``gear2`` - M=2 implicit gear
+ - ``'gear2'`` -- M=2 implicit gear
- The default algorithm is ``rkf45``. If you instead wanted to use
- ``bsimp`` you would do::
+ The default algorithm is ``'rkf45'``. If you instead wanted to use
+ ``'bsimp'`` you would do::
- sage: T.algorithm="bsimp"
+ sage: T.algorithm = "bsimp"
- The user should supply initial conditions in y_0. For example if
- your initial conditions are y_0=1,y_1=1, do::
+ The user should supply initial conditions in ``y_0``. For example if
+ your initial conditions are `y_0=1, y_1=1`, do::
- sage: T.y_0=[1,1]
+ sage: T.y_0 = [1,1]
The actual solver is invoked by the method :meth:`ode_solve`. It
has arguments ``t_span``, ``y_0``, ``num_points``, ``params``.
``y_0`` must be supplied either as an argument or above by
assignment. Params which are optional and only necessary if your
- system uses params can be supplied to ``ode_solve`` or by
+ system uses ``params`` can be supplied to ``ode_solve`` or by
assignment.
``t_span`` is the time interval on which to solve the ode. There
are two ways to specify ``t_span``:
- * If ``num_points`` is not specified then the sequence ``t_span``
+ * If ``num_points`` is not specified, then the sequence ``t_span``
is used as the time points for the solution. Note that the
first element ``t_span[0]`` is the initial time, where the
initial condition ``y_0`` is the specified solution, and
@@ -192,10 +193,10 @@ class ode_solver():
and the solution will be computed at ``num_points`` equally
spaced points between ``t_span[0]`` and ``t_span[1]``. The
initial condition is also included in the output so that
- ``num_points``\ +1 total points are returned. E.g. if ``t_span
+ ``num_points + 1`` total points are returned. E.g. if ``t_span
= [0.0, 1.0]`` and ``num_points = 10``, then solution is
returned at the 11 time points ``[0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
- 0.6, 0.7, 0.8, 0.9, 1.0]``\ .
+ 0.6, 0.7, 0.8, 0.9, 1.0]``.
(Note that if ``num_points`` is specified and ``t_span`` is not
length 2 then ``t_span`` are used as the time points and
@@ -203,13 +204,19 @@ class ode_solver():
Error is estimated via the expression ``D_i =
error_abs*s_i+error_rel*(a|y_i|+a_dydt*h*|y_i'|)``. The user can
- specify ``error_abs`` (1e-10 by default), ``error_rel`` (1e-10 by
- default) ``a`` (1 by default), ``a_(dydt)`` (0 by default) and
- ``s_i`` (as scaling_abs which should be a tuple and is 1 in all
- components by default). If you specify one of ``a`` or ``a_dydt``
+ specify
+
+ - ``error_abs`` (1e-10 by default),
+ - ``error_rel`` (1e-10 by default),
+ - ``a`` (1 by default),
+ - ``a_dydt`` (0 by default) and
+ - ``s_i`` (as ``scaling_abs`` which should be a tuple and is 1 in all
+ components by default).
+
+ If you specify one of ``a`` or ``a_dydt``
you must specify the other. You may specify ``a`` and ``a_dydt``
without ``scaling_abs`` (which will be taken =1 be default).
- ``h`` is the initial step size which is (1e-2) by default.
+ ``h`` is the initial step size, which is 1e-2 by default.
``ode_solve`` solves the solution as a list of tuples of the form,
``[ (t_0,[y_1,...,y_n]),(t_1,[y_1,...,y_n]),...,(t_n,[y_1,...,y_n])]``.
@@ -223,27 +230,29 @@ class ode_solver():
Consider solving the Van der Pol oscillator `x''(t) +
ux'(t)(x(t)^2-1)+x(t)=0` between `t=0` and `t= 100`. As a first
order system it is `x'=y`, `y'=-x+uy(1-x^2)`. Let us take `u=10`
- and use initial conditions `(x,y)=(1,0)` and use the runga-kutta
- prince-dormand algorithm. ::
+ and use initial conditions `(x,y)=(1,0)` and use the Runge-Kutta
+ Prince-Dormand algorithm. ::
- sage: def f_1(t,y,params):
- ....: return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)]
+ sage: def f_1(t, y, params):
+ ....: return [y[1], -y[0] - params[0]*y[1]*(y[0]**2-1.0)]
- sage: def j_1(t,y,params):
- ....: return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ]
+ sage: def j_1(t, y, params):
+ ....: return [[0.0, 1.0],
+ ....: [-2.0*params[0]*y[0]*y[1] - 1.0, -params[0]*(y[0]*y[0]-1.0)],
+ ....: [0.0, 0.0]]
- sage: T=ode_solver()
- sage: T.algorithm="rk8pd"
- sage: T.function=f_1
- sage: T.jacobian=j_1
- sage: T.ode_solve(y_0=[1,0],t_span=[0,100],params=[10.0],num_points=1000)
+ sage: T = ode_solver()
+ sage: T.algorithm = "rk8pd"
+ sage: T.function = f_1
+ sage: T.jacobian = j_1
+ sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000)
sage: import tempfile
- sage: with tempfile.NamedTemporaryFile(suffix=".png") as f:
+ sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot
....: T.plot_solution(filename=f.name)
The solver line is equivalent to::
- sage: T.ode_solve(y_0=[1,0],t_span=[x/10.0 for x in range(1000)],params = [10.0])
+ sage: T.ode_solve(y_0=[1,0], t_span=[x/10.0 for x in range(1000)], params=[10.0])
Let's try a system::
@@ -254,40 +263,42 @@ class ode_solver():
We will not use the jacobian this time and will change the
error tolerances. ::
- sage: g_1= lambda t,y: [y[1]*y[2],-y[0]*y[2],-0.51*y[0]*y[1]]
- sage: T.function=g_1
- sage: T.y_0=[0,1,1]
- sage: T.scale_abs=[1e-4,1e-4,1e-5]
- sage: T.error_rel=1e-4
- sage: T.ode_solve(t_span=[0,12],num_points=100)
+ sage: g_1 = lambda t,y: [y[1]*y[2], -y[0]*y[2], -0.51*y[0]*y[1]]
+ sage: T.function = g_1
+ sage: T.y_0 = [0,1,1]
+ sage: T.scale_abs = [1e-4, 1e-4, 1e-5]
+ sage: T.error_rel = 1e-4
+ sage: T.ode_solve(t_span=[0,12], num_points=100)
- By default T.plot_solution() plots the y_0, to plot general y_i use::
+ By default ``T.plot_solution()`` plots the `y_0`; to plot general `y_i`, use::
- sage: with tempfile.NamedTemporaryFile(suffix=".png") as f:
+ sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot
....: T.plot_solution(i=0, filename=f.name)
....: T.plot_solution(i=1, filename=f.name)
....: T.plot_solution(i=2, filename=f.name)
The method interpolate_solution will return a spline interpolation
- through the points found by the solver. By default y_0 is
- interpolated. You can interpolate y_i through the keyword
- argument i. ::
+ through the points found by the solver. By default, `y_0` is
+ interpolated. You can interpolate `y_i` through the keyword
+ argument ``i``. ::
sage: f = T.interpolate_solution()
- sage: plot(f,0,12).show()
+ sage: plot(f,0,12).show() # needs sage.plot
sage: f = T.interpolate_solution(i=1)
- sage: plot(f,0,12).show()
+ sage: plot(f,0,12).show() # needs sage.plot
sage: f = T.interpolate_solution(i=2)
- sage: plot(f,0,12).show()
+ sage: plot(f,0,12).show() # needs sage.plot
sage: f = T.interpolate_solution()
+ sage: from math import pi
sage: f(pi)
0.5379...
The solver attributes may also be set up using arguments to
ode_solver. The previous example can be rewritten as::
- sage: T = ode_solver(g_1,y_0=[0,1,1],scale_abs=[1e-4,1e-4,1e-5],error_rel=1e-4, algorithm="rk8pd")
- sage: T.ode_solve(t_span=[0,12],num_points=100)
+ sage: T = ode_solver(g_1, y_0=[0,1,1], scale_abs=[1e-4,1e-4,1e-5],
+ ....: error_rel=1e-4, algorithm="rk8pd")
+ sage: T.ode_solve(t_span=[0,12], num_points=100)
sage: f = T.interpolate_solution()
sage: f(pi)
0.5379...
@@ -295,7 +306,7 @@ class ode_solver():
Unfortunately because Python functions are used, this solver
is slow on systems that require many function evaluations. It
is possible to pass a compiled function by deriving from the
- class ``ode_sysem`` and overloading ``c_f`` and ``c_j`` with C
+ class :class:`ode_system` and overloading ``c_f`` and ``c_j`` with C
functions that specify the system. The following will work in the
notebook:
@@ -382,11 +393,11 @@ class ode_solver():
sage: T.function = lambda t,y: [cos(y[0]) * sin(t)]
sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]]
sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000)
- sage: T.plot_solution()
+ sage: T.plot_solution() # needs sage.plot
And with some options::
- sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"])
+ sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # needs sage.plot
"""
if interpolate:
from sage.plot.line import line2d
diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx
index 46e2964eade..05d5b1ec60a 100644
--- a/src/sage/calculus/riemann.pyx
+++ b/src/sage/calculus/riemann.pyx
@@ -1,3 +1,4 @@
+# sage.doctest: needs numpy sage.symbolic
"""
Riemann Mapping
@@ -1190,9 +1191,10 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values,
sage: from sage.calculus.riemann import complex_to_spiderweb
sage: import numpy
- sage: zval = numpy.array([[0, 1, 1000],[.2+.3j,1,-.3j],[0,0,0]],dtype = numpy.complex128)
+ sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]],
+ ....: dtype=numpy.complex128)
sage: deriv = numpy.array([[.1]],dtype = numpy.float64)
- sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,False,0.001)
+ sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001)
array([[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]],
@@ -1205,7 +1207,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values,
[1., 1., 1.],
[1., 1., 1.]]])
- sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,True,0.001)
+ sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001)
array([[[1. , 1. , 1. ],
[1. , 0.05558355, 0.05558355],
[0.17301243, 0. , 0. ]],
@@ -1280,12 +1282,12 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values):
sage: from sage.calculus.riemann import complex_to_rgb
sage: import numpy
- sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype = numpy.complex128))
+ sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128))
array([[[1. , 1. , 1. ],
[1. , 0.05558355, 0.05558355],
[0.17301243, 0. , 0. ]]])
- sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype = numpy.complex128))
+ sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128))
array([[[1. , 1. , 1. ],
[0.52779177, 1. , 0.05558355],
[0.08650622, 0.17301243, 0. ]]])
diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py
index 927e6ee4fb6..b99d5d7857e 100644
--- a/src/sage/calculus/test_sympy.py
+++ b/src/sage/calculus/test_sympy.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# sage.doctest: needs sage.symbolic
r"""
A Sample Session using SymPy
@@ -102,46 +102,47 @@
And here are some actual tests of sympy::
- sage: from sympy import Symbol, cos, sympify, pprint
- sage: from sympy.abc import x
+ sage: from sympy import Symbol, cos, sympify, pprint # needs sympy
+ sage: from sympy.abc import x # needs sympy
::
- sage: e = (1/cos(x)^3)._sympy_(); e
+ sage: e = (1/cos(x)^3)._sympy_(); e # needs sympy
cos(x)**(-3)
- sage: f = e.series(x, 0, int(10)); f
+ sage: f = e.series(x, 0, int(10)); f # needs sympy
1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10)
And the pretty-printer. Since unicode characters are not working on
some architectures, we disable it::
- sage: from sympy.printing import pprint_use_unicode
- sage: prev_use = pprint_use_unicode(False)
- sage: pprint(e)
+ sage: from sympy.printing import pprint_use_unicode # needs sympy
+ sage: prev_use = pprint_use_unicode(False) # needs sympy
+ sage: pprint(e) # needs sympy
1
-------
3
cos (x)
- sage: pprint(f)
+ sage: pprint(f) # needs sympy
2 4 6 8
3*x 11*x 241*x 8651*x / 10\
1 + ---- + ----- + ------ + ------- + O\x /
2 8 240 13440
- sage: pprint_use_unicode(prev_use)
+ sage: pprint_use_unicode(prev_use) # needs sympy
False
And the functionality to convert from sympy format to Sage format::
- sage: e._sage_()
+ sage: e._sage_() # needs sympy
cos(x)^(-3)
- sage: e._sage_().taylor(x._sage_(), 0, 8)
+ sage: e._sage_().taylor(x._sage_(), 0, 8) # needs sympy
8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + 1
- sage: f._sage_()
+ sage: f._sage_() # needs sympy
8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + Order(x^10) + 1
Mixing SymPy with Sage::
+ sage: # needs sympy
sage: import sympy
sage: var("x")._sympy_() + var("y")._sympy_()
x + y
@@ -155,7 +156,7 @@
sage: t1, t2
(omega + x, omega + x)
- sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x"))
+ sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x"))
sage: type(e)
sage: e
@@ -172,23 +173,24 @@
::
- sage: a = sympy.Matrix([1, 2, 3])
- sage: a[1]
+ sage: a = sympy.Matrix([1, 2, 3]) # needs sympy
+ sage: a[1] # needs sympy
2
::
- sage: sympify(1.5)
+ sage: sympify(1.5) # needs sympy
1.50000000000000
- sage: sympify(2)
+ sage: sympify(2) # needs sympy
2
- sage: sympify(-2)
+ sage: sympify(-2) # needs sympy
-2
TESTS:
This was fixed in Sympy, see :trac:`14437`::
+ sage: # needs sympy
sage: from sympy import Function, Symbol, rsolve
sage: u = Function('u')
sage: n = Symbol('n', integer=True)
diff --git a/src/sage/calculus/transforms/all.py b/src/sage/calculus/transforms/all.py
index 06ed525b868..379b3b69c37 100644
--- a/src/sage/calculus/transforms/all.py
+++ b/src/sage/calculus/transforms/all.py
@@ -1,3 +1,5 @@
-from .fft import FastFourierTransform, FFT
-from .dwt import WaveletTransform, DWT
+from sage.misc.lazy_import import lazy_import
+
+lazy_import("sage.calculus.transforms.fft", ["FastFourierTransform", "FFT"])
+lazy_import("sage.calculus.transforms.dwt", ["WaveletTransform", "DWT"])
from .dft import IndexedSequence
diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py
index db18a20e129..b413bc0ea81 100644
--- a/src/sage/calculus/transforms/dft.py
+++ b/src/sage/calculus/transforms/dft.py
@@ -16,7 +16,7 @@
- plotting, printing -- :meth:`IndexedSequence.plot`,
:meth:`IndexedSequence.plot_histogram`, :meth:`_repr_`, :meth:`__str__`
-- dft -- computes the discrete Fourier transform for the following cases:
+- :meth:`dft` -- computes the discrete Fourier transform for the following cases:
* a sequence (over `\QQ` or :class:`CyclotomicField`) indexed by ``range(N)``
or `\ZZ / N \ZZ`
@@ -26,21 +26,21 @@
* a sequence (as above) indexed by a complete set of representatives of
the conjugacy classes of a finite matrix group
-- idft -- computes the discrete Fourier transform for the following cases:
+- :meth:`idft` -- computes the discrete Fourier transform for the following cases:
* a sequence (over `\QQ` or CyclotomicField) indexed by ``range(N)`` or
`\ZZ / N \ZZ`
-- dct, dst (for discrete Fourier/Cosine/Sine transform)
+- :meth:`dct`, :meth:`dst` (for discrete Fourier/Cosine/Sine transform)
- convolution (in :meth:`IndexedSequence.convolution` and
:meth:`IndexedSequence.convolution_periodic`)
-- fft, ifft -- (fast Fourier transforms) wrapping GSL's
+- :meth:`fft`, :meth:`ifft` -- (fast Fourier transforms) wrapping GSL's
``gsl_fft_complex_forward()``, ``gsl_fft_complex_inverse()``,
using William Stein's :func:`FastFourierTransform`
-- dwt, idwt -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``,
+- :meth:`dwt`, :meth:`idwt` -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``,
``gsl_dwt_backward()`` using Joshua Kantor's :func:`WaveletTransform` class.
Allows for wavelets of type:
@@ -71,20 +71,20 @@
#
# https://www.gnu.org/licenses/
##########################################################################
-from sage.rings.number_field.number_field import CyclotomicField
+from sage.functions.trig import sin, cos
from sage.misc.lazy_import import lazy_import
-from sage.groups.abelian_gps.abelian_group import AbelianGroup
-from sage.groups.perm_gps.permgroup_element import is_PermutationGroupElement
-from sage.rings.integer_ring import ZZ
from sage.rings.integer import Integer
+from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
-from sage.rings.real_mpfr import RR
-from sage.functions.all import sin, cos
-from sage.calculus.transforms.fft import FastFourierTransform
-from sage.calculus.transforms.dwt import WaveletTransform
from sage.structure.sage_object import SageObject
from sage.structure.sequence import Sequence
+
+lazy_import("sage.calculus.transforms.dwt", "WaveletTransform")
+lazy_import("sage.calculus.transforms.fft", "FastFourierTransform")
+lazy_import("sage.groups.abelian_gps.abelian_group", "AbelianGroup")
+lazy_import("sage.groups.perm_gps.permgroup_element", "PermutationGroupElement")
lazy_import("sage.plot.all", ["polygon", "line", "text"])
+lazy_import("sage.rings.number_field.number_field", "CyclotomicField")
class IndexedSequence(SageObject):
@@ -218,8 +218,7 @@ def _repr_(self):
indexed by [0, 1, 2]
sage: I = GF(3)
sage: A = [i^2 for i in I]
- sage: s = IndexedSequence(A,I)
- sage: s
+ sage: s = IndexedSequence(A,I); s
Indexed sequence: [0, 1, 1]
indexed by Finite Field of size 3
"""
@@ -240,9 +239,10 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4):
sage: J = list(range(3))
sage: A = [ZZ(i^2)+1 for i in J]
sage: s = IndexedSequence(A,J)
- sage: P = s.plot_histogram()
- sage: show(P) # Not tested
+ sage: P = s.plot_histogram() # needs sage.plot
+ sage: show(P) # not tested # needs sage.plot
"""
+ from sage.rings.real_mpfr import RR
# elements must be coercible into RR
I = self.index_object()
N = len(I)
@@ -268,9 +268,10 @@ def plot(self):
sage: I = list(range(3))
sage: A = [ZZ(i^2)+1 for i in I]
sage: s = IndexedSequence(A,I)
- sage: P = s.plot()
- sage: show(P) # Not tested
+ sage: P = s.plot() # needs sage.plot
+ sage: show(P) # not tested # needs sage.plot
"""
+ from sage.rings.real_mpfr import RR
# elements must be coercible into RR
I = self.index_object()
S = self.list()
@@ -286,30 +287,44 @@ def dft(self, chi=lambda x: x):
sage: J = list(range(6))
sage: A = [ZZ(1) for i in J]
sage: s = IndexedSequence(A,J)
- sage: s.dft(lambda x:x^2)
+ sage: s.dft(lambda x: x^2) # needs sage.rings.number_field
Indexed sequence: [6, 0, 0, 6, 0, 0]
indexed by [0, 1, 2, 3, 4, 5]
- sage: s.dft()
+ sage: s.dft() # needs sage.rings.number_field
Indexed sequence: [6, 0, 0, 0, 0, 0]
indexed by [0, 1, 2, 3, 4, 5]
+
+ sage: # needs sage.groups
sage: G = SymmetricGroup(3)
sage: J = G.conjugacy_classes_representatives()
- sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G
+ sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G
sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn
Indexed sequence: [8, 2, 2]
indexed by [(), (1,2), (1,2,3)]
- sage: J = AbelianGroup(2,[2,3],names='ab')
- sage: s = IndexedSequence([1,2,3,4,5,6],J)
+ sage: J = AbelianGroup(2, [2,3], names='ab')
+ sage: s = IndexedSequence([1,2,3,4,5,6], J)
sage: s.dft() # the precision of output is somewhat random and architecture dependent.
- Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]
- indexed by Multiplicative Abelian group isomorphic to C2 x C3
+ Indexed sequence: [21.0000000000000,
+ -2.99999999999997 - 1.73205080756885*I,
+ -2.99999999999999 + 1.73205080756888*I,
+ -9.00000000000000 + 0.0000000000000485744257349999*I,
+ -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I,
+ -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]
+ indexed by Multiplicative Abelian group isomorphic to C2 x C3
sage: J = CyclicPermutationGroup(6)
- sage: s = IndexedSequence([1,2,3,4,5,6],J)
+ sage: s = IndexedSequence([1,2,3,4,5,6], J)
sage: s.dft() # the precision of output is somewhat random and architecture dependent.
- Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]
- indexed by Cyclic group of order 6 as a permutation group
+ Indexed sequence: [21.0000000000000,
+ -2.99999999999997 - 1.73205080756885*I,
+ -2.99999999999999 + 1.73205080756888*I,
+ -9.00000000000000 + 0.0000000000000485744257349999*I,
+ -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I,
+ -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]
+ indexed by Cyclic group of order 6 as a permutation group
+
+ sage: # needs sage.rings.number_field
sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J]
- sage: s = IndexedSequence(A,J)
+ sage: s = IndexedSequence(A, J)
sage: Fs = s.dft()
sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list()
[0, 1, 1, -1, 1, -1, -1]
@@ -336,7 +351,7 @@ def dft(self, chi=lambda x: x):
zeta = CyclotomicField(N).gen()
FT = [sum([S[i] * chi(zeta**(i * j)) for i in J]) for j in J]
elif (J[0] not in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring() == QQ):
- if is_PermutationGroupElement(J[0]):
+ if isinstance(J[0], PermutationGroupElement):
# J is a CyclicPermGp
n = G.order()
a = list(n.factor())
@@ -364,13 +379,13 @@ def idft(self):
sage: J = list(range(5))
sage: A = [ZZ(1) for i in J]
sage: s = IndexedSequence(A,J)
- sage: fs = s.dft(); fs
+ sage: fs = s.dft(); fs # needs sage.rings.number_field
Indexed sequence: [5, 0, 0, 0, 0]
indexed by [0, 1, 2, 3, 4]
- sage: it = fs.idft(); it
+ sage: it = fs.idft(); it # needs sage.rings.number_field
Indexed sequence: [1, 1, 1, 1, 1]
indexed by [0, 1, 2, 3, 4]
- sage: it == s
+ sage: it == s # needs sage.rings.number_field
True
"""
F = self.base_ring() # elements must be coercible into QQ(zeta_N)
@@ -390,18 +405,23 @@ def dct(self):
EXAMPLES::
sage: J = list(range(5))
- sage: A = [exp(-2*pi*i*I/5) for i in J]
- sage: s = IndexedSequence(A,J)
- sage: s.dct()
+ sage: A = [exp(-2*pi*i*I/5) for i in J] # needs sage.symbolic
+ sage: s = IndexedSequence(A, J) # needs sage.symbolic
+ sage: s.dct() # needs sage.symbolic
Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ...
indexed by [0, 1, 2, 3, 4]
"""
- from sage.symbolic.constants import pi
F = self.base_ring() # elements must be coercible into RR
+ try:
+ pi = F.pi()
+ except AttributeError:
+ from sage.symbolic.constants import pi
+ pi = F(pi)
+
J = self.index_object() # must be = range(N)
N = len(J)
S = self.list()
- PI = 2 * F(pi) / N
+ PI = 2 * pi / N
FT = [sum([S[i] * cos(PI * i * j) for i in J]) for j in J]
return IndexedSequence(FT, J)
@@ -412,16 +432,21 @@ def dst(self):
EXAMPLES::
sage: J = list(range(5))
- sage: I = CC.0; pi = CC(pi)
+ sage: I = CC.0; pi = CC.pi()
sage: A = [exp(-2*pi*i*I/5) for i in J]
- sage: s = IndexedSequence(A,J)
+ sage: s = IndexedSequence(A, J)
sage: s.dst() # discrete sine
Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...]
indexed by [0, 1, 2, 3, 4]
"""
- from sage.symbolic.constants import pi
F = self.base_ring() # elements must be coercible into RR
+ try:
+ pi = F.pi()
+ except AttributeError:
+ from sage.symbolic.constants import pi
+ pi = F(pi)
+
J = self.index_object() # must be = range(N)
N = len(J)
S = self.list()
@@ -711,6 +736,7 @@ def dwt(self, other="haar", wavelet_k=2):
Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000]
indexed by [0, 1, 2, 3, 4, 5, 6, 7]
"""
+ from sage.rings.real_mpfr import RR
# elements must be coercible into RR
J = self.index_object() # must be = range(N)
N = len(J) # must be 1 minus a power of 2
@@ -788,6 +814,7 @@ def idwt(self, other="haar", wavelet_k=2):
sage: t.idwt("bspline", 103) == s
True
"""
+ from sage.rings.real_mpfr import RR
# elements must be coercible into RR
J = self.index_object() # must be = range(N)
N = len(J) # must be 1 minus a power of 2
diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx
index 9296afb7824..807169f2886 100644
--- a/src/sage/calculus/transforms/dwt.pyx
+++ b/src/sage/calculus/transforms/dwt.pyx
@@ -64,27 +64,28 @@ def WaveletTransform(n, wavelet_type, wavelet_k):
sage: for i in range(1, 11):
....: a[i] = 1
....: a[128-i] = 1
- sage: a.plot().show(ymin=0)
+ sage: a.plot().show(ymin=0) # needs sage.plot
sage: a.forward_transform()
- sage: a.plot().show()
+ sage: a.plot().show() # needs sage.plot
sage: a = WaveletTransform(128,'haar',2)
sage: for i in range(1, 11): a[i] = 1; a[128-i] = 1
sage: a.forward_transform()
- sage: a.plot().show(ymin=0)
+ sage: a.plot().show(ymin=0) # needs sage.plot
sage: a = WaveletTransform(128,'bspline_centered',103)
sage: for i in range(1, 11): a[i] = 1; a[100+i] = 1
sage: a.forward_transform()
- sage: a.plot().show(ymin=0)
+ sage: a.plot().show(ymin=0) # needs sage.plot
This example gives a simple example of wavelet compression::
+ sage: # needs sage.symbolic
sage: a = DWT(2048,'daubechies',6)
sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2))
- sage: a.plot().show() # long time (7s on sage.math, 2011)
+ sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot
sage: a.forward_transform()
sage: for i in range(1800): a[2048-i-1] = 0
sage: a.backward_transform()
- sage: a.plot().show() # long time (7s on sage.math, 2011)
+ sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot
"""
cdef size_t _n, _k
_n = int(n)
diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx
index 05db8f5e3e7..168698957c4 100644
--- a/src/sage/calculus/transforms/fft.pyx
+++ b/src/sage/calculus/transforms/fft.pyx
@@ -22,7 +22,6 @@ AUTHORS:
from cysignals.memory cimport sig_malloc, sig_free
-import sage.libs.pari.all
from sage.rings.integer import Integer
from sage.rings.complex_mpfr import ComplexNumber
@@ -70,9 +69,9 @@ def FastFourierTransform(size, base_ring=None):
....: a[128-i] = 1
sage: a[:6:2]
[(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)]
- sage: a.plot().show(ymin=0)
+ sage: a.plot().show(ymin=0) # needs sage.plot
sage: a.forward_transform()
- sage: a.plot().show()
+ sage: a.plot().show() # needs sage.plot
"""
return FastFourierTransform_complex(int(size))
@@ -152,6 +151,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
EXAMPLES::
+ sage: # needs sage.rings.mpfr sage.symbolic
sage: I = CC(I)
sage: a = FastFourierTransform(4)
sage: a[0] = 1
@@ -243,18 +243,19 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
EXAMPLES::
sage: a = FastFourierTransform(4)
- sage: a._plot_polar(0,2)
+ sage: a._plot_polar(0,2) # needs sage.plot
Graphics object consisting of 2 graphics primitives
"""
from sage.plot.point import point
+ from sage.symbolic.constants import pi, I
cdef int i
v = []
- pi = sage.symbolic.constants.pi.n()
- I = sage.symbolic.constants.I.n()
- s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3
+ pi = pi.n()
+ I = I.n()
+ s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3.
for i from xmin <= i < xmax:
z = self.data[2*i] + I*self.data[2*i+1]
@@ -282,15 +283,15 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
EXAMPLES::
sage: a = FastFourierTransform(4)
- sage: a._plot_rect(0,3)
+ sage: a._plot_rect(0,3) # needs sage.plot
Graphics object consisting of 3 graphics primitives
"""
+ from sage.plot.point import point
+
cdef int i
cdef double x, h
v = []
- point = sage.plot.all.point
-
for i in range(xmin, xmax):
x = self.data[2*i]
h = self.data[2*i+1]
@@ -302,10 +303,12 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
Plot a slice of the array.
- ``style`` -- Style of the plot, options are ``"rect"`` or ``"polar"``
- - ``rect`` -- height represents real part, color represents
- imaginary part.
- - ``polar`` -- height represents absolute value, color
- represents argument.
+
+ - ``rect`` -- height represents real part, color represents
+ imaginary part.
+ - ``polar`` -- height represents absolute value, color
+ represents argument.
+
- ``xmin`` -- The lower bound of the slice to plot. 0 by default.
- ``xmax`` -- The upper bound of the slice to plot. ``len(self)`` by default.
- ``**args`` -- passed on to the line plotting function.
@@ -318,11 +321,11 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: a = FastFourierTransform(16)
sage: for i in range(16): a[i] = (random(),random())
- sage: A = plot(a)
- sage: B = plot(a, style='polar')
- sage: type(A)
+ sage: A = plot(a) # needs sage.plot
+ sage: B = plot(a, style='polar') # needs sage.plot
+ sage: type(A) # needs sage.plot
- sage: type(B)
+ sage: type(B) # needs sage.plot
sage: a = FastFourierTransform(125)
sage: b = FastFourierTransform(125)
@@ -330,7 +333,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: for i in range(1, 60): b[i]=1
sage: a.forward_transform()
sage: a.inverse_transform()
- sage: (a.plot()+b.plot())
+ sage: a.plot() + b.plot() # needs sage.plot
Graphics object consisting of 250 graphics primitives
"""
@@ -408,7 +411,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: for i in range(1, 60): b[i]=1
sage: a.forward_transform()
sage: a.inverse_transform()
- sage: (a.plot()+b.plot())
+ sage: a.plot() + b.plot() # needs sage.plot
Graphics object consisting of 250 graphics primitives
sage: abs(sum([CDF(a[i])-CDF(b[i]) for i in range(125)])) < 2**-16
True
@@ -421,7 +424,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: for i in range(1, 60): b[i]=1
sage: a.forward_transform()
sage: a.inverse_transform()
- sage: (a.plot()+b.plot())
+ sage: a.plot() + b.plot() # needs sage.plot
Graphics object consisting of 256 graphics primitives
"""
@@ -459,7 +462,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: for i in range(1, 60): b[i]=1
sage: a.forward_transform()
sage: a.backward_transform()
- sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011)
+ sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011), needs sage.plot
sage: abs(sum([CDF(a[i])/125-CDF(b[i]) for i in range(125)])) < 2**-16
True
@@ -471,7 +474,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base):
sage: for i in range(1, 60): b[i]=1
sage: a.forward_transform()
sage: a.backward_transform()
- sage: (a.plot() + b.plot()).show(ymin=0)
+ sage: (a.plot() + b.plot()).show(ymin=0) # needs sage.plot
"""
cdef gsl_fft_complex_wavetable * wt
cdef gsl_fft_complex_workspace * mem
diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py
index 766ce586eb2..e33409a49ac 100644
--- a/src/sage/calculus/wester.py
+++ b/src/sage/calculus/wester.py
@@ -1,3 +1,4 @@
+# sage.doctest: needs sage.symbolic
r"""
Further examples from Wester's paper
diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py
index 0f43e6bbcfe..79690ff7305 100644
--- a/src/sage/combinat/all.py
+++ b/src/sage/combinat/all.py
@@ -277,7 +277,7 @@
lazy_import('sage.combinat.binary_recurrence_sequences',
'BinaryRecurrenceSequence')
lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace')
-lazy_import('sage.combinat.k_regular_sequence', 'kRegularSequenceSpace')
+lazy_import('sage.combinat.regular_sequence', 'RegularSequenceRing')
# Six Vertex Model
lazy_import('sage.combinat.six_vertex_model', 'SixVertexModel')
diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py
index e5856aacef9..ba100089379 100644
--- a/src/sage/combinat/recognizable_series.py
+++ b/src/sage/combinat/recognizable_series.py
@@ -27,27 +27,13 @@
In particular, minimization is called before checking if a series is
nonzero.
-.. WARNING::
-
- As this code is experimental, warnings are thrown when a
- recognizable series space is created for the first time in a
- session (see :class:`sage.misc.superseded.experimental`).
-
- TESTS::
-
- sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1])
- doctest:...: FutureWarning: This class/method/function is
- marked as experimental. It, its functionality or its interface
- might change without a formal deprecation.
- See https://github.com/sagemath/sage/issues/21202 for details.
-
Various
=======
.. SEEALSO::
- :mod:`k-regular sequence `,
+ :mod:`k-regular sequence `,
:mod:`sage.rings.cfinite_sequence`,
:mod:`sage.combinat.binary_recurrence_sequences`.
@@ -79,7 +65,6 @@
from functools import wraps
from sage.misc.cachefunc import cached_method
-from sage.misc.superseded import experimental
from sage.structure.element import ModuleElement
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
@@ -1140,6 +1125,12 @@ def minimized(self):
sage: all(c == d and v == w
....: for (c, v), (d, w) in islice(zip(iter(S), iter(M)), 20))
True
+
+ TESTS::
+
+ sage: Rec((Matrix([[0]]), Matrix([[0]])),
+ ....: vector([1]), vector([0])).minimized().linear_representation()
+ ((), Finite family {0: [], 1: []}, ())
"""
return self._minimized_right_()._minimized_left_()
@@ -1291,7 +1282,7 @@ def _add_(self, other):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
sage: E
@@ -1314,7 +1305,7 @@ def _add_(self, other):
result = P.element_class(
P,
- dict((a, self.mu[a].block_sum(other.mu[a])) for a in P.alphabet()),
+ {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()},
vector(tuple(self.left) + tuple(other.left)),
vector(tuple(self.right) + tuple(other.right)))
@@ -1330,7 +1321,7 @@ def _neg_(self):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
sage: -E
@@ -1357,7 +1348,7 @@ def _rmul_(self, other):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
sage: M = 2 * E # indirect doctest
@@ -1376,6 +1367,11 @@ def _rmul_(self, other):
sage: 1 * E is E
True
+ ::
+
+ sage: 0 * E is Seq2.zero()
+ True
+
We test that ``_rmul_`` and ``_lmul_`` are actually called::
sage: def print_name(f):
@@ -1394,9 +1390,11 @@ def _rmul_(self, other):
_lmul_
2-regular sequence 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, ...
"""
+ P = self.parent()
+ if other.is_zero():
+ return P._zero_()
if other.is_one():
return self
- P = self.parent()
return P.element_class(P, self.mu, other * self.left, self.right)
def _lmul_(self, other):
@@ -1414,7 +1412,7 @@ def _lmul_(self, other):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
sage: M = E * 2 # indirect doctest
@@ -1433,6 +1431,11 @@ def _lmul_(self, other):
sage: E * 1 is E
True
+ ::
+
+ sage: E * 0 is Seq2.zero()
+ True
+
The following is not tested, as `MS^i` for integers `i` does
not work, thus ``vector([m])`` fails. (See :trac:`21317` for
details.)
@@ -1449,9 +1452,11 @@ def _lmul_(self, other):
sage: M # not tested
sage: M.linear_representation() # not tested
"""
+ P = self.parent()
+ if other.is_zero():
+ return P._zero_()
if other.is_one():
return self
- P = self.parent()
return P.element_class(P, self.mu, self.left, self.right * other)
@minimize_result
@@ -1477,7 +1482,7 @@ def hadamard_product(self, other):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
@@ -1557,8 +1562,7 @@ def tensor_product(left, right):
return T
result = P.element_class(
P,
- dict((a, tensor_product(self.mu[a], other.mu[a]))
- for a in P.alphabet()),
+ {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()},
vector(tensor_product(Matrix(self.left), Matrix(other.left))),
vector(tensor_product(Matrix(self.right), Matrix(other.right))))
@@ -1722,7 +1726,6 @@ def __normalize__(cls,
return (coefficient_ring, indices, category, minimize_results)
- @experimental(issue_number=21202)
def __init__(self, coefficient_ring, indices, category, minimize_results):
r"""
See :class:`RecognizableSeriesSpace` for details.
@@ -1952,6 +1955,59 @@ def some_elements(self, **kwds):
break
yield self(mu, *LR, **kwds)
+ @cached_method
+ def _zero_(self):
+ r"""
+ Return the zero element of this :class:`RecognizableSeriesSpace`,
+ i.e. the unique neutral element for `+`.
+
+ TESTS::
+
+ sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1])
+ sage: Z = Rec._zero_(); Z
+ 0
+ sage: Z.linear_representation()
+ ((), Finite family {0: [], 1: []}, ())
+ """
+ from sage.matrix.constructor import Matrix
+ from sage.modules.free_module_element import vector
+ from sage.sets.family import Family
+
+ return self.element_class(
+ self, Family(self.alphabet(), lambda a: Matrix()),
+ vector([]), vector([]))
+
+ @cached_method
+ def one(self):
+ r"""
+ Return the one element of this :class:`RecognizableSeriesSpace`,
+ i.e. the embedding of the one of the coefficient ring into
+ this :class:`RecognizableSeriesSpace`.
+
+ EXAMPLES::
+
+ sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1])
+ sage: O = Rec.one(); O
+ [] + ...
+ sage: O.linear_representation()
+ ((1), Finite family {0: [0], 1: [0]}, (1))
+
+ TESTS::
+
+ sage: Rec.one() is Rec.one()
+ True
+ """
+ from sage.matrix.constructor import Matrix
+ from sage.modules.free_module_element import vector
+
+ R = self.coefficient_ring()
+ one = R.one()
+ zero = R.zero()
+ return self.element_class(self,
+ len(self.alphabet())*[Matrix([[zero]])],
+ vector([one]),
+ vector([one]))
+
@cached_method
def one_hadamard(self):
r"""
@@ -1979,7 +2035,7 @@ def one_hadamard(self):
from sage.modules.free_module_element import vector
one = self.coefficient_ring()(1)
- return self(dict((a, Matrix([[one]])) for a in self.alphabet()),
+ return self({a: Matrix([[one]]) for a in self.alphabet()},
vector([one]), vector([one]))
def _element_constructor_(self, data,
@@ -2006,6 +2062,19 @@ def _element_constructor_(self, data,
sage: Rec(S) is S
True
+ ::
+
+ sage: A = Rec(42); A
+ 42*[] + ...
+ sage: A.linear_representation()
+ ((42), Finite family {0: [0], 1: [0]}, (1))
+ sage: Z = Rec(0); Z
+ 0
+ sage: Z.linear_representation()
+ ((), Finite family {0: [], 1: []}, ())
+
+ ::
+
sage: Rec((M0, M1))
Traceback (most recent call last):
...
@@ -2024,13 +2093,7 @@ def _element_constructor_(self, data,
ValueError: left or right vector is None
"""
if isinstance(data, int) and data == 0:
- from sage.matrix.constructor import Matrix
- from sage.modules.free_module_element import vector
- from sage.sets.family import Family
-
- return self.element_class(
- self, Family(self.alphabet(), lambda a: Matrix()),
- vector([]), vector([]))
+ return self._zero_()
if type(data) == self.element_class and data.parent() == self:
element = data
@@ -2038,6 +2101,10 @@ def _element_constructor_(self, data,
elif isinstance(data, RecognizableSeries):
element = self.element_class(self, data.mu, data.left, data.right)
+ elif data in self.coefficient_ring():
+ c = self.coefficient_ring()(data)
+ return c * self.one()
+
else:
mu = data
if left is None or right is None:
diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/regular_sequence.py
similarity index 91%
rename from src/sage/combinat/k_regular_sequence.py
rename to src/sage/combinat/regular_sequence.py
index 6a1a2dabf71..afb83bed6f7 100644
--- a/src/sage/combinat/k_regular_sequence.py
+++ b/src/sage/combinat/regular_sequence.py
@@ -1,26 +1,11 @@
# sage.doctest: optional - sage.combinat sage.modules sage.symbolic
r"""
-`k`-regular Sequences
+`k`-regular sequences
An introduction and formal definition of `k`-regular sequences can be
found, for example, on the :wikipedia:`k-regular_sequence` or in
[AS2003]_.
-
-.. WARNING::
-
- As this code is experimental, warnings are thrown when a
- `k`-regular sequence space is created for the first time in a
- session (see :class:`sage.misc.superseded.experimental`).
-
- TESTS::
-
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
- doctest:...: FutureWarning: This class/method/function is
- marked as experimental. It, its functionality or its interface
- might change without a formal deprecation.
- See https://github.com/sagemath/sage/issues/21202 for details.
-
::
sage: import logging
@@ -35,7 +20,7 @@
The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies
`S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])),
....: left=vector([0, 1]), right=vector([1, 0]))
sage: S
@@ -125,7 +110,7 @@ def pad_right(T, length, zero=0):
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import pad_right
+ sage: from sage.combinat.regular_sequence import pad_right
sage: pad_right((1, 2, 3), 10)
(1, 2, 3, 0, 0, 0, 0, 0, 0, 0)
sage: pad_right((1, 2, 3), 2)
@@ -162,7 +147,7 @@ def value(D, k):
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import value
+ sage: from sage.combinat.regular_sequence import value
sage: value(42.digits(7), 7)
42
"""
@@ -172,11 +157,11 @@ def value(D, k):
class DegeneratedSequenceError(RuntimeError):
r"""
Exception raised if a degenerated sequence
- (see :meth:`~kRegularSequence.is_degenerated`) is detected.
+ (see :meth:`~RegularSequence.is_degenerated`) is detected.
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]))
Traceback (most recent call last):
...
@@ -188,14 +173,14 @@ class DegeneratedSequenceError(RuntimeError):
pass
-class kRegularSequence(RecognizableSeries):
+class RegularSequence(RecognizableSeries):
def __init__(self, parent, mu, left=None, right=None):
r"""
A `k`-regular sequence.
INPUT:
- - ``parent`` -- an instance of :class:`kRegularSequenceSpace`
+ - ``parent`` -- an instance of :class:`RegularSequenceRing`
- ``mu`` -- a family of square matrices, all of which have the
same dimension. The indices of this family are `0,...,k-1`.
@@ -213,7 +198,7 @@ def __init__(self, parent, mu, left=None, right=None):
from the right to the matrix product. If ``None``, then this
multiplication is skipped.
- When created via the parent :class:`kRegularSequenceSpace`, then
+ When created via the parent :class:`RegularSequenceRing`, then
the following option is available.
- ``allow_degenerated_sequence`` -- (default: ``False``) a boolean. If set, then
@@ -224,7 +209,7 @@ def __init__(self, parent, mu, left=None, right=None):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: S = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])),
....: vector([1, 0]), vector([0, 1])); S
2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...
@@ -244,8 +229,8 @@ def __init__(self, parent, mu, left=None, right=None):
.. SEEALSO::
- :doc:`k-regular sequence `,
- :class:`kRegularSequenceSpace`.
+ :doc:`k-regular sequence `,
+ :class:`RegularSequenceRing`.
TESTS::
@@ -262,7 +247,7 @@ def _repr_(self):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: s = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])),
....: vector([1, 0]), vector([0, 1]))
sage: repr(s) # indirect doctest
@@ -288,7 +273,7 @@ def coefficient_of_n(self, n, **kwds):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])),
....: left=vector([0, 1]), right=vector([1, 0]))
sage: S[7]
@@ -308,7 +293,7 @@ def coefficient_of_n(self, n, **kwds):
::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: W = Seq2.indices()
sage: M0 = Matrix([[1, 0], [0, 1]])
sage: M1 = Matrix([[0, -1], [1, 2]])
@@ -330,7 +315,7 @@ def __iter__(self):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])),
....: left=vector([0, 1]), right=vector([1, 0]))
sage: from itertools import islice
@@ -357,7 +342,7 @@ def is_degenerated(self):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) # indirect doctest
Traceback (most recent call last):
...
@@ -390,7 +375,7 @@ def _error_if_degenerated_(self):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), # indirect doctest
....: left=vector([0, 1]), right=vector([1, 0]))
Traceback (most recent call last):
@@ -425,7 +410,7 @@ def regenerated(self):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
ALGORITHM:
@@ -433,7 +418,7 @@ def regenerated(self):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
The following linear representation of `S` is chosen badly (is
degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on
@@ -517,14 +502,14 @@ def transposed(self, allow_degenerated_sequence=False):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
Each of the matrices in :meth:`mu ` is transposed. Additionally
the vectors :meth:`left ` and :meth:`right ` are switched.
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])),
....: left=vector([0, 1]), right=vector([1, 0]),
....: allow_degenerated_sequence=True)
@@ -568,7 +553,7 @@ def _minimized_right_(self):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
.. SEEALSO::
@@ -576,7 +561,7 @@ def _minimized_right_(self):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), # indirect doctest
....: left=vector([1, 0]), right=vector([0, 1])).minimized()
2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...
@@ -606,7 +591,7 @@ def subsequence(self, a, b):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
.. NOTE::
@@ -615,7 +600,7 @@ def subsequence(self, a, b):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
We consider the sequence `C` with `C(n) = n` and
the following linear representation
@@ -879,7 +864,7 @@ def shift_left(self, b=1, **kwds):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
.. NOTE::
@@ -888,7 +873,7 @@ def shift_left(self, b=1, **kwds):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])),
....: vector([1, 0]), vector([0, 1])); C
2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
@@ -925,7 +910,7 @@ def shift_right(self, b=1, **kwds):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
.. NOTE::
@@ -934,7 +919,7 @@ def shift_right(self, b=1, **kwds):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])),
....: vector([1, 0]), vector([0, 1])); C
2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
@@ -973,7 +958,7 @@ def backward_differences(self, **kwds):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
.. NOTE::
@@ -981,7 +966,7 @@ def backward_differences(self, **kwds):
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
....: vector([1, 0]), vector([0, 1]))
sage: C
@@ -1014,11 +999,11 @@ def forward_differences(self, **kwds):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
....: vector([1, 0]), vector([0, 1]))
sage: C
@@ -1037,6 +1022,115 @@ def forward_differences(self, **kwds):
"""
return self.subsequence(1, {1: 1, 0: -1}, **kwds)
+ @minimize_result
+ def _mul_(self, other):
+ r"""
+ Return the product of this `k`-regular sequence with ``other``,
+ where the multiplication is convolution of power series.
+
+ The operator `*` is mapped to :meth:`convolution`.
+
+ INPUT:
+
+ - ``other`` -- a :class:`RegularSequence`
+
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
+ if ``False``, then not. If this argument is ``None``, then
+ the default specified by the parent's ``minimize_results`` is used.
+
+ OUTPUT:
+
+ A :class:`RegularSequence`
+
+ ALGORITHM:
+
+ See pdf attached to
+ `github pull request #35894 `_
+ which contains a draft describing the details of the used algorithm.
+
+ EXAMPLES::
+
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
+ sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
+ ....: vector([1, 0]), vector([1, 1]))
+ sage: E
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
+
+ We can build the convolution (in the sense of power-series) of `E` by
+ itself via::
+
+ sage: E.convolution(E)
+ 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ...
+
+ This is the same as using multiplication operator::
+
+ sage: E * E
+ 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ...
+
+ Building :meth:`partial_sums` can also be seen as a convolution::
+
+ sage: o = Seq2.one_hadamard()
+ sage: E * o
+ 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ...
+ sage: E * o == E.partial_sums(include_n=True)
+ True
+
+ TESTS::
+
+ sage: E * o == o * E
+ True
+ """
+ from sage.arith.srange import srange
+ from sage.matrix.constructor import Matrix
+ from sage.matrix.special import zero_matrix
+ from sage.modules.free_module_element import vector
+
+ P = self.parent()
+ k = P.k
+
+ def tensor_product(left, right):
+ T = left.tensor_product(right)
+ T.subdivide()
+ return T
+
+ matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s])
+ for s in srange(0, r+1))
+ for r in P.alphabet()}
+ matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s])
+ for s in srange(r+1, k))
+ for r in P.alphabet()}
+ left = vector(tensor_product(Matrix(self.left), Matrix(other.left)))
+ right = vector(tensor_product(Matrix(self.right), Matrix(other.right)))
+
+ def linear_representation_morphism_recurrence_order_1(C, D):
+ r"""
+ Return the morphism of a linear representation
+ for the sequence `z_n` satisfying
+ `z_{kn+r} = C_r z_n + D_r z_{n-1}`.
+ """
+ Z = zero_matrix(C[0].dimensions()[0])
+
+ def blocks(r):
+ upper = list([C[s], D[s], Z]
+ for s in reversed(srange(max(0, r-2), r+1)))
+ lower = list([Z, C[s], D[s]]
+ for s in reversed(srange(k-3+len(upper), k)))
+ return upper + lower
+
+ return {r: Matrix.block(blocks(r)) for r in P.alphabet()}
+
+ result = P.element_class(
+ P,
+ linear_representation_morphism_recurrence_order_1(matrices_0,
+ matrices_1),
+ vector(list(left) + (2*len(list(left)))*[0]),
+ vector(list(right) + (2*len(list(right)))*[0]))
+
+ return result
+
+ convolution = _mul_
+
@minimize_result
def partial_sums(self, include_n=False):
r"""
@@ -1057,11 +1151,11 @@ def partial_sums(self, include_n=False):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
EXAMPLES::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
....: vector([1, 0]), vector([1, 1]))
@@ -1101,7 +1195,7 @@ def partial_sums(self, include_n=False):
sage: H
2-regular sequence 0, 2, 10, 16, 50, 62, 80, 98, 250, 274, ...
- We can :meth:`~kRegularSequenceSpace.guess` the correct representation::
+ We can :meth:`~RegularSequenceRing.guess` the correct representation::
sage: from itertools import islice
sage: L = []; ps = 0
@@ -1141,20 +1235,36 @@ def partial_sums(self, include_n=False):
1: [0 0]
[0 1]},
(1, 1))
+
sage: P = E.partial_sums(minimize=False)
sage: P.linear_representation()
- ((1, 0, -1, 0),
- Finite family {0: [ 0 1| 0 0]
- [ 0 2| 0 -1]
- [-----+-----]
- [ 0 0| 0 1]
- [ 0 0| 0 1],
- 1: [0 1|0 0]
+ ((1, 0, 0, 0),
+ Finite family {0: [0 1|0 0]
+ [0 2|0 0]
+ [---+---]
+ [0 0|0 1]
+ [0 0|0 1],
+ 1: [0 1|0 1]
+ [0 2|0 1]
+ [---+---]
+ [0 0|0 0]
+ [0 0|0 1]},
+ (0, 0, 1, 1))
+
+ sage: P = E.partial_sums(include_n=True, minimize=False)
+ sage: P.linear_representation()
+ ((1, 0, 1, 0),
+ Finite family {0: [0 1|0 0]
[0 2|0 0]
[---+---]
+ [0 0|0 1]
+ [0 0|0 1],
+ 1: [0 1|0 1]
+ [0 2|0 1]
+ [---+---]
[0 0|0 0]
[0 0|0 1]},
- (1, 1, 1, 1))
+ (0, 0, 1, 1))
"""
from itertools import chain
from sage.matrix.constructor import Matrix
@@ -1165,37 +1275,41 @@ def partial_sums(self, include_n=False):
A = P.alphabet()
k = P.k
dim = self.dimension()
-
- B = {r: sum(self.mu[a] for a in A[r:]) for r in A}
Z = zero_matrix(dim)
- B[k] = Z
+
+ z = A[0]
+ assert z == 0
+ B = {z: Z}
+ for r in A:
+ B[r+1] = B[r] + self.mu[r]
+ C = B[k]
result = P.element_class(
P,
- {r: Matrix.block([[B[0], -B[r + 1]], [Z, self.mu[r]]]) for r in A},
+ {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A},
vector(chain(self.left,
- (dim * (0,) if include_n else -self.left))),
- vector(chain(self.right, self.right)))
+ (dim * (0,) if not include_n else self.left))),
+ vector(chain(dim * (0,), self.right)))
return result
-def _pickle_kRegularSequenceSpace(k, coefficients, category):
+def _pickle_RegularSequenceRing(k, coefficients, category):
r"""
Pickle helper.
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
- sage: from sage.combinat.k_regular_sequence import _pickle_kRegularSequenceSpace
- sage: _pickle_kRegularSequenceSpace(
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
+ sage: from sage.combinat.regular_sequence import _pickle_RegularSequenceRing
+ sage: _pickle_RegularSequenceRing(
....: Seq2.k, Seq2.coefficient_ring(), Seq2.category())
Space of 2-regular sequences over Integer Ring
"""
- return kRegularSequenceSpace(k, coefficients, category=category)
+ return RegularSequenceRing(k, coefficients, category=category)
-class kRegularSequenceSpace(RecognizableSeriesSpace):
+class RegularSequenceRing(RecognizableSeriesSpace):
r"""
The space of `k`-regular Sequences over the given ``coefficient_ring``.
@@ -1210,42 +1324,49 @@ class kRegularSequenceSpace(RecognizableSeriesSpace):
EXAMPLES::
- sage: kRegularSequenceSpace(2, ZZ)
+ sage: RegularSequenceRing(2, ZZ)
Space of 2-regular sequences over Integer Ring
- sage: kRegularSequenceSpace(3, ZZ)
+ sage: RegularSequenceRing(3, ZZ)
Space of 3-regular sequences over Integer Ring
.. SEEALSO::
- :doc:`k-regular sequence `,
- :class:`kRegularSequence`.
+ :doc:`k-regular sequence `,
+ :class:`RegularSequence`.
"""
- Element = kRegularSequence
+ Element = RegularSequence
@classmethod
- def __normalize__(cls, k, coefficient_ring, **kwds):
+ def __normalize__(cls, k,
+ coefficient_ring,
+ category=None,
+ **kwds):
r"""
Normalizes the input in order to ensure a unique
representation.
- For more information see :class:`kRegularSequenceSpace`.
+ For more information see :class:`RegularSequenceRing`.
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2.category()
- Category of modules over Integer Ring
+ Category of algebras over Integer Ring
sage: Seq2.alphabet()
{0, 1}
"""
from sage.arith.srange import srange
+ from sage.categories.algebras import Algebras
+ category = category or Algebras(coefficient_ring)
nargs = super().__normalize__(coefficient_ring,
- alphabet=srange(k), **kwds)
+ alphabet=srange(k),
+ category=category,
+ **kwds)
return (k,) + nargs
def __init__(self, k, *args, **kwds):
r"""
- See :class:`kRegularSequenceSpace` for details.
+ See :class:`RegularSequenceRing` for details.
INPUT:
@@ -1256,22 +1377,22 @@ def __init__(self, k, *args, **kwds):
TESTS::
- sage: kRegularSequenceSpace(2, ZZ)
+ sage: RegularSequenceRing(2, ZZ)
Space of 2-regular sequences over Integer Ring
- sage: kRegularSequenceSpace(3, ZZ)
+ sage: RegularSequenceRing(3, ZZ)
Space of 3-regular sequences over Integer Ring
::
sage: from itertools import islice
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: TestSuite(Seq2).run( # long time
....: elements=tuple(islice(Seq2.some_elements(), 4)))
.. SEEALSO::
- :doc:`k-regular sequence `,
- :class:`kRegularSequence`.
+ :doc:`k-regular sequence `,
+ :class:`RegularSequence`.
"""
self.k = k
super().__init__(*args, **kwds)
@@ -1282,11 +1403,11 @@ def __reduce__(self):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: loads(dumps(Seq2)) # indirect doctest
Space of 2-regular sequences over Integer Ring
"""
- return _pickle_kRegularSequenceSpace, \
+ return _pickle_RegularSequenceRing, \
(self.k, self.coefficient_ring(), self.category())
def _repr_(self):
@@ -1297,7 +1418,7 @@ def _repr_(self):
TESTS::
- sage: repr(kRegularSequenceSpace(2, ZZ)) # indirect doctest
+ sage: repr(RegularSequenceRing(2, ZZ)) # indirect doctest
'Space of 2-regular sequences over Integer Ring'
"""
return 'Space of {}-regular sequences over {}'.format(self.k, self.base())
@@ -1315,7 +1436,7 @@ def _n_to_index_(self, n):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2._n_to_index_(6)
word: 011
sage: Seq2._n_to_index_(-1)
@@ -1331,6 +1452,39 @@ def _n_to_index_(self, n):
except OverflowError:
raise ValueError('value {} of index is negative'.format(n)) from None
+ @cached_method
+ def one(self):
+ r"""
+ Return the one element of this :class:`RegularSequenceRing`,
+ i.e. the unique neutral element for `*` and also
+ the embedding of the one of the coefficient ring into
+ this :class:`RegularSequenceRing`.
+
+ EXAMPLES::
+
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
+ sage: O = Seq2.one(); O
+ 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
+ sage: O.linear_representation()
+ ((1), Finite family {0: [1], 1: [0]}, (1))
+
+ TESTS::
+
+ sage: Seq2.one() is Seq2.one()
+ True
+ """
+ from sage.matrix.constructor import Matrix
+ from sage.modules.free_module_element import vector
+
+ R = self.coefficient_ring()
+ one = R.one()
+ zero = R.zero()
+ return self.element_class(self,
+ [Matrix([[one]])]
+ + (self.k-1)*[Matrix([[zero]])],
+ vector([one]),
+ vector([one]))
+
def some_elements(self):
r"""
Return some elements of this `k`-regular sequence.
@@ -1343,7 +1497,7 @@ def some_elements(self):
EXAMPLES::
- sage: tuple(kRegularSequenceSpace(2, ZZ).some_elements())
+ sage: tuple(RegularSequenceRing(2, ZZ).some_elements())
(2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...,
2-regular sequence 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, ...,
2-regular sequence 1, 1, 0, 1, -1, 0, 0, 1, -2, -1, ...,
@@ -1356,18 +1510,18 @@ def some_elements(self):
"""
return iter(element.regenerated()
for element
- in super(kRegularSequenceSpace, self).some_elements(
+ in super(RegularSequenceRing, self).some_elements(
allow_degenerated_sequence=True))
def _element_constructor_(self, *args, **kwds):
r"""
Return a `k`-regular sequence.
- See :class:`kRegularSequenceSpace` for details.
+ See :class:`RegularSequenceRing` for details.
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]))
Traceback (most recent call last):
...
@@ -1383,7 +1537,7 @@ def _element_constructor_(self, *args, **kwds):
2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
"""
allow_degenerated_sequence = kwds.pop('allow_degenerated_sequence', False)
- element = super(kRegularSequenceSpace, self)._element_constructor_(*args, **kwds)
+ element = super(RegularSequenceRing, self)._element_constructor_(*args, **kwds)
if not allow_degenerated_sequence:
element._error_if_degenerated_()
return element
@@ -1412,7 +1566,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
OUTPUT:
- A :class:`kRegularSequence`
+ A :class:`RegularSequence`
ALGORITHM:
@@ -1449,7 +1603,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
Let us guess a `2`-linear representation for `s(n)`::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: import logging
sage: logging.getLogger().setLevel(logging.INFO)
sage: S1 = Seq2.guess(s); S1
@@ -1539,7 +1693,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
sage: S.is_degenerated()
True
- However, we can :meth:`~kRegularSequenceSpace.guess` a `2`-regular sequence of dimension `2`::
+ However, we can :meth:`~RegularSequenceRing.guess` a `2`-regular sequence of dimension `2`::
sage: G = Seq2.guess(lambda n: S[n])
sage: G
@@ -1582,7 +1736,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
1: [1]},
(1))
- We :meth:`~kRegularSequenceSpace.guess` some partial sums sequences::
+ We :meth:`~RegularSequenceRing.guess` some partial sums sequences::
sage: S = Seq2((Matrix([1]), Matrix([2])), vector([1]), vector([1]))
sage: S
@@ -1607,7 +1761,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
::
- sage: Seq3 = kRegularSequenceSpace(3, QQ)
+ sage: Seq3 = RegularSequenceRing(3, QQ)
sage: S = Seq3((Matrix([1]), Matrix([3]), Matrix([2])), vector([1]), vector([1]))
sage: S
3-regular sequence 1, 3, 2, 3, 9, 6, 2, 6, 4, 3, ...
@@ -1640,7 +1794,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
::
- sage: R = kRegularSequenceSpace(2, QQ)
+ sage: R = RegularSequenceRing(2, QQ)
sage: one = R.one_hadamard()
sage: S = R.guess(lambda n: sum(n.bits()), sequence=one) + one
sage: T = R.guess(lambda n: n*n, sequence=S, n_verify=4); T
@@ -1844,7 +1998,7 @@ def from_recurrence(self, *args, **kwds):
::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: var('n')
n
sage: function('f')
@@ -1876,7 +2030,7 @@ def from_recurrence(self, *args, **kwds):
+ l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers
`0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some
coefficients `c_{r,j}` from the (semi)ring ``coefficients``
- of the corresponding :class:`kRegularSequenceSpace`, valid
+ of the corresponding :class:`RegularSequenceRing`, valid
for all integers `n \geq \text{offset}` for some integer
`\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and
there is an equation of this form (with the same
@@ -1926,13 +2080,13 @@ def from_recurrence(self, *args, **kwds):
in [HKL2022]_, Corollary D. All inhomogeneities have to be
regular sequences from ``self`` or elements of ``coefficient_ring``.
- OUTPUT: a :class:`kRegularSequence`
+ OUTPUT: a :class:`RegularSequence`
EXAMPLES:
Stern--Brocot Sequence::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: var('n')
n
sage: function('f')
@@ -2006,7 +2160,7 @@ def from_recurrence(self, *args, **kwds):
Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_)::
- sage: Seq2 = kRegularSequenceSpace(2, QQ)
+ sage: Seq2 = RegularSequenceRing(2, QQ)
sage: P = Seq2.from_recurrence([
....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1),
....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1),
@@ -2189,8 +2343,8 @@ class RecurrenceParser():
the construction of a `k`-linear representation
for the sequence satisfying these recurrence relations.
- This is used by :meth:`kRegularSequenceSpace.from_recurrence`
- to construct a :class:`kRegularSequence`.
+ This is used by :meth:`RegularSequenceRing.from_recurrence`
+ to construct a :class:`RegularSequence`.
"""
def __init__(self, k, coefficient_ring):
@@ -2204,37 +2358,37 @@ def __init__(self, k, coefficient_ring):
- ``coefficient_ring`` -- a ring.
These are the same parameters used when creating
- a :class:`kRegularSequenceSpace`.
+ a :class:`RegularSequenceRing`.
TESTS::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RecurrenceParser(2, ZZ)
-
+
"""
self.k = k
self.coefficient_ring = coefficient_ring
def parse_recurrence(self, equations, function, var):
r"""
- Parse recurrence relations as admissible in :meth:`kRegularSequenceSpace.from_recurrence`.
+ Parse recurrence relations as admissible in :meth:`RegularSequenceRing.from_recurrence`.
INPUT:
All parameters are explained in the high-level method
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
OUTPUT: a tuple consisting of
- - ``M``, ``m`` -- see :meth:`kRegularSequenceSpace.from_recurrence`
+ - ``M``, ``m`` -- see :meth:`RegularSequenceRing.from_recurrence`
- - ``coeffs`` -- see :meth:`kRegularSequenceSpace.from_recurrence`
+ - ``coeffs`` -- see :meth:`RegularSequenceRing.from_recurrence`
- - ``initial_values`` -- see :meth:`kRegularSequenceSpace.from_recurrence`
+ - ``initial_values`` -- see :meth:`RegularSequenceRing.from_recurrence`
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: var('n')
n
@@ -2259,7 +2413,7 @@ def parse_recurrence(self, equations, function, var):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
TESTS:
@@ -2604,7 +2758,7 @@ def parse_recurrence(self, equations, function, var):
This results in giving the correct (see :trac:`33158`) minimization in::
- sage: Seq2 = kRegularSequenceSpace(2, QQ)
+ sage: Seq2 = RegularSequenceRing(2, QQ)
sage: P = Seq2.from_recurrence(equations, f, n)
sage: P
2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ...
@@ -2804,18 +2958,18 @@ def parse_one_summand(summand, eq):
def parse_direct_arguments(self, M, m, coeffs, initial_values):
r"""
Check whether the direct arguments as admissible in
- :meth:`kRegularSequenceSpace.from_recurrence` are valid.
+ :meth:`RegularSequenceRing.from_recurrence` are valid.
INPUT:
All parameters are explained in the high-level method
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
OUTPUT: a tuple consisting of the input parameters
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: RP.parse_direct_arguments(2, 1,
....: {(0, -2): 3, (0, 0): 1, (0, 1): 2,
@@ -2838,7 +2992,7 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
TESTS:
@@ -2981,12 +3135,12 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values):
def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}):
r"""
Determine parameters from recurrence relations as admissible in
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
INPUT:
All parameters are explained in the high-level method
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
OUTPUT: a namedtuple ``recurrence_rules`` consisting of
@@ -3009,7 +3163,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={})
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: RP.parameters(2, 1,
....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4,
@@ -3026,7 +3180,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={})
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
TESTS::
@@ -3050,7 +3204,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={})
::
- sage: Seq3 = kRegularSequenceSpace(3, ZZ)
+ sage: Seq3 = RegularSequenceRing(3, ZZ)
sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0,
....: {0: Seq3.zero()})
Traceback (most recent call last):
@@ -3128,12 +3282,12 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={})
raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no "
f"integers between 0 and {k**M - 1}.")
- Seq = kRegularSequenceSpace(k, coefficient_ring)
+ Seq = RegularSequenceRing(k, coefficient_ring)
inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard()
for i in inhomogeneities
if inhomogeneities[i] in coefficient_ring})
invalid = {i: inhomogeneities[i] for i in inhomogeneities
- if not (isinstance(inhomogeneities[i].parent(), kRegularSequenceSpace) and
+ if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and
inhomogeneities[i].parent().k == k)}
if invalid:
raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular "
@@ -3177,7 +3331,7 @@ def values(self, *, M, m, l, u, ll, coeffs,
initial_values, last_value_needed, offset, inhomogeneities):
r"""
Determine enough values of the corresponding recursive sequence by
- applying the recurrence relations given in :meth:`kRegularSequenceSpace.from_recurrence`
+ applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence`
to the values given in ``initial_values``.
INPUT:
@@ -3189,7 +3343,7 @@ def values(self, *, M, m, l, u, ll, coeffs,
see [HKL2022]_, Theorem A
- ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the
- coefficient `c_{r,j}` as given in :meth:`kRegularSequenceSpace.from_recurrence`.
+ coefficient `c_{r,j}` as given in :meth:`RegularSequenceRing.from_recurrence`.
If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``,
then it is assumed to be zero.
@@ -3211,7 +3365,7 @@ def values(self, *, M, m, l, u, ll, coeffs,
Stern--Brocot Sequence::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
@@ -3222,7 +3376,7 @@ def values(self, *, M, m, l, u, ll, coeffs,
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
TESTS:
@@ -3303,7 +3457,7 @@ def values(self, *, M, m, l, u, ll, coeffs,
::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: RP.values(M=1, m=0, l=0, u=0, ll=0,
....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={},
....: last_value_needed=10, offset=0,
@@ -3397,7 +3551,7 @@ def ind(self, M, m, ll, uu):
EXAMPLES::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: RP.ind(3, 1, -3, 3)
{(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1,
@@ -3410,7 +3564,7 @@ def ind(self, M, m, ll, uu):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
"""
from sage.arith.srange import srange
@@ -3460,9 +3614,9 @@ def shifted_inhomogeneities(self, recurrence_rules):
EXAMPLES::
sage: from collections import namedtuple
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])),
....: left=vector([0, 1]), right=vector([1, 0]))
sage: S
@@ -3495,7 +3649,7 @@ def shifted_inhomogeneities(self, recurrence_rules):
TESTS::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: var('n')
n
sage: function('f')
@@ -3528,7 +3682,7 @@ def shifted_inhomogeneities(self, recurrence_rules):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
"""
from sage.arith.srange import srange
from sage.functions.other import floor
@@ -3564,7 +3718,7 @@ def v_eval_n(self, recurrence_rules, n):
Stern--Brocot Sequence::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: SB_rules = RP.parameters(
....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1},
@@ -3574,7 +3728,7 @@ def v_eval_n(self, recurrence_rules, n):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
"""
from itertools import chain
@@ -3628,7 +3782,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True):
right-hand sides of the recurrence relations correspond to the entries of
the matrices. ::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: var('n')
n
@@ -3753,7 +3907,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
"""
from itertools import chain
@@ -3871,7 +4025,7 @@ def left(self, recurrence_rules):
EXAMPLES::
sage: from collections import namedtuple
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: RRD = namedtuple('recurrence_rules_dim',
....: ['dim', 'inhomogeneities'])
@@ -3881,7 +4035,7 @@ def left(self, recurrence_rules):
::
- sage: Seq2 = kRegularSequenceSpace(2, ZZ)
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
sage: RRD = namedtuple('recurrence_rules_dim',
....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities'])
sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5,
@@ -3891,7 +4045,7 @@ def left(self, recurrence_rules):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
"""
from sage.modules.free_module_element import vector
@@ -3919,13 +4073,13 @@ def right(self, recurrence_rules):
.. SEEALSO::
- :meth:`kRegularSequenceSpace.from_recurrence`
+ :meth:`RegularSequenceRing.from_recurrence`
TESTS:
Stern--Brocot Sequence::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: var('n')
n
@@ -3974,22 +4128,22 @@ def __call__(self, *args, **kwds):
given in ``equations``.
This is the main method of :class:`RecurrenceParser` and
- is called by :meth:`kRegularSequenceSpace.from_recurrence`
- to construct a :class:`kRegularSequence`.
+ is called by :meth:`RegularSequenceRing.from_recurrence`
+ to construct a :class:`RegularSequence`.
INPUT:
All parameters are explained in the high-level method
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
OUTPUT: a linear representation ``(left, mu, right)``
Many examples can be found in
- :meth:`kRegularSequenceSpace.from_recurrence`.
+ :meth:`RegularSequenceRing.from_recurrence`.
TESTS::
- sage: from sage.combinat.k_regular_sequence import RecurrenceParser
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
sage: RP = RecurrenceParser(2, ZZ)
sage: var('n')
n
diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py
index 4844662073d..9261c69dd4b 100644
--- a/src/sage/doctest/control.py
+++ b/src/sage/doctest/control.py
@@ -281,6 +281,10 @@ def skipfile(filename, tested_optional_tags=False, *,
if log:
log(f"Skipping '{filename}' because it does not have one of the recognized file name extensions")
return True
+ if if_installed and ext not in ('.py', '.pyx'):
+ if log:
+ log(f"Skipping '{filename}' because it is not the source file of a Python module")
+ return True
if "jupyter_execute" in filename:
if log:
log(f"Skipping '{filename}' because it is created by the jupyter-sphinx extension for internal use and should not be tested")
diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py
index 234a4f82aa9..bafa3283990 100644
--- a/src/sage/functions/transcendental.py
+++ b/src/sage/functions/transcendental.py
@@ -17,6 +17,7 @@
# ****************************************************************************
import sys
+from sage.misc.misc import increase_recursion_limit
from sage.rings.integer_ring import ZZ
from sage.rings.real_mpfr import RR
from sage.rings.real_double import RDF
@@ -551,9 +552,8 @@ def _eval_(self, x):
max = x.parent()(1.1)*x + 10
abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil()
self._f = {}
- if sys.getrecursionlimit() < max + 10:
- sys.setrecursionlimit(int(max) + 10)
- self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
+ with increase_recursion_limit(int(max)):
+ self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
return self._f[n](2*(x-n-x.parent()(0.5)))
def power_series(self, n, abs_prec):
diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx
index d6508f172f8..ff222837117 100644
--- a/src/sage/graphs/base/boost_graph.pyx
+++ b/src/sage/graphs/base/boost_graph.pyx
@@ -572,7 +572,7 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'):
from sage.graphs.base.boost_graph import bandwidth_heuristics
sage: bandwidth_heuristics(Graph())
(0, [])
- sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # optional - networkx
+ sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # needs networkx
(0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
"""
@@ -1964,8 +1964,8 @@ cpdef diameter_DHV(g, weight_function=None, check_weight=True):
TESTS::
- sage: G = graphs.RandomBarabasiAlbert(17,6) # optional - networkx
- sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # optional - networkx
+ sage: G = graphs.RandomBarabasiAlbert(17,6) # needs networkx
+ sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # needs networkx
True
sage: G = Graph([(0,1,-1)], weighted=True)
sage: diameter_DHV(G)
diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx
index a4f2efd6060..79e62e13a33 100644
--- a/src/sage/graphs/base/c_graph.pyx
+++ b/src/sage/graphs/base/c_graph.pyx
@@ -1576,12 +1576,13 @@ cdef class CGraphBackend(GenericGraphBackend):
We check that the bug described in :trac:`8406` is gone::
+ sage: # needs sage.rings.finite_rings
sage: G = Graph()
- sage: R. = GF(3**3) # optional - sage.rings.finite_rings
- sage: S. = R[] # optional - sage.rings.finite_rings
- sage: G.add_vertex(a**2) # optional - sage.rings.finite_rings
- sage: G.add_vertex(x) # optional - sage.rings.finite_rings
- sage: G.vertices(sort=True) # optional - sage.rings.finite_rings
+ sage: R. = GF(3**3)
+ sage: S. = R[]
+ sage: G.add_vertex(a**2)
+ sage: G.add_vertex(x)
+ sage: G.vertices(sort=True)
[a^2, x]
And that the bug described in :trac:`9610` is gone::
@@ -2107,9 +2108,9 @@ cdef class CGraphBackend(GenericGraphBackend):
Ensure that :trac:`13664` is fixed ::
- sage: W = WeylGroup(["A",1]) # optional - sage.combinat sage.groups
- sage: G = W.cayley_graph() # optional - sage.combinat sage.groups
- sage: Graph(G).degree() # optional - sage.combinat sage.groups
+ sage: W = WeylGroup(["A",1]) # needs sage.combinat sage.groups
+ sage: G = W.cayley_graph() # needs sage.combinat sage.groups
+ sage: Graph(G).degree() # needs sage.combinat sage.groups
[1, 1]
sage: h = Graph()
sage: h.add_edge(1,2,"a")
@@ -4406,9 +4407,9 @@ cdef class CGraphBackend(GenericGraphBackend):
TESTS::
- sage: P = posets.PentagonPoset() # optional - sage.modules
- sage: H = P._hasse_diagram # optional - sage.modules
- sage: H._backend.is_connected() # optional - sage.modules
+ sage: P = posets.PentagonPoset() # needs sage.modules
+ sage: H = P._hasse_diagram # needs sage.modules
+ sage: H._backend.is_connected() # needs sage.modules
True
"""
cdef int v_int
@@ -4548,7 +4549,7 @@ cdef class CGraphBackend(GenericGraphBackend):
At first, the following graph is acyclic::
sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
- sage: D.plot(layout='circular').show() # optional - sage.plot
+ sage: D.plot(layout='circular').show() # needs sage.plot
sage: D.is_directed_acyclic()
True
@@ -4589,9 +4590,9 @@ cdef class CGraphBackend(GenericGraphBackend):
TESTS::
- sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # optional - sage.modules
- sage: g = DiGraph(m) # optional - sage.modules
- sage: g.is_directed_acyclic(certificate=True) # optional - sage.modules
+ sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # needs sage.modules
+ sage: g = DiGraph(m) # needs sage.modules
+ sage: g.is_directed_acyclic(certificate=True) # needs sage.modules
(True, [0, 2, 1])
"""
if not self._directed:
diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx
index a8de583d4db..2eecc1a69d0 100644
--- a/src/sage/graphs/base/static_sparse_backend.pyx
+++ b/src/sage/graphs/base/static_sparse_backend.pyx
@@ -446,17 +446,18 @@ cdef class StaticSparseBackend(CGraphBackend):
::
- sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") # optional - sage.combinat
- sage: gi = DiGraph(g, data_structure="static_sparse") # optional - sage.combinat
- sage: gi.edges(sort=True)[0] # optional - sage.combinat
+ sage: # needs sage.combinat
+ sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse")
+ sage: gi = DiGraph(g, data_structure="static_sparse")
+ sage: gi.edges(sort=True)[0]
('000', '000', '0')
- sage: sorted(gi.edges_incident('111')) # optional - sage.combinat
+ sage: sorted(gi.edges_incident('111'))
[('111', '110', '0'),
('111', '111', '1'),
('111', '112', '2'),
('111', '113', '3')]
- sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # optional - sage.combinat
+ sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # needs sage.combinat
True
::
@@ -671,10 +672,10 @@ cdef class StaticSparseBackend(CGraphBackend):
::
sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
- sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # optional - sage.combinat
- sage: g.has_edge('00', '01', '1') # optional - sage.combinat
+ sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # needs sage.combinat
+ sage: g.has_edge('00', '01', '1') # needs sage.combinat
True
- sage: g.has_edge('00', '01', '0') # optional - sage.combinat
+ sage: g.has_edge('00', '01', '0') # needs sage.combinat
False
"""
try:
diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx
index cfaff95ccde..6fd78510c94 100644
--- a/src/sage/graphs/base/static_sparse_graph.pyx
+++ b/src/sage/graphs/base/static_sparse_graph.pyx
@@ -731,8 +731,8 @@ def tarjan_strongly_connected_components(G):
Checking against NetworkX::
- sage: import networkx # optional - networkx
- sage: for i in range(10): # long time # optional - networkx
+ sage: import networkx # needs networkx
+ sage: for i in range(10): # long time # needs networkx
....: g = digraphs.RandomDirectedGNP(100,.05)
....: h = g.networkx_graph()
....: scc1 = g.strongly_connected_components()
@@ -1023,8 +1023,8 @@ def spectral_radius(G, prec=1e-10):
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)])
sage: e_min, e_max = spectral_radius(G, 1e-14)
- sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False))
- sage: e_min < e < e_max
+ sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) # needs sage.modules
+ sage: e_min < e < e_max # needs sage.modules
True
sage: G.spectral_radius() # abs tol 1e-9
@@ -1037,10 +1037,10 @@ def spectral_radius(G, prec=1e-10):
sage: G.add_edge(200,0)
sage: G.add_edge(1,0)
sage: e_min, e_max = spectral_radius(G, 0.00001)
- sage: p = G.adjacency_matrix(sparse=True).charpoly()
- sage: p
+ sage: p = G.adjacency_matrix(sparse=True).charpoly() # needs sage.modules
+ sage: p # needs sage.modules
x^201 - x^199 - 1
- sage: r = p.roots(AA, multiplicities=False)[0]
+ sage: r = p.roots(AA, multiplicities=False)[0] # needs sage.modules
sage: e_min < r < e_max
True
@@ -1060,7 +1060,7 @@ def spectral_radius(G, prec=1e-10):
sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)])
sage: spectral_radius(G, 1e-14) # abs tol 1e-14
(2.414213562373094, 2.414213562373095)
- sage: max(G.adjacency_matrix().eigenvalues(AA))
+ sage: max(G.adjacency_matrix().eigenvalues(AA)) # needs sage.modules
2.414213562373095?
Some bipartite graphs::
@@ -1091,7 +1091,7 @@ def spectral_radius(G, prec=1e-10):
...
ValueError: precision (=1.00000000000000e-20) is too small
- sage: for _ in range(100):
+ sage: for _ in range(100): # needs sage.modules
....: G = digraphs.RandomDirectedGNM(10,35)
....: if not G.is_strongly_connected():
....: continue
diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py
index 635d5554329..b2c9fdbf3db 100644
--- a/src/sage/graphs/bipartite_graph.py
+++ b/src/sage/graphs/bipartite_graph.py
@@ -161,7 +161,7 @@ class BipartiteGraph(Graph):
sage: B = BipartiteGraph(P, partition, check=False)
sage: B.left
{0, 1, 2, 3, 4}
- sage: B.show() # optional - sage.plot
+ sage: B.show() # needs sage.plot
::
@@ -198,16 +198,17 @@ class BipartiteGraph(Graph):
#. From a reduced adjacency matrix::
- sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules
+ sage: # needs sage.modules
+ sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
- sage: M # optional - sage.modules
+ sage: M
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
- sage: H = BipartiteGraph(M); H # optional - sage.modules
+ sage: H = BipartiteGraph(M); H
Bipartite graph on 11 vertices
- sage: H.edges(sort=True) # optional - sage.modules
+ sage: H.edges(sort=True)
[(0, 7, None),
(0, 8, None),
(0, 10, None),
@@ -224,9 +225,9 @@ class BipartiteGraph(Graph):
::
- sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # optional - sage.modules
- sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules
- sage: B.edges(sort=True) # optional - sage.modules
+ sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # needs sage.modules
+ sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules
+ sage: B.edges(sort=True) # needs sage.modules
[(0, 5, None),
(1, 5, None),
(1, 6, None),
@@ -244,13 +245,14 @@ class BipartiteGraph(Graph):
::
- sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings
- sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings
- sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings
- sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings
- sage: B.edges(sort=True) # optional - sage.modules sage.rings.finite_rings
+ sage: # needs sage.modules sage.rings.finite_rings
+ sage: F. = GF(4)
+ sage: MS = MatrixSpace(F, 2, 3)
+ sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]])
+ sage: B = BipartiteGraph(M, weighted=True, sparse=True)
+ sage: B.edges(sort=True)
[(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)]
- sage: B.weighted() # optional - sage.modules sage.rings.finite_rings
+ sage: B.weighted()
True
#. From an alist file::
@@ -264,7 +266,7 @@ class BipartiteGraph(Graph):
....: 1 2 4 7 \n")
....: f.flush()
....: B = BipartiteGraph(f.name)
- sage: B.is_isomorphic(H) # optional - sage.modules
+ sage: B.is_isomorphic(H) # needs sage.modules
True
#. From a ``graph6`` string::
@@ -307,14 +309,15 @@ class BipartiteGraph(Graph):
sage: B = BipartiteGraph('F?^T_\n', partition=[[0, 1, 2], [3, 4, 5, 6]], check=False)
sage: B.left
{0, 1, 2}
- sage: B.show() # optional - sage.plot
+ sage: B.show() # needs sage.plot
#. From a NetworkX bipartite graph::
- sage: import networkx # optional - networkx
- sage: G = graphs.OctahedralGraph() # optional - networkx
- sage: N = networkx.make_clique_bipartite(G.networkx_graph()) # optional - networkx
- sage: B = BipartiteGraph(N) # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: G = graphs.OctahedralGraph()
+ sage: N = networkx.make_clique_bipartite(G.networkx_graph())
+ sage: B = BipartiteGraph(N)
TESTS:
@@ -328,15 +331,16 @@ class BipartiteGraph(Graph):
Ensure that we can construct a ``BipartiteGraph`` with isolated vertices via
the reduced adjacency matrix (:trac:`10356`)::
- sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) # optional - sage.modules
- sage: a # optional - sage.modules
+ sage: # needs sage.modules
+ sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0]))
+ sage: a
Bipartite graph on 4 vertices
- sage: a.vertices(sort=True) # optional - sage.modules
+ sage: a.vertices(sort=True)
[0, 1, 2, 3]
- sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) # optional - sage.modules
- sage: g.vertices(sort=True) # optional - sage.modules
+ sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12))
+ sage: g.vertices(sort=True)
[0, 1, 2, 3, 4, 5, 6, 7]
- sage: sorted(g.left.union(g.right)) # optional - sage.modules
+ sage: sorted(g.left.union(g.right))
[0, 1, 2, 3, 4, 5, 6, 7]
Make sure that loops are not allowed (:trac:`23275`)::
@@ -1291,10 +1295,10 @@ def is_bipartite(self, certificate=False):
EXAMPLES::
- sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # optional - numpy
- sage: g.is_bipartite() # optional - numpy
+ sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # needs numpy
+ sage: g.is_bipartite() # needs numpy
True
- sage: g.is_bipartite(certificate=True) # random # optional - numpy
+ sage: g.is_bipartite(certificate=True) # random # needs numpy
(True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1})
TESTS::
@@ -1466,7 +1470,7 @@ def plot(self, *args, **kwds):
EXAMPLES::
sage: B = BipartiteGraph(graphs.CycleGraph(20))
- sage: B.plot() # optional - sage.plot
+ sage: B.plot() # needs sage.plot
Graphics object consisting of 41 graphics primitives
"""
if "pos" not in kwds:
@@ -1511,14 +1515,16 @@ def matching_polynomial(self, algorithm="Godsil", name=None):
sage: x = polygen(QQ)
sage: g = BipartiteGraph(graphs.CompleteBipartiteGraph(16, 16))
- sage: bool(factorial(16) * laguerre(16, x^2) == g.matching_polynomial(algorithm='rook')) # optional - sage.symbolic
+ sage: bool(factorial(16) * laguerre(16, x^2) # needs sage.symbolic
+ ....: == g.matching_polynomial(algorithm='rook'))
True
Compute the matching polynomial of a line with `60` vertices::
- sage: from sage.functions.orthogonal_polys import chebyshev_U # optional - sage.symbolic
+ sage: from sage.functions.orthogonal_polys import chebyshev_U # needs sage.symbolic
sage: g = next(graphs.trees(60))
- sage: chebyshev_U(60, x/2) == BipartiteGraph(g).matching_polynomial(algorithm='rook') # optional - sage.symbolic
+ sage: (chebyshev_U(60, x/2) # needs sage.symbolic
+ ....: == BipartiteGraph(g).matching_polynomial(algorithm='rook'))
True
The matching polynomial of a tree is equal to its characteristic
@@ -1627,7 +1633,7 @@ def perfect_matchings(self, labels=False):
sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(4, 4))
sage: len(list(B.perfect_matchings()))
24
- sage: B.matching_polynomial(algorithm='rook')(0) # optional - sage.modules
+ sage: B.matching_polynomial(algorithm='rook')(0) # needs sage.modules
24
TESTS::
@@ -1804,26 +1810,27 @@ def save_afile(self, fname):
EXAMPLES::
- sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules
+ sage: # needs sage.modules
+ sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
- sage: M # optional - sage.modules
+ sage: M
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
- sage: b = BipartiteGraph(M) # optional - sage.modules
- sage: import tempfile # optional - sage.modules
- sage: with tempfile.NamedTemporaryFile() as f: # optional - sage.modules
+ sage: b = BipartiteGraph(M)
+ sage: import tempfile
+ sage: with tempfile.NamedTemporaryFile() as f:
....: b.save_afile(f.name)
....: b2 = BipartiteGraph(f.name)
- sage: b.is_isomorphic(b2) # optional - sage.modules
+ sage: b.is_isomorphic(b2)
True
TESTS::
sage: import tempfile
sage: f = tempfile.NamedTemporaryFile()
- sage: for order in range(3, 13, 3): # optional - sage.combinat
+ sage: for order in range(3, 13, 3): # needs sage.combinat
....: num_chks = int(order / 3)
....: num_vars = order - num_chks
....: partition = (list(range(num_vars)), list(range(num_vars, num_vars+num_chks)))
@@ -1921,78 +1928,81 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds):
Bipartite graphs that are not weighted will return a matrix over ZZ,
unless a base ring is specified::
- sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules
+ sage: # needs sage.modules
+ sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
- sage: B = BipartiteGraph(M) # optional - sage.modules
- sage: N = B.reduced_adjacency_matrix() # optional - sage.modules
- sage: N # optional - sage.modules
+ sage: B = BipartiteGraph(M)
+ sage: N = B.reduced_adjacency_matrix(); N
[1 1 1 0 0 0 0]
[1 0 0 1 1 0 0]
[0 1 0 1 0 1 0]
[1 1 0 1 0 0 1]
- sage: N == M # optional - sage.modules
+ sage: N == M
True
- sage: N[0,0].parent() # optional - sage.modules
+ sage: N[0,0].parent()
Integer Ring
- sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 # optional - sage.modules
+ sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2
[1.0 1.0 1.0 0.0 0.0 0.0 0.0]
[1.0 0.0 0.0 1.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0 1.0 0.0]
[1.0 1.0 0.0 1.0 0.0 0.0 1.0]
- sage: N2[0, 0].parent() # optional - sage.modules
+ sage: N2[0, 0].parent()
Real Double Field
Multi-edge graphs also return a matrix over ZZ,
unless a base ring is specified::
- sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) # optional - sage.modules
- sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules
- sage: N = B.reduced_adjacency_matrix() # optional - sage.modules
- sage: N == M # optional - sage.modules
+ sage: # needs sage.modules
+ sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)])
+ sage: B = BipartiteGraph(M, multiedges=True, sparse=True)
+ sage: N = B.reduced_adjacency_matrix()
+ sage: N == M
True
- sage: N[0,0].parent() # optional - sage.modules
+ sage: N[0,0].parent()
Integer Ring
- sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules
- sage: N2[0, 0].parent() # optional - sage.modules
+ sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF)
+ sage: N2[0, 0].parent()
Real Double Field
Weighted graphs will return a matrix over the ring given by their
(first) weights, unless a base ring is specified::
- sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings
- sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings
- sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings
- sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings
- sage: N = B.reduced_adjacency_matrix(sparse=False) # optional - sage.modules sage.rings.finite_rings
- sage: N == M # optional - sage.modules sage.rings.finite_rings
+ sage: # needs sage.modules sage.rings.finite_rings
+ sage: F. = GF(4)
+ sage: MS = MatrixSpace(F, 2, 3)
+ sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]])
+ sage: B = BipartiteGraph(M, weighted=True, sparse=True)
+ sage: N = B.reduced_adjacency_matrix(sparse=False)
+ sage: N == M
True
- sage: N[0,0].parent() # optional - sage.modules sage.rings.finite_rings
+ sage: N[0,0].parent()
Finite Field in a of size 2^2
- sage: N2 = B.reduced_adjacency_matrix(base_ring=F) # optional - sage.modules sage.rings.finite_rings
- sage: N2[0, 0].parent() # optional - sage.modules sage.rings.finite_rings
+ sage: N2 = B.reduced_adjacency_matrix(base_ring=F)
+ sage: N2[0, 0].parent()
Finite Field in a of size 2^2
TESTS::
sage: B = BipartiteGraph()
- sage: B.reduced_adjacency_matrix() # optional - sage.modules
+ sage: B.reduced_adjacency_matrix() # needs sage.modules
[]
- sage: M = Matrix([[0,0], [0,0]]) # optional - sage.modules
- sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # optional - sage.modules
+ sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules
+ sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # needs sage.modules
True
- sage: M = Matrix([[10,2/3], [0,0]]) # optional - sage.modules
- sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules
- sage: M == B.reduced_adjacency_matrix() # optional - sage.modules
+ sage: M = Matrix([[10,2/3], [0,0]]) # needs sage.modules
+ sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules
+ sage: M == B.reduced_adjacency_matrix() # needs sage.modules
True
An error is raised if the specified base ring is not compatible with the
type of the weights of the bipartite graph::
- sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings
- sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings
- sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings
- sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings
- sage: B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules sage.rings.finite_rings
+ sage: # needs sage.modules sage.rings.finite_rings
+ sage: F. = GF(4)
+ sage: MS = MatrixSpace(F, 2, 3)
+ sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]])
+ sage: B = BipartiteGraph(M, weighted=True, sparse=True)
+ sage: B.reduced_adjacency_matrix(base_ring=RDF)
Traceback (most recent call last):
...
TypeError: float() argument must be a string or a ...number, not 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement'
@@ -2098,14 +2108,14 @@ class :class:`MixedIntegerLinearProgram
Maximum matching in a cycle graph::
sage: G = BipartiteGraph(graphs.CycleGraph(10))
- sage: G.matching() # optional - networkx
+ sage: G.matching() # needs networkx
[(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)]
The size of a maximum matching in a complete bipartite graph using
Eppstein::
sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5))
- sage: G.matching(algorithm="Eppstein", value_only=True)
+ sage: G.matching(algorithm="Eppstein", value_only=True) # needs networkx
4
TESTS:
@@ -2123,11 +2133,11 @@ class :class:`MixedIntegerLinearProgram
sage: G = graphs.CycleGraph(4)
sage: B = BipartiteGraph([(u,v,2) for u,v in G.edges(sort=True, labels=0)])
- sage: sorted(B.matching(use_edge_labels=True))
+ sage: sorted(B.matching(use_edge_labels=True)) # needs networkx
[(0, 3, 2), (1, 2, 2)]
- sage: B.matching(use_edge_labels=True, value_only=True) # optional - networkx
+ sage: B.matching(use_edge_labels=True, value_only=True) # needs networkx
4
- sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds')
+ sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') # needs networkx
4
sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP')
4
@@ -2139,11 +2149,13 @@ class :class:`MixedIntegerLinearProgram
Traceback (most recent call last):
...
ValueError: use_edge_labels cannot be used with "Hopcroft-Karp" or "Eppstein"
- sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Hopcroft-Karp') # optional - networkx
+ sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx
+ ....: algorithm='Hopcroft-Karp')
2
- sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Eppstein') # optional - networkx
+ sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx
+ ....: algorithm='Eppstein')
2
- sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds')
+ sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') # needs networkx
2
sage: B.matching(use_edge_labels=False, value_only=True, algorithm='LP')
2
@@ -2154,23 +2166,23 @@ class :class:`MixedIntegerLinearProgram
sage: for e in G.edges(sort=True):
....: G.set_edge_label(e[0], e[1], int(e[0]) + int(e[1]))
sage: G.allow_multiple_edges(True)
- sage: G.matching(use_edge_labels=True, value_only=True)
+ sage: G.matching(use_edge_labels=True, value_only=True) # needs networkx
444
Empty bipartite graph and bipartite graphs without edges::
sage: B = BipartiteGraph()
sage: algorithms = ["Hopcroft-Karp", "Eppstein", "Edmonds", "LP"]
- sage: not any(B.matching(algorithm=algo) for algo in algorithms)
+ sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx
True
- sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms)
+ sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx
True
sage: B.add_vertex(1, left=True)
sage: B.add_vertex(2, left=True)
sage: B.add_vertex(3, right=True)
- sage: not any(B.matching(algorithm=algo) for algo in algorithms)
+ sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx
True
- sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms)
+ sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx
True
"""
if algorithm is None:
@@ -2285,13 +2297,14 @@ def vertex_cover(self, algorithm="Konig", value_only=False,
On the Cycle Graph::
sage: B = BipartiteGraph(graphs.CycleGraph(6))
- sage: len(B.vertex_cover()) # optional - networkx
+ sage: len(B.vertex_cover()) # needs networkx
3
- sage: B.vertex_cover(value_only=True) # optional - networkx
+ sage: B.vertex_cover(value_only=True) # needs networkx
3
The two algorithms should return the same result::
+ sage: # needs numpy
sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5))
sage: vc1 = g.vertex_cover(algorithm="Konig")
sage: vc2 = g.vertex_cover(algorithm="Cliquer")
@@ -2303,7 +2316,7 @@ def vertex_cover(self, algorithm="Konig", value_only=False,
Giving a non connected bipartite graph::
sage: B = BipartiteGraph(graphs.CycleGraph(4) * 2)
- sage: len(B.vertex_cover())
+ sage: len(B.vertex_cover()) # needs networkx
4
Empty bipartite graph and bipartite graphs without edges::
diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx
index d8c50f220e3..5911778953c 100644
--- a/src/sage/graphs/bliss.pyx
+++ b/src/sage/graphs/bliss.pyx
@@ -437,12 +437,13 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True
sage: g.is_isomorphic(canonical_form(g, return_graph=True)) # optional - bliss
True
- sage: g1 = graphs.RandomGNP(100, .4) # optional - bliss
- sage: r = Permutations(range(100)).random_element() # optional - bliss
- sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) # optional - bliss
- sage: g1 = canonical_form(g1, return_graph=True) # optional - bliss
- sage: g2 = canonical_form(g2, return_graph=True) # optional - bliss
- sage: g2 == g2 # optional - bliss
+ sage: # optional - bliss
+ sage: g1 = graphs.RandomGNP(100, .4)
+ sage: r = Permutations(range(100)).random_element()
+ sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)])
+ sage: g1 = canonical_form(g1, return_graph=True)
+ sage: g2 = canonical_form(g2, return_graph=True)
+ sage: g2 == g2
True
sage: g = Graph({1: [2]})
@@ -476,11 +477,12 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True
Check that it works with non hashable non sortable edge labels (relying
on string representations of the labels)::
- sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) # optional - sage.modules
- sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) # optional - sage.modules
- sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss sage.modules
- sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss sage.modules
- sage: g1can == g2can # optional - bliss sage.modules
+ sage: # needs sage.modules
+ sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')])
+ sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')])
+ sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss
+ sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss
+ sage: g1can == g2can # optional - bliss
True
Check that :trac:`32395` is fixed::
@@ -677,11 +679,12 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True):
Computing the automorphism group of a graph or digraph::
- sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) # optional - bliss
- sage: automorphism_group(G).cardinality() # optional - bliss
+ sage: # optional - bliss
+ sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2])
+ sage: automorphism_group(G).cardinality()
12
- sage: D = DiGraph(G.edges(sort=True)) # optional - bliss
- sage: automorphism_group(D).cardinality() # optional - bliss
+ sage: D = DiGraph(G.edges(sort=True))
+ sage: automorphism_group(D).cardinality()
2
Observe that the order 12 is given by permuting the first three vertices, or the last two
@@ -690,12 +693,13 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True):
Partitioning the vertices into classes::
- sage: G = graphs.CompleteMultipartiteGraph([3, 2]) # optional - bliss
- sage: automorphism_group(G).cardinality() # optional - bliss
+ sage: # optional - bliss
+ sage: G = graphs.CompleteMultipartiteGraph([3, 2])
+ sage: automorphism_group(G).cardinality()
12
- sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() # optional - bliss
+ sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality()
2
- sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() # optional - bliss
+ sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality()
4
sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() # optional - bliss
@@ -724,10 +728,11 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True):
sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss
True
- sage: G = graphs.HeawoodGraph() # optional - bliss
- sage: p = G.bipartite_sets() # optional - bliss
- sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss
- sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss
+ sage: # optional - bliss
+ sage: G = graphs.HeawoodGraph()
+ sage: p = G.bipartite_sets()
+ sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])])
+ sage: automorphism_group(G, partition=p).is_isomorphic(A)
True
sage: G = graphs.CompleteMultipartiteGraph([5,7,11])
@@ -735,55 +740,59 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True):
sage: B.cardinality() == prod(factorial(n) for n in [5,7,11]) # optional - bliss
True
- sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True)# optional - bliss
- sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss
+ sage: # optional - bliss
+ sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True)
+ sage: for i,j in G.edges(labels=False, sort=False):
....: if 0 <= i < 3:
....: G.set_edge_label(i, j, "A")
....: if 3 <= i < 6:
....: G.set_edge_label(i, j, "B")
....: if 6 <= i < 8:
....: G.set_edge_label(i, j, "C")
- sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] ) # optional - bliss
+ sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] )
True
- sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] ) # optional - bliss
+ sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] )
True
- sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] ) # optional - bliss
+ sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] )
True
- sage: G = Graph() # optional - bliss
- sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) # optional - bliss
- sage: A = automorphism_group(G) # optional - bliss
- sage: print(A.gens()) # random, optional - bliss
+ sage: # optional - bliss
+ sage: G = Graph()
+ sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20))
+ sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20))
+ sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20))
+ sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20))
+ sage: A = automorphism_group(G)
+ sage: print(A.gens()) # random
[(9,13), (18,19), (17,18), (16,17), (15,16), (14,15), (12,9), (11,12),
(10,11), (7,8), (6,7), (5,6), (3,4), (2,3), (0,1)]
- sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss
+ sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6])
True
sage: alpha = "abcdefghijklmnopqrstuvwxyz"
- sage: G = Graph() # optional - bliss
- sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss
- sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) # optional - bliss
- sage: A = automorphism_group(G) # optional - bliss
- sage: print(A.gens()) # random, optional - bliss
+ sage: # optional - bliss
+ sage: G = Graph()
+ sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20))
+ sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20))
+ sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20))
+ sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20))
+ sage: A = automorphism_group(G)
+ sage: print(A.gens())
[('r','t'), ('s','r'), ('p','s'), ('q','p'), ('o','q'), ('l','n'),
('m','l'), ('j','m'), ('k','j'), ('i','h'), ('f','i'), ('g','f'),
('e','d'), ('c','e'), ('a','b')]
- sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss
+ sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6])
True
- sage: gg = graphs.CompleteGraph(5) # optional - bliss
- sage: gg.allow_loops(True) # optional - bliss
- sage: gg.add_edge(0,0) # optional - bliss
- sage: gg.add_edge(1,1) # optional - bliss
- sage: automorphism_group(gg).cardinality() # optional - bliss
+ sage: # optional - bliss
+ sage: gg = graphs.CompleteGraph(5)
+ sage: gg.allow_loops(True)
+ sage: gg.add_edge(0,0)
+ sage: gg.add_edge(1,1)
+ sage: automorphism_group(gg).cardinality()
12
- sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() # optional - bliss
+ sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality()
6
"""
# We need this to convert the numbers from to
diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx
index 9de214115f9..0f6e83565ee 100755
--- a/src/sage/graphs/centrality.pyx
+++ b/src/sage/graphs/centrality.pyx
@@ -99,11 +99,12 @@ def centrality_betweenness(G, bint exact=False, bint normalize=True):
Compare with NetworkX::
- sage: import networkx # optional - networkx
- sage: g = graphs.RandomGNP(100, .2) # optional - networkx
- sage: nw = networkx.betweenness_centrality(g.networkx_graph()) # optional - networkx
- sage: sg = centrality_betweenness(g) # optional - networkx
- sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: g = graphs.RandomGNP(100, .2)
+ sage: nw = networkx.betweenness_centrality(g.networkx_graph())
+ sage: sg = centrality_betweenness(g)
+ sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10
0
Stupid cases::
@@ -637,34 +638,36 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0):
The result is correct::
+ sage: # needs networkx
sage: from sage.graphs.centrality import centrality_closeness_top_k
sage: import random
sage: n = 20
sage: m = random.randint(1, n * (n - 1) / 2)
sage: k = random.randint(1, n)
- sage: g = graphs.RandomGNM(n, m) # optional - networkx
- sage: topk = centrality_closeness_top_k(g, k) # optional - networkx
- sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx
- sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx
- sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx
+ sage: g = graphs.RandomGNM(n, m)
+ sage: topk = centrality_closeness_top_k(g, k)
+ sage: centr = g.centrality_closeness(algorithm='BFS')
+ sage: sorted_centr = sorted(centr.values(), reverse=True)
+ sage: len(topk) == min(k, len(sorted_centr))
True
- sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx
+ sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk)))
True
Directed case::
+ sage: # needs networkx
sage: from sage.graphs.centrality import centrality_closeness_top_k
sage: import random
sage: n = 20
sage: m = random.randint(1, n * (n - 1))
sage: k = random.randint(1, n)
- sage: g = digraphs.RandomDirectedGNM(n, m) # optional - networkx
- sage: topk = centrality_closeness_top_k(g, k) # optional - networkx
- sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx
- sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx
- sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx
+ sage: g = digraphs.RandomDirectedGNM(n, m)
+ sage: topk = centrality_closeness_top_k(g, k)
+ sage: centr = g.centrality_closeness(algorithm='BFS')
+ sage: sorted_centr = sorted(centr.values(), reverse=True)
+ sage: len(topk) == min(k, len(sorted_centr))
True
- sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx
+ sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk)))
True
"""
cdef list res
diff --git a/src/sage/graphs/cliquer.pyx b/src/sage/graphs/cliquer.pyx
index 9ff02b8572e..6f232d97e16 100644
--- a/src/sage/graphs/cliquer.pyx
+++ b/src/sage/graphs/cliquer.pyx
@@ -115,7 +115,7 @@ def all_max_clique(graph):
[2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],
[5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
+ sage: G.show(figsize=[2,2]) # needs sage.plot
sage: G.cliques_maximum()
[[0, 1, 2], [0, 1, 3]]
sage: C = graphs.PetersenGraph()
@@ -302,7 +302,7 @@ def clique_number(graph):
sage: C.clique_number()
4
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
+ sage: G.show(figsize=[2,2]) # needs sage.plot
sage: G.clique_number()
3
diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx
index b694b552ee8..119cd892265 100644
--- a/src/sage/graphs/comparability.pyx
+++ b/src/sage/graphs/comparability.pyx
@@ -417,20 +417,20 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0):
The 5-cycle or the Petersen Graph are not transitively orientable::
sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability
- sage: is_comparability(graphs.CycleGraph(5), certificate = True)
+ sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip
(False, None)
sage: g = graphs.PetersenGraph()
- sage: is_comparability(g, certificate = True)
+ sage: is_comparability(g, certificate=True) # needs sage.numerical.mip
(False, None)
But the Bull graph is::
sage: g = graphs.BullGraph()
- sage: is_comparability(g)
+ sage: is_comparability(g) # needs sage.numerical.mip
True
- sage: is_comparability(g, certificate = True)
+ sage: is_comparability(g, certificate=True) # needs sage.numerical.mip
(True, Digraph on 5 vertices)
- sage: is_comparability(g, certificate = True)[1].is_transitive()
+ sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip
True
"""
from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
@@ -642,7 +642,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True,
sage: p1 = Permutation([nn+1 for nn in perm[0]])
sage: p2 = Permutation([nn+1 for nn in perm[1]])
sage: p = p2 * p1.inverse()
- sage: p.show(representation="braid") # optional - sage.plot
+ sage: p.show(representation="braid") # needs sage.plot
TESTS:
@@ -664,7 +664,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True,
Then with MILP::
sage: from sage.graphs.comparability import is_permutation
- sage: for i in range(20):
+ sage: for i in range(20): # needs sage.numerical.mip
....: p = Permutations(10).random_element()
....: g1 = graphs.PermutationGraph(p)
....: isit, certif = is_permutation(g1, algorithm="MILP", certificate=True)
@@ -745,15 +745,15 @@ def is_transitive(g, certificate=False):
(0, 2)
sage: digraphs.RandomDirectedGNP(30,.2).is_transitive()
False
- sage: D = digraphs.DeBruijn(5, 2) # optional - sage.combinat
- sage: D.is_transitive() # optional - sage.combinat
+ sage: D = digraphs.DeBruijn(5, 2) # needs sage.combinat
+ sage: D.is_transitive() # needs sage.combinat
False
- sage: cert = D.is_transitive(certificate=True) # optional - sage.combinat
- sage: D.has_edge(*cert) # optional - sage.combinat
+ sage: cert = D.is_transitive(certificate=True) # needs sage.combinat
+ sage: D.has_edge(*cert) # needs sage.combinat
False
- sage: bool(D.shortest_path(*cert)) # optional - sage.combinat
+ sage: bool(D.shortest_path(*cert)) # needs sage.combinat
True
- sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # optional - networkx
+ sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # needs networkx
True
"""
cdef int n = g.order()
diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx
index c2100141f30..ff0cabb8f37 100644
--- a/src/sage/graphs/connectivity.pyx
+++ b/src/sage/graphs/connectivity.pyx
@@ -258,12 +258,12 @@ def connected_components_subgraphs(G):
sage: from sage.graphs.connectivity import connected_components_subgraphs
sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]})
sage: L = connected_components_subgraphs(G)
- sage: graphs_list.show_graphs(L) # optional - sage.plot
+ sage: graphs_list.show_graphs(L) # needs sage.plot
sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]})
sage: L = connected_components_subgraphs(D)
- sage: graphs_list.show_graphs(L) # optional - sage.plot
+ sage: graphs_list.show_graphs(L) # needs sage.plot
sage: L = D.connected_components_subgraphs()
- sage: graphs_list.show_graphs(L) # optional - sage.plot
+ sage: graphs_list.show_graphs(L) # needs sage.plot
TESTS:
@@ -1361,25 +1361,25 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver
A basic application on a ``PappusGraph``::
sage: from sage.graphs.connectivity import vertex_connectivity
- sage: g=graphs.PappusGraph()
- sage: vertex_connectivity(g)
+ sage: g = graphs.PappusGraph()
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
3
- sage: g.vertex_connectivity()
+ sage: g.vertex_connectivity() # needs sage.numerical.mip
3
In a grid, the vertex connectivity is equal to the minimum degree, in which
case one of the two sets is of cardinality `1`::
sage: g = graphs.GridGraph([ 3,3 ])
- sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
- sage: len(setA) == 1 or len(setB) == 1
+ sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) # needs sage.numerical.mip
+ sage: len(setA) == 1 or len(setB) == 1 # needs sage.numerical.mip
True
A vertex cut in a tree is any internal vertex::
sage: tree = graphs.RandomTree(15)
- sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False)
- sage: tree.degree(cut_vertex) > 1
+ sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) # needs sage.numerical.mip
+ sage: tree.degree(cut_vertex) > 1 # needs sage.numerical.mip
True
When ``value_only = True``, this function is optimized for small
@@ -1388,41 +1388,41 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver
It is the case for connected graphs which are not connected::
sage: g = 2 * graphs.PetersenGraph()
- sage: vertex_connectivity(g)
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
0
Or if they are just 1-connected::
sage: g = graphs.PathGraph(10)
- sage: vertex_connectivity(g)
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
1
For directed graphs, the strong connectivity is tested through the dedicated
function::
sage: g = digraphs.ButterflyGraph(3)
- sage: vertex_connectivity(g)
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
0
A complete graph on `10` vertices is `9`-connected::
sage: g = graphs.CompleteGraph(10)
- sage: vertex_connectivity(g)
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
9
A complete digraph on `10` vertices is `9`-connected::
sage: g = DiGraph(graphs.CompleteGraph(10))
- sage: vertex_connectivity(g)
+ sage: vertex_connectivity(g) # needs sage.numerical.mip
9
When parameter ``k`` is set, we only check for the existence of a vertex cut
of order at least ``k``::
sage: g = graphs.PappusGraph()
- sage: vertex_connectivity(g, k=3)
+ sage: vertex_connectivity(g, k=3) # needs sage.numerical.mip
True
- sage: vertex_connectivity(g, k=4)
+ sage: vertex_connectivity(g, k=4) # needs sage.numerical.mip
False
TESTS:
@@ -1441,13 +1441,13 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver
sage: from sage.graphs.connectivity import is_strongly_connected
sage: from sage.graphs.connectivity import is_connected
sage: empty = Graph()
- sage: vertex_connectivity(empty)
+ sage: vertex_connectivity(empty) # needs sage.numerical.mip
0
- sage: vertex_connectivity(empty, k=1) == is_connected(empty)
+ sage: vertex_connectivity(empty, k=1) == is_connected(empty) # needs sage.numerical.mip
True
- sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected()
+ sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() # needs sage.numerical.mip
True
- sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph())
+ sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) # needs sage.numerical.mip
True
If ``G`` is not a Sage (Di)Graph, an error is raised::
@@ -1460,16 +1460,16 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver
Complete Graph with loops or multiple edges (:trac:`25589`)::
sage: G = Graph([(0, 1), (0, 1)], multiedges=True)
- sage: G.vertex_connectivity()
+ sage: G.vertex_connectivity() # needs sage.numerical.mip
1
sage: G = graphs.CompleteGraph(4)
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
- sage: G.vertex_connectivity(value_only=False, verbose=1)
+ sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip
(3, [])
sage: G.allow_multiple_edges(True)
sage: G.add_edge(0, 1)
- sage: G.vertex_connectivity(value_only=False, verbose=1)
+ sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip
(3, [])
"""
from sage.graphs.generic_graph import GenericGraph
@@ -2379,21 +2379,21 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0,
sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan")
sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
- sage: T2 = spqr_tree(G, algorithm='cleave')
- sage: G.is_isomorphic(spqr_tree_to_graph(T2))
+ sage: T2 = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip
+ sage: G.is_isomorphic(spqr_tree_to_graph(T2)) # needs sage.numerical.mip
True
sage: G = Graph([(0, 1)], multiedges=True)
- sage: T = spqr_tree(G, algorithm='cleave')
- sage: T.vertices(sort=True)
+ sage: T = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip
+ sage: T.vertices(sort=True) # needs sage.numerical.mip
[('Q', Multi-graph on 2 vertices)]
- sage: G.is_isomorphic(spqr_tree_to_graph(T))
+ sage: G.is_isomorphic(spqr_tree_to_graph(T)) # needs sage.numerical.mip
True
sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan')
sage: T.vertices(sort=True)
[('Q', Multi-graph on 2 vertices)]
sage: G.add_edge(0, 1)
- sage: spqr_tree(G, algorithm='cleave').vertices(sort=True)
+ sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) # needs sage.numerical.mip
[('P', Multi-graph on 2 vertices)]
sage: from collections import Counter
@@ -2401,24 +2401,24 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0,
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
- sage: T = G.spqr_tree(algorithm="cleave")
- sage: Counter(u[0] for u in T)
+ sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip
+ sage: Counter(u[0] for u in T) # needs sage.numerical.mip
Counter({'R': 1})
sage: for u,v in list(G.edges(labels=False, sort=False)):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: sorted(Counter(u[0] for u in T).items())
[('P', 15), ('R', 1), ('S', 15)]
- sage: T = G.spqr_tree(algorithm="cleave")
- sage: sorted(Counter(u[0] for u in T).items())
+ sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip
+ sage: sorted(Counter(u[0] for u in T).items()) # needs sage.numerical.mip
[('P', 15), ('R', 1), ('S', 15)]
sage: for u,v in list(G.edges(labels=False, sort=False)):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: sorted(Counter(u[0] for u in T).items())
[('P', 60), ('R', 1), ('S', 75)]
- sage: T = G.spqr_tree(algorithm="cleave") # long time
- sage: sorted(Counter(u[0] for u in T).items()) # long time
+ sage: T = G.spqr_tree(algorithm="cleave") # long time # needs sage.numerical.mip
+ sage: sorted(Counter(u[0] for u in T).items()) # long time # needs sage.numerical.mip
[('P', 60), ('R', 1), ('S', 75)]
TESTS::
@@ -2814,7 +2814,7 @@ cdef class _Component:
....: 'comp.add_edge(3)',
....: 'comp.finish_tric_or_poly(4)',
....: 'print(comp)']
- sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
Polygon: 2 3 4
"""
self.mem = MemoryAllocator()
@@ -2861,7 +2861,7 @@ cdef class _Component:
....: 'comp.add_edge(3)',
....: 'comp.finish_tric_or_poly(4)',
....: 'print(comp)']
- sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
Polygon: 2 3 4
"""
if self.component_type == 0:
@@ -4344,8 +4344,8 @@ def is_triconnected(G):
Comparing different methods on random graphs that are not always
triconnected::
- sage: G = graphs.RandomBarabasiAlbert(50, 3) # optional - networkx
- sage: G.is_triconnected() == G.vertex_connectivity(k=3) # optional - networkx
+ sage: G = graphs.RandomBarabasiAlbert(50, 3) # needs networkx
+ sage: G.is_triconnected() == G.vertex_connectivity(k=3) # needs networkx
True
.. SEEALSO::
diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py
index b1d046ee25d..1017f8490eb 100644
--- a/src/sage/graphs/digraph.py
+++ b/src/sage/graphs/digraph.py
@@ -357,7 +357,7 @@ class DiGraph(GenericGraph):
sage: g = DiGraph([[1..12], lambda i,j: i != j and i.divides(j)])
sage: g.vertices(sort=True)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
- sage: g.adjacency_matrix() # optional - sage.modules
+ sage: g.adjacency_matrix() # needs sage.modules
[0 1 1 1 1 1 1 1 1 1 1 1]
[0 0 0 1 0 1 0 1 0 1 0 1]
[0 0 0 0 0 1 0 0 1 0 0 1]
@@ -377,28 +377,28 @@ class DiGraph(GenericGraph):
- an adjacency matrix::
- sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # optional - sage.modules
+ sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # needs sage.modules
....: [0, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]); M
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 1]
[0 0 0 0 0]
[0 0 0 0 0]
- sage: DiGraph(M) # optional - sage.modules
+ sage: DiGraph(M) # needs sage.modules
Digraph on 5 vertices
- sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # optional - sage.modules
+ sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # needs sage.modules
[ 0 1 -1]
[ -1 0 -1/2]
[ 1 1/2 0]
- sage: G = DiGraph(M, sparse=True, weighted=True); G # optional - sage.modules
+ sage: G = DiGraph(M, sparse=True, weighted=True); G # needs sage.modules
Digraph on 3 vertices
- sage: G.weighted() # optional - sage.modules
+ sage: G.weighted() # needs sage.modules
True
- an incidence matrix::
- sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # optional - sage.modules
+ sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules
....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M
[-1 0 0 0 1]
[ 1 -1 0 0 0]
@@ -406,7 +406,7 @@ class DiGraph(GenericGraph):
[ 0 0 1 -1 0]
[ 0 0 0 1 -1]
[ 0 0 0 0 0]
- sage: DiGraph(M) # optional - sage.modules
+ sage: DiGraph(M) # needs sage.modules
Digraph on 6 vertices
#. A ``dig6`` string: Sage automatically recognizes whether a string is in
@@ -429,17 +429,17 @@ class DiGraph(GenericGraph):
#. A NetworkX MultiDiGraph::
- sage: import networkx # optional - networkx
- sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx
- sage: DiGraph(g) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx
+ sage: DiGraph(g) # needs networkx
Multi-digraph on 5 vertices
#. A NetworkX digraph::
- sage: import networkx # optional - networkx
- sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx
- sage: DiGraph(g) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx
+ sage: DiGraph(g) # needs networkx
Digraph on 5 vertices
#. An igraph directed Graph (see also
@@ -453,11 +453,12 @@ class DiGraph(GenericGraph):
If ``vertex_labels`` is ``True``, the names of the vertices are given by
the vertex attribute ``'name'``, if available::
- sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) # optional - python_igraph
- sage: DiGraph(g).vertices(sort=True) # optional - python_igraph
+ sage: # optional - python_igraph
+ sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']})
+ sage: DiGraph(g).vertices(sort=True)
['a', 'b', 'c']
- sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) # optional - python_igraph
- sage: DiGraph(g).vertices(sort=True) # optional - python_igraph
+ sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']})
+ sage: DiGraph(g).vertices(sort=True)
[0, 1, 2]
If the igraph Graph has edge attributes, they are used as edge labels::
@@ -479,18 +480,19 @@ class DiGraph(GenericGraph):
Demonstrate that digraphs using the static backend are equal to mutable
graphs but can be used as dictionary keys::
- sage: import networkx # optional - networkx
- sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) # optional - networkx
- sage: G = DiGraph(g) # optional - networkx
- sage: G_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx
- sage: H_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx
- sage: H_imm is G_imm # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]})
+ sage: G = DiGraph(g)
+ sage: G_imm = DiGraph(G, data_structure="static_sparse")
+ sage: H_imm = DiGraph(G, data_structure="static_sparse")
+ sage: H_imm is G_imm
False
- sage: H_imm == G_imm == G # optional - networkx
+ sage: H_imm == G_imm == G
True
- sage: {G_imm:1}[H_imm] # optional - networkx
+ sage: {G_imm:1}[H_imm]
1
- sage: {G_imm:1}[G] # optional - networkx
+ sage: {G_imm:1}[G]
Traceback (most recent call last):
...
TypeError: This graph is mutable, and thus not hashable. Create an
@@ -500,10 +502,10 @@ class DiGraph(GenericGraph):
specifying the ``immutable`` optional argument (not only by
``data_structure='static_sparse'`` as above)::
- sage: J_imm = DiGraph(G, immutable=True) # optional - networkx
- sage: J_imm == G_imm # optional - networkx
+ sage: J_imm = DiGraph(G, immutable=True) # needs networkx
+ sage: J_imm == G_imm # needs networkx
True
- sage: type(J_imm._backend) == type(G_imm._backend) # optional - networkx
+ sage: type(J_imm._backend) == type(G_imm._backend) # needs networkx
True
From a list of vertices and a list of edges::
@@ -515,7 +517,7 @@ class DiGraph(GenericGraph):
Check that :trac:`27505` is fixed::
- sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # optional - networkx
+ sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # needs networkx
Digraph on 0 vertices
"""
_directed = True
@@ -532,12 +534,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
sage: loads(dumps(D)) == D
True
- sage: a = matrix(2,2,[1,2,0,1]) # optional - sage.modules
- sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules
+ sage: a = matrix(2,2,[1,2,0,1]) # needs sage.modules
+ sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules
True
- sage: a = matrix(2,2,[3,2,0,1]) # optional - sage.modules
- sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules
+ sage: a = matrix(2,2,[3,2,0,1]) # needs sage.modules
+ sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules
True
The positions are copied when the DiGraph is built from another DiGraph
@@ -580,9 +582,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},
....: 3:{5:4},4:{5:1,6:5},5:{4:1,6:7,5:1}}
sage: grafo3 = DiGraph(B, weighted=True)
- sage: matad = grafo3.weighted_adjacency_matrix() # optional - sage.modules
- sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # optional - sage.modules
- sage: grafo4.shortest_path(0, 6, by_weight=True) # optional - sage.modules
+ sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules
+ sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules
+ sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules
[0, 1, 2, 5, 4, 6]
Building a DiGraph with ``immutable=False`` returns a mutable graph::
@@ -954,7 +956,7 @@ def is_directed_acyclic(self, certificate=False):
At first, the following graph is acyclic::
sage: D = DiGraph({0:[1, 2, 3], 4:[2, 5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10]})
- sage: D.plot(layout='circular').show() # optional - sage.plot
+ sage: D.plot(layout='circular').show() # needs sage.plot
sage: D.is_directed_acyclic()
True
@@ -1457,12 +1459,12 @@ def degree_polynomial(self):
EXAMPLES::
- sage: G = posets.PentagonPoset().hasse_diagram() # optional - sage.matrix
- sage: G.degree_polynomial() # optional - sage.matrix
+ sage: G = posets.PentagonPoset().hasse_diagram() # needs sage.modules
+ sage: G.degree_polynomial() # needs sage.modules
x^2 + 3*x*y + y^2
sage: G = posets.BooleanLattice(4).hasse_diagram()
- sage: G.degree_polynomial().factor()
+ sage: G.degree_polynomial().factor() # needs sage.libs.pari
(x + y)^4
"""
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
@@ -1563,7 +1565,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False,
sage: dcycle=DiGraph(cycle)
sage: cycle.size()
5
- sage: dcycle.feedback_edge_set(value_only=True)
+ sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip
5
And in this situation, for any edge `uv` of the first graph, `uv` of
@@ -1573,9 +1575,9 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False,
sage: while not g.num_edges():
....: g = graphs.RandomGNP(5,.3)
sage: dg = DiGraph(g)
- sage: feedback = dg.feedback_edge_set()
+ sage: feedback = dg.feedback_edge_set() # needs sage.numerical.mip
sage: u,v,l = next(g.edge_iterator())
- sage: (u,v) in feedback or (v,u) in feedback
+ sage: (u,v) in feedback or (v,u) in feedback # needs sage.numerical.mip
True
TESTS:
@@ -1583,7 +1585,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False,
Comparing with/without constraint generation. Also double-checks issue
:trac:`12833`::
- sage: for i in range(20):
+ sage: for i in range(20): # needs sage.numerical.mip
....: g = digraphs.RandomDirectedGNP(10, .3)
....: x = g.feedback_edge_set(value_only=True)
....: y = g.feedback_edge_set(value_only=True,
@@ -1594,34 +1596,37 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False,
Loops are part of the feedback edge set (:trac:`23989`)::
+ sage: # needs sage.combinat
sage: D = digraphs.DeBruijn(2, 2)
sage: sorted(D.loops(labels=None))
[('00', '00'), ('11', '11')]
- sage: FAS = D.feedback_edge_set(value_only=False)
- sage: all(l in FAS for l in D.loops(labels=None))
+ sage: FAS = D.feedback_edge_set(value_only=False) # needs sage.numerical.mip
+ sage: all(l in FAS for l in D.loops(labels=None)) # needs sage.numerical.mip
True
- sage: FAS2 = D.feedback_edge_set(value_only=False, constraint_generation=False)
- sage: len(FAS) == len(FAS2)
+ sage: FAS2 = D.feedback_edge_set(value_only=False, # needs sage.numerical.mip
+ ....: constraint_generation=False)
+ sage: len(FAS) == len(FAS2) # needs sage.numerical.mip
True
Check that multi-edges are properly taken into account::
sage: cycle = graphs.CycleGraph(5)
sage: dcycle = DiGraph(cycle)
- sage: dcycle.feedback_edge_set(value_only=True)
+ sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip
5
sage: dcycle.allow_multiple_edges(True)
sage: dcycle.add_edges(dcycle.edges(sort=True))
- sage: dcycle.feedback_edge_set(value_only=True)
+ sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip
10
- sage: dcycle.feedback_edge_set(value_only=True, constraint_generation=False)
+ sage: dcycle.feedback_edge_set(value_only=True, # needs sage.numerical.mip
+ ....: constraint_generation=False)
10
Strongly connected components are well handled (:trac:`23989`)::
sage: g = digraphs.Circuit(3) * 2
sage: g.add_edge(0, 3)
- sage: g.feedback_edge_set(value_only=True)
+ sage: g.feedback_edge_set(value_only=True) # needs sage.numerical.mip
2
"""
# It would be a pity to start a LP if the digraph is already acyclic
@@ -2071,10 +2076,10 @@ def reverse_edges(self, edges, inplace=True, multiedges=None):
[(0, 5, None), (1, 0, None), (2, 1, None),
(3, 2, None), (4, 3, None), (5, 4, None)]
- sage: D = digraphs.Kautz(2, 3) # optional - sage.combinat
- sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # optional - sage.combinat
+ sage: D = digraphs.Kautz(2, 3) # needs sage.combinat
+ sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # needs sage.combinat
....: multiedges=True)
- sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # optional - sage.combinat
+ sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # needs sage.combinat
True
"""
tempG = self if inplace else copy(self)
@@ -2181,7 +2186,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None,
[2, 2, 2]
sage: G.eccentricity(algorithm='Floyd-Warshall-Cython')
[2, 2, 2]
- sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # optional - networkx
+ sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx
[5, 5, 4]
sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_Boost')
[5, 5, 4]
@@ -2446,11 +2451,12 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None,
EXAMPLES::
- sage: G = digraphs.DeBruijn(5,4) # optional - sage.combinat
- sage: G.diameter() # optional - sage.combinat
+ sage: # needs sage.combinat
+ sage: G = digraphs.DeBruijn(5,4)
+ sage: G.diameter()
4
- sage: G = digraphs.GeneralizedDeBruijn(9, 3) # optional - sage.combinat
- sage: G.diameter() # optional - sage.combinat
+ sage: G = digraphs.GeneralizedDeBruijn(9, 3)
+ sage: G.diameter()
2
TESTS::
@@ -3144,7 +3150,7 @@ def topological_sort(self, implementation="default"):
sage: D = DiGraph({0: [1, 2, 3], 4: [2, 5], 1: [8], 2: [7], 3: [7],
....: 5: [6, 7], 7: [8], 6: [9], 8: [10], 9: [10]})
- sage: D.plot(layout='circular').show() # optional - sage.plot
+ sage: D.plot(layout='circular').show() # needs sage.plot
sage: D.topological_sort()
[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]
@@ -3156,9 +3162,9 @@ def topological_sort(self, implementation="default"):
Using the NetworkX implementation ::
- sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # optional - networkx
+ sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # needs networkx
[0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10]
- sage: all(s.index(u) < s.index(v) # optional - networkx
+ sage: all(s.index(u) < s.index(v) # needs networkx
....: for u, v in D.edges(sort=False, labels=False))
True
@@ -3225,14 +3231,14 @@ def topological_sort_generator(self):
EXAMPLES::
sage: D = DiGraph({0: [1, 2], 1: [3], 2: [3, 4]})
- sage: D.plot(layout='circular').show() # optional - sage.plot
- sage: list(D.topological_sort_generator()) # optional - sage.modules sage.rings.finite_rings
+ sage: D.plot(layout='circular').show() # needs sage.plot
+ sage: list(D.topological_sort_generator()) # needs sage.modules sage.rings.finite_rings
[[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3],
[0, 2, 4, 1, 3], [0, 1, 2, 4, 3]]
::
- sage: for sort in D.topological_sort_generator():
+ sage: for sort in D.topological_sort_generator(): # needs sage.modules sage.rings.finite_rings
....: for u, v in D.edge_iterator(labels=False):
....: if sort.index(u) > sort.index(v):
....: print("this should never happen")
@@ -3592,7 +3598,7 @@ def flow_polytope(self, edges=None, ends=None, backend=None):
Flow polytopes can also be built through the ``polytopes.``
object::
- sage: polytopes.flow_polytope(digraphs.Path(5)) # optional - sage.geometry.polyhedron
+ sage: polytopes.flow_polytope(digraphs.Path(5)) # needs sage.geometry.polyhedron
A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex
EXAMPLES:
@@ -3600,26 +3606,26 @@ def flow_polytope(self, edges=None, ends=None, backend=None):
A commutative square::
sage: G = DiGraph({1: [2, 3], 2: [4], 3: [4]})
- sage: fl = G.flow_polytope(); fl # optional - sage.geometry.polyhedron
+ sage: fl = G.flow_polytope(); fl # needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hull
of 2 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices() # needs sage.geometry.polyhedron
(A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0))
Using a different order for the edges of the graph::
- sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl # optional - sage.geometry.polyhedron
+ sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl # needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices() # needs sage.geometry.polyhedron
(A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1))
A tournament on 4 vertices::
sage: H = digraphs.TransitiveTournament(4)
- sage: fl = H.flow_polytope(); fl # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(); fl # needs sage.geometry.polyhedron
A 3-dimensional polyhedron in QQ^6 defined as the convex hull
of 4 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices() # needs sage.geometry.polyhedron
(A vertex at (0, 0, 1, 0, 0, 0),
A vertex at (0, 1, 0, 0, 0, 1),
A vertex at (1, 0, 0, 0, 1, 0),
@@ -3627,40 +3633,41 @@ def flow_polytope(self, edges=None, ends=None, backend=None):
Restricting to a subset of the edges::
- sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # needs sage.geometry.polyhedron
....: (2, 3, None), (0, 3, None)]); fl
A 1-dimensional polyhedron in QQ^4 defined as the convex hull
of 2 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices() # needs sage.geometry.polyhedron
(A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0))
Using a different choice of sources and sinks::
- sage: fl = H.flow_polytope(ends=([1], [3])); fl # optional - sage.geometry.polyhedron
+ sage: # needs sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(ends=([1], [3])); fl
A 1-dimensional polyhedron in QQ^6 defined as the convex hull
of 2 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices()
(A vertex at (0, 0, 0, 1, 0, 1), A vertex at (0, 0, 0, 0, 1, 0))
- sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl
The empty polyhedron in QQ^6
- sage: fl = H.flow_polytope(ends=([3], [0])); fl # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(ends=([3], [0])); fl
The empty polyhedron in QQ^6
- sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl
A 3-dimensional polyhedron in QQ^6 defined as the convex hull
of 5 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices()
(A vertex at (0, 0, 1, 1, 0, 0),
A vertex at (0, 1, 0, 0, 1, 0),
A vertex at (1, 0, 0, 2, 0, 1),
A vertex at (1, 0, 0, 1, 1, 0),
A vertex at (0, 1, 0, 1, 0, 1))
- sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron
+ sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None),
....: (2, 3, None), (0, 2, None),
....: (1, 3, None)],
....: ends=([0, 1], [2, 3])); fl
A 2-dimensional polyhedron in QQ^5 defined as the convex hull
of 4 vertices
- sage: fl.vertices() # optional - sage.geometry.polyhedron
+ sage: fl.vertices()
(A vertex at (0, 0, 0, 1, 1),
A vertex at (1, 2, 1, 0, 0),
A vertex at (1, 1, 0, 0, 1),
@@ -3669,13 +3676,13 @@ def flow_polytope(self, edges=None, ends=None, backend=None):
A digraph with one source and two sinks::
sage: Y = DiGraph({1: [2], 2: [3, 4]})
- sage: Y.flow_polytope() # optional - sage.geometry.polyhedron
+ sage: Y.flow_polytope() # needs sage.geometry.polyhedron
The empty polyhedron in QQ^3
A digraph with one vertex and no edge::
sage: Z = DiGraph({1: []})
- sage: Z.flow_polytope() # optional - sage.geometry.polyhedron
+ sage: Z.flow_polytope() # needs sage.geometry.polyhedron
A 0-dimensional polyhedron in QQ^0 defined as the convex hull
of 1 vertex
@@ -3683,11 +3690,11 @@ def flow_polytope(self, edges=None, ends=None, backend=None):
sage: G = DiGraph([(0, 1), (0,1)], multiedges=True); G
Multi-digraph on 2 vertices
- sage: P = G.flow_polytope(); P # optional - sage.geometry.polyhedron
+ sage: P = G.flow_polytope(); P # needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices
- sage: P.vertices() # optional - sage.geometry.polyhedron
+ sage: P.vertices() # needs sage.geometry.polyhedron
(A vertex at (1, 0), A vertex at (0, 1))
- sage: P.lines() # optional - sage.geometry.polyhedron
+ sage: P.lines() # needs sage.geometry.polyhedron
()
"""
from sage.geometry.polyhedron.constructor import Polyhedron
diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py
index b9a87601a47..3070cb2f37f 100644
--- a/src/sage/graphs/digraph_generators.py
+++ b/src/sage/graphs/digraph_generators.py
@@ -226,22 +226,23 @@ def ButterflyGraph(self, n, vertices='strings'):
sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False)
[(('00', 0), ('00', 1)),
- (('00', 0), ('10', 1)),
- (('00', 1), ('00', 2)),
- (('00', 1), ('01', 2)),
- (('01', 0), ('01', 1)),
- (('01', 0), ('11', 1)),
- (('01', 1), ('00', 2)),
- (('01', 1), ('01', 2)),
- (('10', 0), ('00', 1)),
- (('10', 0), ('10', 1)),
- (('10', 1), ('10', 2)),
- (('10', 1), ('11', 2)),
- (('11', 0), ('01', 1)),
- (('11', 0), ('11', 1)),
- (('11', 1), ('10', 2)),
- (('11', 1), ('11', 2))]
- sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(sort=True, labels=False)
+ (('00', 0), ('10', 1)),
+ (('00', 1), ('00', 2)),
+ (('00', 1), ('01', 2)),
+ (('01', 0), ('01', 1)),
+ (('01', 0), ('11', 1)),
+ (('01', 1), ('00', 2)),
+ (('01', 1), ('01', 2)),
+ (('10', 0), ('00', 1)),
+ (('10', 0), ('10', 1)),
+ (('10', 1), ('10', 2)),
+ (('10', 1), ('11', 2)),
+ (('11', 0), ('01', 1)),
+ (('11', 0), ('11', 1)),
+ (('11', 1), ('10', 2)),
+ (('11', 1), ('11', 2))]
+ sage: digraphs.ButterflyGraph(2, vertices='vectors').edges(sort=True, # needs sage.modules sage.rings.finite_rings
+ ....: labels=False)
[(((0, 0), 0), ((0, 0), 1)),
(((0, 0), 0), ((1, 0), 1)),
(((0, 0), 1), ((0, 0), 2)),
@@ -338,7 +339,7 @@ def Path(self, n):
[0, 1, 2, 3, 4]
sage: g.size()
4
- sage: g.automorphism_group().cardinality()
+ sage: g.automorphism_group().cardinality() # needs sage.groups
1
"""
g = DiGraph(n, name="Path")
@@ -370,9 +371,11 @@ def StronglyRegular(self, n):
A Strongly Regular digraph satisfies the condition `AJ = JA = kJ` where
`A` is the adjacency matrix::
+ sage: # needs sage.modules
sage: g = digraphs.StronglyRegular(7); g
Strongly regular digraph: Digraph on 7 vertices
- sage: A = g.adjacency_matrix()*ones_matrix(7); B = ones_matrix(7)*g.adjacency_matrix()
+ sage: A = g.adjacency_matrix()*ones_matrix(7)
+ sage: B = ones_matrix(7)*g.adjacency_matrix()
sage: A == B == A[0, 0]*ones_matrix(7)
True
@@ -380,7 +383,7 @@ def StronglyRegular(self, n):
Wrong parameter::
- sage: digraphs.StronglyRegular(73)
+ sage: digraphs.StronglyRegular(73) # needs sage.modules
Traceback (most recent call last):
...
ValueError: strongly regular digraph with 73 vertices not yet implemented
@@ -413,16 +416,16 @@ def Paley(self, q):
A Paley digraph has `n * (n-1) / 2` edges, its underlying graph is a
clique, and so it is a tournament::
- sage: g = digraphs.Paley(7); g
+ sage: g = digraphs.Paley(7); g # needs sage.rings.finite_rings
Paley digraph with parameter 7: Digraph on 7 vertices
- sage: g.size() == g.order() * (g.order() - 1) / 2
+ sage: g.size() == g.order() * (g.order() - 1) / 2 # needs sage.rings.finite_rings
True
- sage: g.to_undirected().is_clique()
+ sage: g.to_undirected().is_clique() # needs sage.rings.finite_rings
True
A Paley digraph is always self-complementary::
- sage: g.complement().is_isomorphic(g)
+ sage: g.complement().is_isomorphic(g) # needs sage.rings.finite_rings
True
TESTS:
@@ -470,7 +473,7 @@ def TransitiveTournament(self, n):
[0, 1, 2, 3, 4]
sage: g.size()
10
- sage: g.automorphism_group().cardinality()
+ sage: g.automorphism_group().cardinality() # needs sage.groups
1
.. SEEALSO::
@@ -890,15 +893,16 @@ def DeBruijn(self, k, n, vertices='strings'):
de Bruijn digraph of degree 2 and diameter 2::
- sage: db = digraphs.DeBruijn(2, 2); db
+ sage: db = digraphs.DeBruijn(2, 2); db # needs sage.combinat
De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices
- sage: db.order(), db.size()
+ sage: db.order(), db.size() # needs sage.combinat
(4, 8)
- sage: db.diameter()
+ sage: db.diameter() # needs sage.combinat
2
Building a de Bruijn digraph on a different alphabet::
+ sage: # needs sage.combinat
sage: g = digraphs.DeBruijn(['a', 'b'], 2)
sage: g.vertices(sort=True)
['aa', 'ab', 'ba', 'bb']
@@ -914,20 +918,20 @@ def DeBruijn(self, k, n, vertices='strings'):
Alphabet of null size or words of length zero::
- sage: digraphs.DeBruijn(5, 0)
+ sage: digraphs.DeBruijn(5, 0) # needs sage.combinat
De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex
- sage: digraphs.DeBruijn(0, 0)
+ sage: digraphs.DeBruijn(0, 0) # needs sage.combinat
De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices
:trac:`22355`::
- sage: db = digraphs.DeBruijn(2, 2, vertices='strings')
- sage: db.vertices(sort=True)
+ sage: db = digraphs.DeBruijn(2, 2, vertices='strings') # needs sage.combinat
+ sage: db.vertices(sort=True) # needs sage.combinat
['00', '01', '10', '11']
sage: h = digraphs.DeBruijn(2, 2, vertices='integers')
sage: h.vertices(sort=True)
[0, 1, 2, 3]
- sage: db.is_isomorphic(h)
+ sage: db.is_isomorphic(h) # needs sage.combinat
True
sage: digraphs.DeBruijn(0, 0, vertices='integers')
De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices
@@ -998,8 +1002,9 @@ def GeneralizedDeBruijn(self, n, d):
EXAMPLES::
sage: GB = digraphs.GeneralizedDeBruijn(8, 2)
- sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True)
- (True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110', 7: '111'})
+ sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat
+ (True, {0: '000', 1: '001', 2: '010', 3: '011',
+ 4: '100', 5: '101', 6: '110', 7: '111'})
TESTS:
@@ -1054,14 +1059,15 @@ def ImaseItoh(self, n, d):
EXAMPLES::
sage: II = digraphs.ImaseItoh(8, 2)
- sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True)
- (True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100', 7: '101'})
+ sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat
+ (True, {0: '010', 1: '011', 2: '000', 3: '001',
+ 4: '110', 5: '111', 6: '100', 7: '101'})
sage: II = digraphs.ImaseItoh(12, 2)
- sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True)
- sage: b
+ sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) # needs sage.combinat
+ sage: b # needs sage.combinat
True
- sage: D # random isomorphism
+ sage: D # random isomorphism # needs sage.combinat
{0: '202', 1: '201', 2: '210', 3: '212', 4: '121',
5: '120', 6: '102', 7: '101', 8: '010', 9: '012',
10: '021', 11: '020'}
@@ -1132,23 +1138,24 @@ def Kautz(self, k, D, vertices='strings'):
EXAMPLES::
+ sage: # needs sage.combinat
sage: K = digraphs.Kautz(2, 3)
- sage: b,D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True)
+ sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True)
sage: b
True
sage: D # random isomorphism
{'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6,
'120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3}
- sage: K = digraphs.Kautz([1,'a','B'], 2)
- sage: K.edges(sort=True)
+ sage: K = digraphs.Kautz([1,'a','B'], 2) # needs sage.combinat
+ sage: K.edges(sort=True) # needs sage.combinat
[('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'),
('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'),
('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'),
('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')]
- sage: K = digraphs.Kautz([1,'aA','BB'], 2)
- sage: K.edges(sort=True)
+ sage: K = digraphs.Kautz([1,'aA','BB'], 2) # needs sage.combinat
+ sage: K.edges(sort=True) # needs sage.combinat
[('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'),
('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'),
('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'),
@@ -1160,12 +1167,12 @@ def Kautz(self, k, D, vertices='strings'):
An exception is raised when the degree is less than one::
- sage: G = digraphs.Kautz(0, 2)
+ sage: G = digraphs.Kautz(0, 2) # needs sage.combinat
Traceback (most recent call last):
...
ValueError: degree must be greater than or equal to one
- sage: G = digraphs.Kautz(['a'], 2)
+ sage: G = digraphs.Kautz(['a'], 2) # needs sage.combinat
Traceback (most recent call last):
...
ValueError: degree must be greater than or equal to one
@@ -1173,23 +1180,23 @@ def Kautz(self, k, D, vertices='strings'):
An exception is raised when the diameter of the graph is less than
one::
- sage: G = digraphs.Kautz(2, 0)
+ sage: G = digraphs.Kautz(2, 0) # needs sage.combinat
Traceback (most recent call last):
...
ValueError: diameter must be greater than or equal to one
:trac:`22355`::
- sage: K = digraphs.Kautz(2, 2, vertices='strings')
- sage: K.vertices(sort=True)
+ sage: K = digraphs.Kautz(2, 2, vertices='strings') # needs sage.combinat
+ sage: K.vertices(sort=True) # needs sage.combinat
['01', '02', '10', '12', '20', '21']
sage: h = digraphs.Kautz(2, 2, vertices='integers')
sage: h.vertices(sort=True)
[0, 1, 2, 3, 4, 5]
- sage: h.is_isomorphic(K)
+ sage: h.is_isomorphic(K) # needs sage.combinat
True
sage: h = digraphs.Kautz([1,'aA','BB'], 2, vertices='integers')
- sage: h.is_isomorphic(K)
+ sage: h.is_isomorphic(K) # needs sage.combinat
True
sage: h.vertices(sort=True)
[0, 1, 2, 3, 4, 5]
@@ -1346,6 +1353,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None):
EXAMPLES::
+ sage: # needs networkx
sage: D = digraphs.RandomDirectedGN(25)
sage: D.num_verts()
25
@@ -1355,7 +1363,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None):
True
sage: D.parent() is DiGraph
True
- sage: D.show() # long time
+ sage: D.show() # long time
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
@@ -1382,12 +1390,13 @@ def RandomDirectedGNC(self, n, seed=None):
EXAMPLES::
+ sage: # needs networkx
sage: D = digraphs.RandomDirectedGNC(25)
sage: D.is_directed_acyclic()
True
sage: D.topological_sort()
[24, 23, ..., 1, 0]
- sage: D.show() # long time
+ sage: D.show() # long time
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
@@ -1583,12 +1592,13 @@ def RandomDirectedGNR(self, n, p, seed=None):
EXAMPLES::
+ sage: # needs networkx
sage: D = digraphs.RandomDirectedGNR(25, .2)
sage: D.is_directed_acyclic()
True
sage: D.to_undirected().is_tree()
True
- sage: D.show() # long time
+ sage: D.show() # long time # needs sage.plot
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx
index 46baaf8ca73..a5a90cc0c0c 100644
--- a/src/sage/graphs/distances_all_pairs.pyx
+++ b/src/sage/graphs/distances_all_pairs.pyx
@@ -545,7 +545,7 @@ def is_distance_regular(G, parameters=False):
sage: graphs.PathGraph(2).is_distance_regular(parameters=True)
([1, None], [None, 1])
- sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # optional - networkx
+ sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # needs networkx
([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3])
"""
@@ -843,8 +843,8 @@ cdef uint32_t * c_eccentricity_DHV(short_digraph sd) except NULL:
TESTS:
- sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx
- sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # optional - networkx
+ sage: G = graphs.RandomBarabasiAlbert(50, 2) # needs networkx
+ sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # needs networkx
True
"""
cdef uint32_t n = sd.n
@@ -1777,26 +1777,28 @@ def diameter(G, algorithm=None, source=None):
Comparison of exact algorithms for graphs::
- sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx
- sage: d1 = diameter(G, algorithm='standard') # optional - networkx
- sage: d2 = diameter(G, algorithm='iFUB') # optional - networkx
- sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex()) # optional - networkx
- sage: d4 = diameter(G, algorithm='DHV') # optional - networkx
- sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!") # optional - networkx
+ sage: # needs networkx
+ sage: G = graphs.RandomBarabasiAlbert(100, 2)
+ sage: d1 = diameter(G, algorithm='standard')
+ sage: d2 = diameter(G, algorithm='iFUB')
+ sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex())
+ sage: d4 = diameter(G, algorithm='DHV')
+ sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!")
Comparison of lower bound algorithms::
- sage: lb2 = diameter(G, algorithm='2sweep') # optional - networkx
- sage: lbm = diameter(G, algorithm='multi-sweep') # optional - networkx
- sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # optional - networkx
+ sage: lb2 = diameter(G, algorithm='2sweep') # needs networkx
+ sage: lbm = diameter(G, algorithm='multi-sweep') # needs networkx
+ sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # needs networkx
Comparison of exact algorithms for digraphs::
- sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) # optional - networkx
- sage: d1 = diameter(D, algorithm='standard') # optional - networkx
- sage: d2 = diameter(D, algorithm='DiFUB') # optional - networkx
- sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex()) # optional - networkx
- sage: d1 == d2 and d1 == d3 # optional - networkx
+ sage: # needs networkx
+ sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2))
+ sage: d1 = diameter(D, algorithm='standard')
+ sage: d2 = diameter(D, algorithm='DiFUB')
+ sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex())
+ sage: d1 == d2 and d1 == d3
True
TESTS:
@@ -2294,10 +2296,11 @@ def szeged_index(G, algorithm=None):
Check that both algorithms return same value::
- sage: G = graphs.RandomBarabasiAlbert(100, 2) # long time
- sage: a = szeged_index(G, algorithm='low') # long time
- sage: b = szeged_index(G, algorithm='high') # long time
- sage: a == b # long time
+ sage: # long time
+ sage: G = graphs.RandomBarabasiAlbert(100, 2)
+ sage: a = szeged_index(G, algorithm='low')
+ sage: b = szeged_index(G, algorithm='high')
+ sage: a == b
True
The Szeged index of a directed circuit of order `n` is `(n-1)^2`::
@@ -2438,8 +2441,8 @@ def distances_distribution(G):
The de Bruijn digraph dB(2,3)::
- sage: D = digraphs.DeBruijn(2,3) # optional - sage.combinat
- sage: D.distances_distribution() # optional - sage.combinat
+ sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat
+ sage: D.distances_distribution() # needs sage.combinat
{1: 1/4, 2: 11/28, 3: 5/14}
"""
cdef size_t n = G.order()
diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py
index ed2fdd17183..00cc3ed5900 100644
--- a/src/sage/graphs/domination.py
+++ b/src/sage/graphs/domination.py
@@ -24,7 +24,7 @@
We compute the size of a minimum dominating set of the Petersen graph::
sage: g = graphs.PetersenGraph()
- sage: g.dominating_set(value_only=True)
+ sage: g.dominating_set(value_only=True) # needs sage.numerical.mip
3
We enumerate the minimal dominating sets of the 5-star graph::
@@ -281,7 +281,7 @@ def dominating_sets(g, k=1, independent=False, total=False,
Number of distance-`k` dominating sets of a Path graph of order 10::
sage: g = graphs.PathGraph(10)
- sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]
+ sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip
[1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10]
If we build a graph from two disjoint stars, then link their centers we will
@@ -290,15 +290,15 @@ def dominating_sets(g, k=1, independent=False, total=False,
sage: g = 2 * graphs.StarGraph(5)
sage: g.add_edge(0, 6)
- sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]
+ sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip
[1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12]
The total dominating set of the Petersen graph has cardinality 4::
sage: G = graphs.PetersenGraph()
- sage: G.dominating_set(total=True, value_only=True)
+ sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip
4
- sage: sorted(G.dominating_sets(k=1))
+ sage: sorted(G.dominating_sets(k=1)) # needs sage.numerical.mip
[[0, 2, 6],
[0, 3, 9],
[0, 7, 8],
@@ -312,6 +312,7 @@ def dominating_sets(g, k=1, independent=False, total=False,
Independent distance-`k` dominating sets of a Path graph::
+ sage: # needs sage.numerical.mip
sage: G = graphs.PathGraph(6)
sage: sorted(G.dominating_sets(k=1, independent=True))
[[1, 4]]
@@ -323,6 +324,7 @@ def dominating_sets(g, k=1, independent=False, total=False,
The dominating set is calculated for both the directed and undirected graphs
(modification introduced in :trac:`17905`)::
+ sage: # needs sage.numerical.mip
sage: g = digraphs.Path(3)
sage: g.dominating_set(value_only=True)
2
@@ -339,7 +341,7 @@ def dominating_sets(g, k=1, independent=False, total=False,
TESTS::
sage: g = Graph([(0, 1)])
- sage: next(g.dominating_sets(k=-1))
+ sage: next(g.dominating_sets(k=-1)) # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: the domination distance must be a non-negative integer
@@ -468,7 +470,7 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False,
A basic illustration on a ``PappusGraph``::
sage: g = graphs.PappusGraph()
- sage: g.dominating_set(value_only=True)
+ sage: g.dominating_set(value_only=True) # needs sage.numerical.mip
5
If we build a graph from two disjoint stars, then link their centers we will
@@ -477,34 +479,34 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False,
sage: g = 2 * graphs.StarGraph(5)
sage: g.add_edge(0, 6)
- sage: len(g.dominating_set())
+ sage: len(g.dominating_set()) # needs sage.numerical.mip
2
- sage: len(g.dominating_set(independent=True))
+ sage: len(g.dominating_set(independent=True)) # needs sage.numerical.mip
6
The total dominating set of the Petersen graph has cardinality 4::
sage: G = graphs.PetersenGraph()
- sage: G.dominating_set(total=True, value_only=True)
+ sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip
4
The dominating set is calculated for both the directed and undirected graphs
(modification introduced in :trac:`17905`)::
sage: g = digraphs.Path(3)
- sage: g.dominating_set(value_only=True)
+ sage: g.dominating_set(value_only=True) # needs sage.numerical.mip
2
sage: g = graphs.PathGraph(3)
- sage: g.dominating_set(value_only=True)
+ sage: g.dominating_set(value_only=True) # needs sage.numerical.mip
1
Cardinality of distance-`k` dominating sets::
sage: G = graphs.PetersenGraph()
- sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
+ sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip
[10, 3, 1]
sage: G = graphs.PathGraph(5)
- sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
+ sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip
[5, 2, 1]
"""
dom = next(dominating_sets(g, k=k, independent=independent, total=total,
@@ -780,32 +782,32 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1):
sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets())
sage: pp = [{0, 2, 6},
- ....: {0, 9, 3},
- ....: {0, 8, 7},
- ....: {1, 3, 7},
- ....: {1, 4, 5},
- ....: {8, 1, 9},
- ....: {8, 2, 4},
- ....: {9, 2, 5},
- ....: {3, 5, 6},
- ....: {4, 6, 7},
- ....: {0, 8, 2, 9},
- ....: {0, 3, 6, 7},
- ....: {1, 3, 5, 9},
- ....: {8, 1, 4, 7},
- ....: {2, 4, 5, 6},
- ....: {0, 1, 2, 3, 4},
- ....: {0, 1, 2, 5, 7},
- ....: {0, 1, 4, 6, 9},
- ....: {0, 1, 5, 6, 8},
- ....: {0, 8, 3, 4, 5},
- ....: {0, 9, 4, 5, 7},
- ....: {8, 1, 2, 3, 6},
- ....: {1, 2, 9, 6, 7},
- ....: {9, 2, 3, 4, 7},
- ....: {8, 2, 3, 5, 7},
- ....: {8, 9, 3, 4, 6},
- ....: {8, 9, 5, 6, 7}]
+ ....: {0, 9, 3},
+ ....: {0, 8, 7},
+ ....: {1, 3, 7},
+ ....: {1, 4, 5},
+ ....: {8, 1, 9},
+ ....: {8, 2, 4},
+ ....: {9, 2, 5},
+ ....: {3, 5, 6},
+ ....: {4, 6, 7},
+ ....: {0, 8, 2, 9},
+ ....: {0, 3, 6, 7},
+ ....: {1, 3, 5, 9},
+ ....: {8, 1, 4, 7},
+ ....: {2, 4, 5, 6},
+ ....: {0, 1, 2, 3, 4},
+ ....: {0, 1, 2, 5, 7},
+ ....: {0, 1, 4, 6, 9},
+ ....: {0, 1, 5, 6, 8},
+ ....: {0, 8, 3, 4, 5},
+ ....: {0, 9, 4, 5, 7},
+ ....: {8, 1, 2, 3, 6},
+ ....: {1, 2, 9, 6, 7},
+ ....: {9, 2, 3, 4, 7},
+ ....: {8, 2, 3, 5, 7},
+ ....: {8, 9, 3, 4, 6},
+ ....: {8, 9, 5, 6, 7}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py
index 95850012885..ce2cd873c8b 100644
--- a/src/sage/graphs/dot2tex_utils.py
+++ b/src/sage/graphs/dot2tex_utils.py
@@ -74,7 +74,7 @@ def quoted_latex(x):
EXAMPLES::
- sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules
+ sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules
'\\left(\\begin{array}{rr}1 & 1 \\\\0 & 1 \\\\0 & 0\\end{array}\\right)'
"""
return re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x))
@@ -89,9 +89,9 @@ def quoted_str(x):
EXAMPLES::
- sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules
+ sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules
'[1 1]\\n\\\n[0 1]\\n\\\n[0 0]'
- sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # optional - sage.modules
+ sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # needs sage.modules
[1 1]\n\
[0 1]\n\
[0 0]
diff --git a/src/sage/graphs/edge_connectivity.pyx b/src/sage/graphs/edge_connectivity.pyx
index c4cf6a4f81b..02326437a54 100644
--- a/src/sage/graphs/edge_connectivity.pyx
+++ b/src/sage/graphs/edge_connectivity.pyx
@@ -56,10 +56,10 @@ cdef class GabowEdgeConnectivity:
A random `d`-regular digraph is `d`-edge-connected::
sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
- sage: D = DiGraph(graphs.RandomRegular(6, 50)) # optional - networkx
- sage: while not D.is_strongly_connected(): # optional - networkx
+ sage: D = DiGraph(graphs.RandomRegular(6, 50)) # needs networkx
+ sage: while not D.is_strongly_connected(): # needs networkx
....: D = DiGraph(graphs.RandomRegular(6, 50))
- sage: GabowEdgeConnectivity(D).edge_connectivity() # optional - networkx
+ sage: GabowEdgeConnectivity(D).edge_connectivity() # needs networkx
6
A complete digraph with `n` vertices is `n-1`-edge-connected::
@@ -72,15 +72,16 @@ cdef class GabowEdgeConnectivity:
Check that we get the same result when with and without the DFS-based
speed-up initialization proposed in [GKLP2021]_::
- sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx
- sage: D = DiGraph(G) # optional - networkx
- sage: ec1 = GabowEdgeConnectivity(D, # optional - networkx
+ sage: # needs networkx
+ sage: G = graphs.RandomBarabasiAlbert(100, 2)
+ sage: D = DiGraph(G)
+ sage: ec1 = GabowEdgeConnectivity(D,
....: dfs_preprocessing=False).edge_connectivity()
- sage: ec2 = GabowEdgeConnectivity(D, # optional - networkx
+ sage: ec2 = GabowEdgeConnectivity(D,
....: dfs_preprocessing=True).edge_connectivity()
- sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, # optional - networkx
+ sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True,
....: use_rec=True).edge_connectivity()
- sage: ec1 == ec2 and ec2 == ec3 # optional - networkx
+ sage: ec1 == ec2 and ec2 == ec3
True
TESTS:
diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py
index 43e0b683703..314d66aef43 100644
--- a/src/sage/graphs/generators/basic.py
+++ b/src/sage/graphs/generators/basic.py
@@ -179,13 +179,13 @@ def CircularLadderGraph(n):
sage: for i in range(9):
....: k = graphs.CircularLadderGraph(i+3)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3): # needs sage.plot
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j) # needs sage.plot
+ sage: G.show() # long time # needs sage.plot
"""
G = Graph(2 * n, name="Circular Ladder graph")
G._circle_embedding(list(range(n)), radius=1, angle=pi/2)
@@ -248,44 +248,47 @@ def CycleGraph(n):
Compare plotting using the predefined layout and networkx::
- sage: import networkx # optional - networkx
- sage: n = networkx.cycle_graph(23) # optional - networkx
- sage: spring23 = Graph(n) # optional - networkx
- sage: posdict23 = graphs.CycleGraph(23) # optional - networkx
- sage: spring23.show() # long time # optional - networkx
- sage: posdict23.show() # long time # optional - networkx
+ sage: # needs networkx sage.plot
+ sage: import networkx
+ sage: n = networkx.cycle_graph(23)
+ sage: spring23 = Graph(n)
+ sage: posdict23 = graphs.CycleGraph(23)
+ sage: spring23.show() # long time
+ sage: posdict23.show() # long time
We next view many cycle graphs as a Sage graphics array. First we use the
``CycleGraph`` constructor, which fills in the position dictionary::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CycleGraph(i+3)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Compare to plotting with the spring-layout algorithm::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
TESTS:
@@ -334,42 +337,45 @@ def CompleteGraph(n):
We view many Complete graphs with a Sage Graphics Array, first with this
constructor (i.e., the position dictionary filled)::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CompleteGraph(i+3)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
We compare to plotting with the spring-layout algorithm::
- sage: import networkx # optional - networkx
+ sage: # needs networkx sage.plot
+ sage: import networkx
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.complete_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Compare the constructors (results will vary)::
- sage: import networkx # optional - networkx
- sage: t = cputime() # optional - networkx
- sage: n = networkx.complete_graph(389); spring389 = Graph(n) # optional - networkx
- sage: cputime(t) # random # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: t = cputime()
+ sage: n = networkx.complete_graph(389); spring389 = Graph(n)
+ sage: cputime(t) # random
0.59203700000000126
sage: t = cputime()
sage: posdict389 = graphs.CompleteGraph(389)
@@ -378,12 +384,13 @@ def CompleteGraph(n):
We compare plotting::
- sage: import networkx # optional - networkx
- sage: n = networkx.complete_graph(23) # optional - networkx
- sage: spring23 = Graph(n) # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: n = networkx.complete_graph(23)
+ sage: spring23 = Graph(n)
sage: posdict23 = graphs.CompleteGraph(23)
- sage: spring23.show() # long time # optional - networkx sage.plot
- sage: posdict23.show() # long time # optional - sage.plot
+ sage: spring23.show() # long time # needs sage.plot
+ sage: posdict23.show() # long time # needs sage.plot
"""
G = Graph(n, name="Complete graph")
if n == 1:
@@ -403,16 +410,17 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation):
EXAMPLES:
+ sage: # needs numpy
sage: from sage.graphs.generators.basic import CorrelationGraph
sage: data = [[1,2,3], [4,5,6], [7,8,9999]]
- sage: CG1 = CorrelationGraph(data, 0.9, False) # optional - numpy
- sage: CG2 = CorrelationGraph(data, 0.9, True) # optional - numpy
- sage: CG3 = CorrelationGraph(data, 0.1, True) # optional - numpy
- sage: CG1.edges(sort=False) # optional - numpy
+ sage: CG1 = CorrelationGraph(data, 0.9, False)
+ sage: CG2 = CorrelationGraph(data, 0.9, True)
+ sage: CG3 = CorrelationGraph(data, 0.1, True)
+ sage: CG1.edges(sort=False)
[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
- sage: CG2.edges(sort=False) # optional - numpy
+ sage: CG2.edges(sort=False)
[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
- sage: CG3.edges(sort=False) # optional - numpy
+ sage: CG3.edges(sort=False)
[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)]
"""
@@ -477,20 +485,21 @@ def CompleteBipartiteGraph(p, q, set_position=True):
Two ways of constructing the complete bipartite graph, using different
layout algorithms::
- sage: import networkx # optional - networkx
- sage: n = networkx.complete_bipartite_graph(389, 157) # long time # optional - networkx
- sage: spring_big = Graph(n) # long time # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: n = networkx.complete_bipartite_graph(389, 157) # long time
+ sage: spring_big = Graph(n) # long time
sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time
Compare the plotting::
- sage: n = networkx.complete_bipartite_graph(11, 17) # optional - networkx
- sage: spring_med = Graph(n) # optional - networkx
+ sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx
+ sage: spring_med = Graph(n) # needs networkx
sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)
Notice here how the spring-layout tends to center the nodes of `n1`::
- sage: spring_med.show() # long time # optional - networkx
+ sage: spring_med.show() # long time # needs networkx
sage: posdict_med.show() # long time
View many complete bipartite graphs with a Sage Graphics Array, with this
@@ -501,29 +510,30 @@ def CompleteBipartiteGraph(p, q, set_position=True):
sage: for i in range(9):
....: k = graphs.CompleteBipartiteGraph(i+1,4)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3): # needs sage.plot
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j) # needs sage.plot
+ sage: G.show() # long time # needs sage.plot
We compare to plotting with the spring-layout algorithm::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.complete_bipartite_graph(i+1,4)
....: k = Graph(spr)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
:trac:`12155`::
@@ -825,13 +835,13 @@ def Toroidal6RegularGrid2dGraph(p, q):
sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
sage: g.is_regular(k=6)
True
- sage: g.is_vertex_transitive() # optional - sage.groups
+ sage: g.is_vertex_transitive() # needs sage.groups
True
- sage: g.line_graph().is_vertex_transitive() # optional - sage.groups
+ sage: g.line_graph().is_vertex_transitive() # needs sage.groups
True
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
300
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
TESTS:
@@ -973,9 +983,9 @@ def GridGraph(dim_list):
sage: dim = [randint(1,4) for i in range(4)]
sage: g = graphs.GridGraph(dim)
- sage: import networkx # optional - networkx
- sage: h = Graph(networkx.grid_graph(list(dim))) # optional - networkx
- sage: g.is_isomorphic(h) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx
+ sage: g.is_isomorphic(h) # needs networkx
True
Trivial cases::
@@ -1110,18 +1120,19 @@ def LadderGraph(n):
Create several ladder graphs in a Sage graphics array::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.LadderGraph(i+2)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
pos_dict = {}
for i in range(n):
@@ -1263,14 +1274,15 @@ def StarGraph(n):
EXAMPLES::
- sage: import networkx # optional - networkx
+ sage: import networkx # needs networkx
Compare the plots::
- sage: n = networkx.star_graph(23) # optional - networkx
- sage: spring23 = Graph(n) # optional - networkx
+ sage: # needs networkx sage.plot
+ sage: n = networkx.star_graph(23)
+ sage: spring23 = Graph(n)
sage: posdict23 = graphs.StarGraph(23)
- sage: spring23.show() # long time # optional - networkx
+ sage: spring23.show() # long time
sage: posdict23.show() # long time
View many star graphs as a Sage Graphics Array
@@ -1279,36 +1291,38 @@ def StarGraph(n):
::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.StarGraph(i+3)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Compared to plotting with the spring-layout algorithm
::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.star_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
G = Graph({0: list(range(1, n + 1))}, name="Star graph", format="dict_of_lists")
G.set_pos({0: (0, 0)})
diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py
index 2835fbe987f..59517d128bb 100644
--- a/src/sage/graphs/generators/chessboard.py
+++ b/src/sage/graphs/generators/chessboard.py
@@ -414,7 +414,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False):
The `(6,6)`-Knight Graph is Hamiltonian::
sage: G = graphs.KnightGraph( [6, 6] )
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
"""
G, dimstr = ChessboardGraphGenerator(dim_list,
diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py
index 680402dc476..a770ecdbd28 100644
--- a/src/sage/graphs/generators/classical_geometries.py
+++ b/src/sage/graphs/generators/classical_geometries.py
@@ -48,32 +48,34 @@ def SymplecticPolarGraph(d, q, algorithm=None):
Computation of the spectrum of `Sp(6,2)`::
- sage: g = graphs.SymplecticPolarGraph(6,2)
+ sage: g = graphs.SymplecticPolarGraph(6, 2)
sage: g.is_strongly_regular(parameters=True)
(63, 30, 13, 15)
- sage: set(g.spectrum()) == {-5, 3, 30}
+ sage: set(g.spectrum()) == {-5, 3, 30} # needs sage.rings.number_field
True
The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are
not isomorphic if `q` is odd::
- sage: G = graphs.SymplecticPolarGraph(4,3)
+ sage: G = graphs.SymplecticPolarGraph(4, 3)
sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
- sage: O = graphs.OrthogonalPolarGraph(5,3)
+
+ sage: # needs sage.libs.gap
+ sage: O = graphs.OrthogonalPolarGraph(5, 3)
sage: O.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
sage: O.is_isomorphic(G)
False
- sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time) # optional - sage.libs.gap
- sage: S.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.libs.gap
+ sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time)
+ sage: S.is_strongly_regular(parameters=True) # not tested (long time)
(1365, 340, 83, 85)
TESTS::
- sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap
(85, 20, 3, 5)
- sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True)
+ sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) # needs sage.libs.pari
(85, 20, 3, 5)
sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah")
Traceback (most recent call last):
@@ -147,13 +149,14 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"):
The :meth:`Brouwer-Haemers graph ` is isomorphic to
`VO^-(4,3)`::
- sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
- sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())
+ sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") # needs sage.libs.gap
+ sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # needs sage.libs.gap
True
Some examples from `Brouwer's table or strongly regular graphs
`_::
+ sage: # needs sage.libs.gap
sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g
Affine Polar Graph VO^-(6,2): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
@@ -165,6 +168,7 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"):
When ``sign is None``::
+ sage: # needs sage.libs.gap
sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g
Affine Polar Graph VO^-(5,2): Graph on 32 vertices
sage: g.is_strongly_regular(parameters=True)
@@ -224,14 +228,14 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]):
Petersen graph::
sage: from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph
- sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # needs sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(10, 3, 0, 1)
A locally Petersen graph (a.k.a. Doro graph, a.k.a. Hall graph)::
- sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # optional - sage.libs.gap
- sage: g.is_distance_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # needs sage.libs.gap
+ sage: g.is_distance_regular(parameters=True) # needs sage.libs.gap
([10, 6, 4, None], [None, 1, 2, 5])
Various big and slow to build graphs:
@@ -250,20 +254,20 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]):
`NO^+(6,3)`::
- sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # needs sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(117, 36, 15, 9)
`NO^-(6,3)`::
- sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # needs sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(126, 45, 12, 18)
`NO^{-,\perp}(5,5)`::
- sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap
(300, 65, 10, 15)
`NO^{+,\perp}(5,5)`::
@@ -274,11 +278,12 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]):
TESTS::
- sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: g = _orthogonal_polar_graph(5,3,point_type=[-1])
+ sage: g.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
- sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = _orthogonal_polar_graph(5,3,point_type=[1])
+ sage: g.is_strongly_regular(parameters=True)
(36, 15, 6, 6)
"""
@@ -342,34 +347,35 @@ def OrthogonalPolarGraph(m, q, sign="+"):
EXAMPLES::
- sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(130, 48, 20, 16)
- sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(112, 30, 2, 10)
- sage: G = graphs.OrthogonalPolarGraph(5,3); G # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(5,3); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(40, 12, 2, 4)
- sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(135, 70, 37, 35)
- sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(119, 54, 21, 27)
TESTS::
- sage: G = graphs.OrthogonalPolarGraph(4,3,"") # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(4,3,"") # needs sage.libs.gap
Traceback (most recent call last):
...
ValueError: sign must be equal to either '-' or '+' when m is even
- sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # needs sage.libs.gap
Traceback (most recent call last):
...
ValueError: sign must be equal to either '' or '+' when m is odd
@@ -417,43 +423,46 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None):
`NO^-(4,2)` is isomorphic to Petersen graph::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # needs sage.libs.gap
NO^-(4, 2): Graph on 10 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(10, 3, 0, 1)
`NO^-(6,2)` and `NO^+(6,2)`::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-')
+ sage: g.is_strongly_regular(parameters=True)
(36, 15, 6, 6)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g
NO^+(6, 2): Graph on 28 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True)
(28, 15, 6, 10)
`NO^+(8,2)`::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # needs sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(120, 63, 30, 36)
Wilbrink's graphs for `q=5`::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1)
+ sage: g.is_strongly_regular(parameters=True) # long time
(325, 60, 15, 10)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1)
+ sage: g.is_strongly_regular(parameters=True) # long time
(300, 65, 10, 15)
Wilbrink's graphs::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
+ sage: g.is_strongly_regular(parameters=True)
(136, 75, 42, 40)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-')
+ sage: g.is_strongly_regular(parameters=True)
(120, 51, 18, 24)
sage: g = graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time)
NO^+(7, 4): Graph on 2080 vertices
@@ -462,29 +471,33 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None):
TESTS::
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g
NO^+(4, 2): Graph on 6 vertices
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') # optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-')
+ sage: g.is_strongly_regular(parameters=True)
(15, 6, 1, 3)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g
NO^-,perp(3, 5): Graph on 10 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True)
(10, 3, 0, 1)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+
+ sage: # long time, needs sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+')
+ sage: g.is_strongly_regular(parameters=True)
(117, 36, 15, 9)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time, optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g
NO^-(6, 3): Graph on 126 vertices
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True)
(126, 45, 12, 18)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-')
+ sage: g.is_strongly_regular(parameters=True)
(300, 104, 28, 40)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, optional - sage.libs.gap
- sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+')
+ sage: g.is_strongly_regular(parameters=True)
(325, 144, 68, 60)
- sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') # optional - sage.libs.gap
+
+ sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+')
Traceback (most recent call last):
...
ValueError: for m even q must be 2 or 3
@@ -565,9 +578,9 @@ def _polar_graph(m, q, g, intersection_size=None):
TESTS::
sage: from sage.graphs.generators.classical_geometries import _polar_graph
- sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # optional - sage.libs.gap
+ sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap
Graph on 45 vertices
- sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # optional - sage.libs.gap
+ sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # needs sage.libs.gap
Graph on 27 vertices
"""
from sage.libs.gap.libgap import libgap
@@ -609,20 +622,21 @@ def UnitaryPolarGraph(m, q, algorithm="gap"):
EXAMPLES::
- sage: G = graphs.UnitaryPolarGraph(4,2); G # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: G = graphs.UnitaryPolarGraph(4,2); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
- sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True)
(45, 12, 3, 3)
- sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True)
(165, 36, 3, 9)
- sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) # optional - sage.libs.gap
+ sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time)
Unitary Polar Graph U(6, 2): Graph on 693 vertices
TESTS::
- sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap
(280, 36, 8, 4)
- sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # needs sage.libs.gap
(280, 36, 8, 4)
sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo")
Traceback (most recent call last):
@@ -676,18 +690,18 @@ def NonisotropicUnitaryPolarGraph(m, q):
EXAMPLES::
- sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # optional - sage.libs.gap
+ sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # needs sage.libs.gap
NU(5, 2): Graph on 176 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
(176, 135, 102, 108)
TESTS::
- sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap
+ sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # needs sage.libs.gap
(40, 27, 18, 18)
- sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap
+ sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, needs sage.libs.gap
(540, 224, 88, 96)
- sage: graphs.NonisotropicUnitaryPolarGraph(6,6) # optional - sage.libs.gap
+ sage: graphs.NonisotropicUnitaryPolarGraph(6,6)
Traceback (most recent call last):
...
ValueError: q must be a prime power
@@ -742,16 +756,16 @@ def UnitaryDualPolarGraph(m, q):
The point graph of a generalized quadrangle (see
:wikipedia:`Generalized_quadrangle`, [PT2009]_) of order (8,4)::
- sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # optional - sage.libs.gap
+ sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # needs sage.libs.gap
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
- sage: G.is_strongly_regular(parameters=True) # long time # optional - sage.libs.gap
+ sage: G.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap
(297, 40, 7, 5)
Another way to get the generalized quadrangle of order (2,4)::
- sage: G = graphs.UnitaryDualPolarGraph(4,2); G # optional - sage.libs.gap
+ sage: G = graphs.UnitaryDualPolarGraph(4,2); G # needs sage.libs.gap
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices
- sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # optional - sage.libs.gap
+ sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # needs sage.libs.gap
True
A bigger graph::
@@ -763,7 +777,7 @@ def UnitaryDualPolarGraph(m, q):
TESTS::
- sage: graphs.UnitaryDualPolarGraph(6,6) # optional - sage.libs.gap
+ sage: graphs.UnitaryDualPolarGraph(6,6) # needs sage.libs.gap
Traceback (most recent call last):
...
GAPError: Error, must be a prime or a finite field
@@ -800,11 +814,11 @@ def SymplecticDualPolarGraph(m, q):
TESTS::
- sage: G = graphs.SymplecticDualPolarGraph(6,2); G # optional - sage.libs.gap
+ sage: G = graphs.SymplecticDualPolarGraph(6,2); G # needs sage.libs.gap
Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices
- sage: G.is_distance_regular(parameters=True) # optional - sage.libs.gap
+ sage: G.is_distance_regular(parameters=True) # needs sage.libs.gap
([14, 12, 8, None], [None, 1, 3, 7])
- sage: graphs.SymplecticDualPolarGraph(6,6) # optional - sage.libs.gap
+ sage: graphs.SymplecticDualPolarGraph(6,6) # needs sage.libs.gap
Traceback (most recent call last):
...
GAPError: Error, must be a prime or a finite field
@@ -848,28 +862,30 @@ def TaylorTwographDescendantSRG(q, clique_partition=False):
EXAMPLES::
- sage: g = graphs.TaylorTwographDescendantSRG(3); g # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: g = graphs.TaylorTwographDescendantSRG(3); g
Taylor two-graph descendant SRG: Graph on 27 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(27, 10, 1, 5)
sage: from sage.combinat.designs.twographs import taylor_twograph
- sage: T = taylor_twograph(3) # long time, optional - sage.rings.finite_rings
- sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time, optional - sage.rings.finite_rings
+ sage: T = taylor_twograph(3) # long time
+ sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time
True
- sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time)
- sage: g.is_strongly_regular(parameters=True) # not tested (long time)
+ sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time)
+ sage: g.is_strongly_regular(parameters=True) # not tested (long time)
(125, 52, 15, 26)
TESTS::
- sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) # optional - sage.rings.finite_rings
- sage: all(g.is_clique(x) for x in l) # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True)
+ sage: all(g.is_clique(x) for x in l)
True
- sage: graphs.TaylorTwographDescendantSRG(4) # optional - sage.rings.finite_rings
+ sage: graphs.TaylorTwographDescendantSRG(4)
Traceback (most recent call last):
...
ValueError: q must be an odd prime power
- sage: graphs.TaylorTwographDescendantSRG(6) # optional - sage.rings.finite_rings
+ sage: graphs.TaylorTwographDescendantSRG(6)
Traceback (most recent call last):
...
ValueError: q must be an odd prime power
@@ -922,9 +938,9 @@ def TaylorTwographSRG(q):
EXAMPLES::
- sage: t = graphs.TaylorTwographSRG(3); t # optional - sage.rings.finite_rings
+ sage: t = graphs.TaylorTwographSRG(3); t # needs sage.rings.finite_rings
Taylor two-graph SRG: Graph on 28 vertices
- sage: t.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: t.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
(28, 15, 6, 10)
"""
G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True)
@@ -959,13 +975,13 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False):
EXAMPLES::
- sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g # optional - sage.rings.finite_rings
+ sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
AS(5); GQ(4, 6): Graph on 125 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(125, 28, 3, 7)
- sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g # optional - sage.rings.finite_rings
+ sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(175, 30, 5, 5)
"""
from sage.combinat.designs.incidence_structures import IncidenceStructure
@@ -1029,35 +1045,38 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None,
using the built-in construction::
- sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)
- sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g # optional - sage.rings.finite_rings
+ sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g
T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(96, 20, 4, 4)
supplying your own hyperoval::
- sage: F = GF(4,'b') # optional - sage.rings.finite_rings
- sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: F = GF(4,'b')
+ sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x))
....: for x in F]
- sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g # optional - sage.rings.finite_rings
+ sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(64, 18, 2, 6)
TESTS::
+ sage: # needs sage.rings.finite_rings
sage: F = GF(4,'b') # repeating a point...
- sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
- sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings
+ sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F]
+ sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
Traceback (most recent call last):
...
RuntimeError: incorrect hyperoval size
- sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
- sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings
+ sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F]
+ sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
Traceback (most recent call last):
...
RuntimeError: incorrect hyperoval
@@ -1149,35 +1168,36 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h
using the built-in constructions::
- sage: g = graphs.HaemersGraph(4); g # optional - sage.rings.finite_rings
+ sage: g = graphs.HaemersGraph(4); g # needs sage.rings.finite_rings
Haemers(4): Graph on 96 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
(96, 19, 2, 4)
supplying your own hyperoval_matching::
- sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # optional - sage.rings.finite_rings
+ sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # needs sage.rings.finite_rings
Haemers(4): Graph on 96 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
(96, 19, 2, 4)
TESTS::
- sage: F=GF(4,'b') # repeating a point... # optional - sage.rings.finite_rings
- sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
- sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: F = GF(4,'b') # repeating a point...
+ sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F]
+ sage: graphs.HaemersGraph(4, hyperoval=O, field=F)
Traceback (most recent call last):
...
RuntimeError: incorrect hyperoval size
- sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
- sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings
+ sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F]
+ sage: graphs.HaemersGraph(4, hyperoval=O, field=F)
Traceback (most recent call last):
...
RuntimeError: incorrect hyperoval
- sage: g = graphs.HaemersGraph(8); g # not tested (long time) # optional - sage.rings.finite_rings
+ sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings
Haemers(8): Graph on 640 vertices
- sage: g.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings
(640, 71, 6, 8)
"""
@@ -1264,19 +1284,19 @@ def CossidentePenttilaGraph(q):
For `q=3` one gets Sims-Gewirtz graph. ::
- sage: g = graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape)
+ sage: G = graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape)
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(56, 10, 0, 2)
For `q>3` one gets new graphs. ::
- sage: g = graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape)
+ sage: G = graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape)
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape)
(378, 52, 1, 8)
TESTS::
- sage: g = graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time
+ sage: G = graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time
sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time
(1376, 150, 2, 18)
sage: graphs.CossidentePenttilaGraph(2)
@@ -1372,9 +1392,10 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov
using the built-in construction::
- sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time)
sage: g.is_strongly_regular(parameters=True) # not tested (long time)
@@ -1382,23 +1403,25 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov
supplying your own hyperoval::
+ sage: # needs sage.rings.finite_rings
sage: F = GF(8)
- sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) # optional - sage.rings.finite_rings
+ sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x))
....: for x in F]
- sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g # optional - sage.rings.finite_rings
+ sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
- sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings
+ sage: g.is_strongly_regular(parameters=True)
(196, 60, 14, 20)
TESTS::
- sage: F = GF(8) # repeating a point... # optional - sage.rings.finite_rings
- sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
- sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # optional - sage.rings.finite_rings
+ sage: # needs sage.rings.finite_rings
+ sage: F = GF(8) # repeating a point...
+ sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F]
+ sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F)
Traceback (most recent call last):
...
RuntimeError: incorrect hyperoval size
- sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings
+ sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F]
sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F)
Traceback (most recent call last):
...
@@ -1467,13 +1490,14 @@ def OrthogonalDualPolarGraph(e, d, q):
EXAMPLES::
- sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(1,3,2)
+ sage: G.is_distance_regular(True)
([7, 6, 4, None], [None, 1, 3, 7])
- sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time
+ sage: G.is_distance_regular(True) # long time
([39, 36, 27, None], [None, 1, 4, 13])
- sage: G.order() # long time # optional - sage.libs.gap
+ sage: G.order() # long time
1120
REFERENCES:
@@ -1482,17 +1506,18 @@ def OrthogonalDualPolarGraph(e, d, q):
TESTS::
- sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # optional - sage.libs.gap
+ sage: # needs sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(0,3,2)
+ sage: G.is_distance_regular(True)
([14, 12, 8, None], [None, 1, 3, 7])
- sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time
+ sage: G.is_distance_regular(True) # long time
([28, 24, 16, None], [None, 1, 3, 7])
- sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(1,3,4)
+ sage: G.is_distance_regular(True)
([21, 20, 16, None], [None, 1, 5, 21])
- sage: G = graphs.OrthogonalDualPolarGraph(1,4,2) # optional - sage.libs.gap
- sage: G.is_distance_regular(True) # optional - sage.libs.gap
+ sage: G = graphs.OrthogonalDualPolarGraph(1,4,2)
+ sage: G.is_distance_regular(True)
([15, 14, 12, 8, None], [None, 1, 3, 7, 15])
"""
from sage.libs.gap.libgap import libgap
diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py
index 071878d124e..ed89ce43abc 100644
--- a/src/sage/graphs/generators/degree_sequence.py
+++ b/src/sage/graphs/generators/degree_sequence.py
@@ -41,25 +41,25 @@ def DegreeSequence(deg_sequence):
EXAMPLES::
- sage: G = graphs.DegreeSequence([3,3,3,3]) # optional - networkx
- sage: G.edges(sort=True, labels=False) # optional - networkx
+ sage: G = graphs.DegreeSequence([3,3,3,3]) # needs networkx
+ sage: G.edges(sort=True, labels=False) # needs networkx
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs networkx sage.plot
::
- sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
::
- sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
::
- sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
"""
import networkx
return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence]))
@@ -93,15 +93,15 @@ def DegreeSequenceBipartite(s1, s2):
If we are given as sequences ``[2,2,2,2,2]`` and ``[5,5]`` we are given as
expected the complete bipartite graph `K_{2,5}`::
- sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # optional - sage.modules
- sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # optional - sage.modules
+ sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # needs sage.modules
+ sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # needs sage.modules
True
Some sequences being incompatible if, for example, their sums are different,
the functions raises a ``ValueError`` when no graph corresponding to the
degree sequences exists::
- sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # optional - sage.modules
+ sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # needs sage.modules
Traceback (most recent call last):
...
ValueError: there exists no bipartite graph corresponding to the given degree sequences
@@ -110,7 +110,7 @@ def DegreeSequenceBipartite(s1, s2):
:trac:`12155`::
- sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # optional - sage.modules
+ sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # needs sage.modules
Graph on 7 vertices
"""
from sage.combinat.integer_vector import gale_ryser_theorem
@@ -147,20 +147,21 @@ def DegreeSequenceConfigurationModel(deg_sequence, seed=None):
EXAMPLES::
- sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # optional - networkx
- sage: G.adjacency_matrix() # optional - networkx sage.modules
+ sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # needs networkx
+ sage: G.adjacency_matrix() # needs networkx sage.modules
[0 1]
[1 0]
The output is allowed to contain both loops and multiple edges::
- sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] # optional - networkx
- sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) # optional - networkx
- sage: G.order(), G.size() # optional - networkx
+ sage: # needs networkx
+ sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
+ sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence)
+ sage: G.order(), G.size()
(20, 30)
- sage: G.has_loops() or G.has_multiple_edges() # random # optional - networkx
+ sage: G.has_loops() or G.has_multiple_edges() # random
True
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs sage.plot
REFERENCE:
@@ -191,9 +192,9 @@ def DegreeSequenceTree(deg_sequence):
EXAMPLES::
- sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # optional - networkx
+ sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # needs networkx
Graph on 9 vertices
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs networkx sage.plot
"""
import networkx
return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence]))
@@ -219,9 +220,9 @@ def DegreeSequenceExpected(deg_sequence, seed=None):
EXAMPLES::
- sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # optional - networkx
+ sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # needs networkx
Looped graph on 5 vertices
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs networkx sage.plot
REFERENCE:
diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx
index dd809a835af..15bd3594185 100644
--- a/src/sage/graphs/generators/distance_regular.pyx
+++ b/src/sage/graphs/generators/distance_regular.pyx
@@ -132,8 +132,8 @@ def ConwaySmith_for_3S7():
EXAMPLES::
- sage: G = graphs.ConwaySmith_for_3S7()
- sage: G.is_distance_regular(True)
+ sage: G = graphs.ConwaySmith_for_3S7() # needs sage.modules sage.rings.finite_rings sage.rings.number_field
+ sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings sage.rings.number_field
([10, 6, 4, 1, None], [None, 1, 2, 6, 10])
REFERENCES:
@@ -243,8 +243,8 @@ def FosterGraph3S6():
EXAMPLES::
- sage: G = graphs.FosterGraph3S6()
- sage: G.is_distance_regular(True)
+ sage: G = graphs.FosterGraph3S6() # needs sage.libs.gap
+ sage: G.is_distance_regular(True) # needs sage.libs.gap
([6, 4, 2, 1, None], [None, 1, 1, 4, 6])
REFERENCES:
@@ -321,8 +321,8 @@ def LargeWittGraph():
EXAMPLES::
- sage: g = graphs.LargeWittGraph()
- sage: g.is_distance_regular(True)
+ sage: g = graphs.LargeWittGraph() # needs sage.modules
+ sage: g.is_distance_regular(True) # needs sage.modules
([30, 28, 24, None], [None, 1, 3, 15])
REFERENCES:
@@ -359,8 +359,8 @@ def TruncatedWittGraph():
EXAMPLES::
- sage: G = graphs.TruncatedWittGraph() # long time
- sage: G.is_distance_regular(True) # long time (due to above)
+ sage: G = graphs.TruncatedWittGraph() # long time # needs sage.modules
+ sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules
([15, 14, 12, None], [None, 1, 1, 9])
REFERENCES:
@@ -388,8 +388,8 @@ def DoublyTruncatedWittGraph():
EXAMPLES::
- sage: G = graphs.DoublyTruncatedWittGraph()
- sage: G.is_distance_regular(True)
+ sage: G = graphs.DoublyTruncatedWittGraph() # needs sage.modules
+ sage: G.is_distance_regular(True) # needs sage.modules
([7, 6, 4, 4, None], [None, 1, 1, 1, 6])
REFERENCES:
@@ -411,8 +411,8 @@ def distance_3_doubly_truncated_Golay_code_graph():
EXAMPLES::
- sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time
- sage: G.is_distance_regular(True) # long time (due to above)
+ sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time, needs sage.modules sage.rings.finite_rings
+ sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules sage.rings.finite_rings
([9, 8, 6, 3, None], [None, 1, 1, 3, 8])
ALGORITHM:
@@ -446,8 +446,8 @@ def shortened_00_11_binary_Golay_code_graph():
EXAMPLES::
- sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s)
- sage: G.is_distance_regular(True) # long time
+ sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s), needs sage.modules sage.rings.finite_rings
+ sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings
([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21])
ALGORITHM:
@@ -485,8 +485,8 @@ def shortened_000_111_extended_binary_Golay_code_graph():
EXAMPLES::
- sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s)
- sage: G.is_distance_regular(True) # long time
+ sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s), needs sage.modules sage.rings.finite_rings
+ sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings
([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21])
ALGORITHM:
@@ -526,8 +526,8 @@ def vanLintSchrijverGraph():
EXAMPLES::
- sage: G = graphs.vanLintSchrijverGraph()
- sage: G.is_distance_regular(True)
+ sage: G = graphs.vanLintSchrijverGraph() # needs sage.modules
+ sage: G.is_distance_regular(True) # needs sage.modules
([6, 5, 5, 4, None], [None, 1, 1, 2, 6])
REFERENCES:
@@ -557,8 +557,8 @@ def LeonardGraph():
EXAMPLES::
- sage: G = graphs.LeonardGraph()
- sage: G.is_distance_regular(True)
+ sage: G = graphs.LeonardGraph() # needs sage.combinat sage.modules
+ sage: G.is_distance_regular(True) # needs sage.combinat sage.modules
([12, 11, 10, 7, None], [None, 1, 2, 5, 12])
REFERENCES:
@@ -597,8 +597,8 @@ def UstimenkoGraph(const int m, const int q):
EXAMPLES::
- sage: G = graphs.UstimenkoGraph(4, 2)
- sage: G.is_distance_regular(True)
+ sage: G = graphs.UstimenkoGraph(4, 2) # needs sage.libs.gap
+ sage: G.is_distance_regular(True) # needs sage.libs.gap
([70, 32, None], [None, 1, 35])
REFERENCES:
@@ -607,13 +607,14 @@ def UstimenkoGraph(const int m, const int q):
TESTS::
- sage: G = graphs.UstimenkoGraph(5, 2) # long time
- sage: G.order() # long time
+ sage: # long time, needs sage.libs.gap
+ sage: G = graphs.UstimenkoGraph(5, 2)
+ sage: G.order()
2295
- sage: G.is_distance_regular(True) # long time
+ sage: G.is_distance_regular(True)
([310, 224, None], [None, 1, 35])
- sage: G = graphs.UstimenkoGraph(4,3) # long time
- sage: G.is_distance_regular(True) # long time
+ sage: G = graphs.UstimenkoGraph(4,3)
+ sage: G.is_distance_regular(True)
([390, 243, None], [None, 1, 130])
"""
from sage.graphs.graph_generators import graphs
@@ -652,14 +653,15 @@ def BilinearFormsGraph(const int d, const int e, const int q):
EXAMPLES::
+ sage: # needs sage.modules
sage: G = graphs.BilinearFormsGraph(3, 3, 2)
sage: G.is_distance_regular(True)
([49, 36, 16, None], [None, 1, 6, 28])
- sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s)
- sage: G.order() # not tested (due to above)
+ sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) # needs sage.rings.finite_rings
+ sage: G.order() # not tested (due to above) # needs sage.rings.finite_rings
19683
- sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time
- sage: G.is_distance_regular(True) # long time
+ sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time # needs sage.rings.finite_rings
+ sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings
([105, 84, 48, None], [None, 1, 6, 28])
REFERENCES:
@@ -669,6 +671,7 @@ def BilinearFormsGraph(const int d, const int e, const int q):
TESTS::
+ sage: # needs sage.modules
sage: G = graphs.BilinearFormsGraph(2,3,2)
sage: G.is_distance_regular(True)
([21, 12, None], [None, 1, 6])
@@ -754,10 +757,11 @@ def AlternatingFormsGraph(const int n, const int q):
TESTS::
- sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min)
- sage: G.order() # not tested (because of above)
+ sage: # needs sage.modules
+ sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) # needs sage.rings.finite_rings
+ sage: G.order() # not tested (because of above) # needs sage.rings.finite_rings
32768
- sage: G.is_distance_regular(True) # not tested (33 min)
+ sage: G.is_distance_regular(True) # not tested (33 min) # needs sage.rings.finite_rings
([651, 560, 256, None], [None, 1, 20, 336])
sage: G = graphs.AlternatingFormsGraph(4, 3)
sage: G.is_distance_regular(True)
@@ -840,11 +844,12 @@ def HermitianFormsGraph(const int n, const int r):
EXAMPLES::
+ sage: # needs sage.modules sage.rings.finite_rings
sage: G = graphs.HermitianFormsGraph(2, 2)
sage: G.is_distance_regular(True)
([5, 4, None], [None, 1, 2])
- sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min)
- sage: G.order() # not tested (bacuase of the above)
+ sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min)
+ sage: G.order() # not tested (bacuase of the above)
19683
REFERENCES:
@@ -853,6 +858,7 @@ def HermitianFormsGraph(const int n, const int r):
TESTS::
+ sage: # needs sage.modules sage.rings.finite_rings
sage: G = graphs.HermitianFormsGraph(3, 2)
sage: G.is_distance_regular(True)
([21, 20, 16, None], [None, 1, 2, 12])
@@ -1079,8 +1085,8 @@ def GrassmannGraph(const int q, const int n, const int input_e):
EXAMPLES::
- sage: G = graphs.GrassmannGraph(2, 4, 2)
- sage: G.is_distance_regular(True)
+ sage: G = graphs.GrassmannGraph(2, 4, 2) # needs sage.modules sage.rings.finite_rings
+ sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings
([18, 8, None], [None, 1, 9])
REFERENCES:
@@ -1089,8 +1095,9 @@ def GrassmannGraph(const int q, const int n, const int input_e):
TESTS::
- sage: G = graphs.GrassmannGraph(2, 6, 3) # long time
- sage: G.is_distance_regular(True) # long time
+ sage: # needs sage.modules sage.rings.finite_rings
+ sage: G = graphs.GrassmannGraph(2, 6, 3) # long time
+ sage: G.is_distance_regular(True) # long time
([98, 72, 32, None], [None, 1, 9, 49])
sage: G = graphs.GrassmannGraph(3, 4, 2)
sage: G.is_distance_regular(True)
@@ -1132,10 +1139,10 @@ def DoubleGrassmannGraph(const int q, const int e):
EXAMPLES::
- sage: G = graphs.DoubleGrassmannGraph(2,1)
- sage: G.diameter()
+ sage: G = graphs.DoubleGrassmannGraph(2,1) # needs sage.modules
+ sage: G.diameter() # needs sage.modules
3
- sage: G.is_distance_regular(True)
+ sage: G.is_distance_regular(True) # needs sage.modules
([3, 2, 2, None], [None, 1, 1, 3])
@@ -1145,15 +1152,16 @@ def DoubleGrassmannGraph(const int q, const int e):
TESTS::
+ sage: # needs sage.modules
sage: G = graphs.DoubleGrassmannGraph(5,1)
sage: G.order()
62
sage: G.is_distance_regular(True)
([6, 5, 5, None], [None, 1, 1, 6])
- sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time
- sage: G.order() # long time
+ sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time # needs sage.rings.finite_rings
+ sage: G.order() # long time # needs sage.rings.finite_rings
2420
- sage: G.is_distance_regular(True) # long time
+ sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings
([13, 12, 12, 9, 9, None], [None, 1, 1, 4, 4, 13])
"""
n = 2*e + 1
@@ -1187,10 +1195,10 @@ def is_from_GQ_spread(list arr):
sage: from sage.graphs.generators.distance_regular import \
....: is_from_GQ_spread, graph_from_GQ_spread
- sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125])
+ sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) # needs sage.libs.pari
(5, 25)
- sage: G = graph_from_GQ_spread(5, 25)
- sage: G.is_distance_regular(True)
+ sage: G = graph_from_GQ_spread(5, 25) # needs sage.libs.pari
+ sage: G.is_distance_regular(True) # needs sage.libs.pari
([125, 120, 1, None], [None, 1, 24, 125])
REFERENCES:
@@ -1202,9 +1210,9 @@ def is_from_GQ_spread(list arr):
sage: from sage.graphs.generators.distance_regular import \
....: is_from_GQ_spread
- sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343])
+ sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) # needs sage.libs.pari
(7, 49)
- sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343])
+ sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) # needs sage.libs.pari
False
Check that we don't get ``True`` for inexisting GQs::
@@ -1215,7 +1223,7 @@ def is_from_GQ_spread(list arr):
sage: t = 6
sage: [s * t, s * (t-1), 1, 1, t - 1, s * t]
[30, 25, 1, 1, 5, 30]
- sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30])
+ sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) # needs sage.libs.pari
False
"""
from sage.combinat.designs import design_catalog as designs
@@ -1258,8 +1266,8 @@ def graph_from_GQ_spread(const int s, const int t):
sage: from sage.graphs.generators.distance_regular import \
....: graph_from_GQ_spread
- sage: G = graph_from_GQ_spread(4, 16)
- sage: G.is_distance_regular(True)
+ sage: G = graph_from_GQ_spread(4, 16) # needs sage.libs.pari
+ sage: G.is_distance_regular(True) # needs sage.libs.pari
([64, 60, 1, None], [None, 1, 15, 64])
REFERENCES:
@@ -1270,11 +1278,11 @@ def graph_from_GQ_spread(const int s, const int t):
sage: from sage.graphs.generators.distance_regular import \
....: graph_from_GQ_spread, is_from_GQ_spread
- sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64])
+ sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) # needs sage.libs.pari
(4, 16)
- sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27]))
+ sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) # needs sage.libs.pari
Graph on 112 vertices
- sage: _.is_distance_regular(True)
+ sage: _.is_distance_regular(True) # needs sage.libs.pari
([27, 24, 1, None], [None, 1, 8, 27])
"""
from sage.combinat.designs import design_catalog as designs
@@ -1302,13 +1310,14 @@ def GeneralisedDodecagonGraph(const int s, const int t):
EXAMPLES::
- sage: G = graphs.GeneralisedDodecagonGraph(1, 5) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(1, 5)
+ sage: G.is_distance_regular(True)
([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6])
- sage: H = graphs.GeneralisedDodecagonGraph(5, 1) # optional - gap_packages internet
- sage: H.order() # optional - gap_packages internet
+ sage: H = graphs.GeneralisedDodecagonGraph(5, 1)
+ sage: H.order()
23436
- sage: H.is_distance_regular(True) # not tested (6 min); optional - gap_packages internet
+ sage: H.is_distance_regular(True) # not tested (6 min)
([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2])
.. NOTE::
@@ -1326,29 +1335,31 @@ def GeneralisedDodecagonGraph(const int s, const int t):
Test all graphs of order `(1, q)`::
- sage: G = graphs.GeneralisedDodecagonGraph(1, 4) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(1, 4)
+ sage: G.is_distance_regular(True)
([5, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 5])
- sage: G = graphs.GeneralisedDodecagonGraph(1, 3) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(1, 3)
+ sage: G.is_distance_regular(True)
([4, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 4])
- sage: G = graphs.GeneralisedDodecagonGraph(1, 2) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(1, 2)
+ sage: G.is_distance_regular(True)
([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3])
- sage: G = graphs.GeneralisedDodecagonGraph(1, 1) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(1, 1)
+ sage: G.is_distance_regular(True)
([2, 1, 1, 1, 1, 1, None], [None, 1, 1, 1, 1, 1, 2])
Now test all graphs of order `(q, 1)`::
- sage: G = graphs.GeneralisedDodecagonGraph(4, 1) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(4, 1)
+ sage: G.is_distance_regular(True)
([8, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 2])
- sage: G = graphs.GeneralisedDodecagonGraph(3, 1) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(3, 1)
+ sage: G.is_distance_regular(True)
([6, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 2])
- sage: G = graphs.GeneralisedDodecagonGraph(2, 1) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedDodecagonGraph(2, 1)
+ sage: G.is_distance_regular(True)
([4, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 2])
"""
from sage.arith.misc import is_prime_power
@@ -1407,15 +1418,16 @@ def GeneralisedOctagonGraph(const int s, const int t):
EXAMPLES::
- sage: G = graphs.GeneralisedOctagonGraph(1, 4)
- sage: G.is_distance_regular(True)
- ([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
- sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
- ([10, 8, 8, 8, None], [None, 1, 1, 1, 5])
- sage: G = graphs.GeneralisedOctagonGraph(5, 1)
- sage: G.is_distance_regular(True)
- ([10, 5, 5, 5, None], [None, 1, 1, 1, 2])
+ sage: # needs sage.libs.gap
+ sage: G = graphs.GeneralisedOctagonGraph(1, 4)
+ sage: G.is_distance_regular(True)
+ ([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
+ sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet
+ sage: G.is_distance_regular(True) # optional - gap_packages internet
+ ([10, 8, 8, 8, None], [None, 1, 1, 1, 5])
+ sage: G = graphs.GeneralisedOctagonGraph(5, 1)
+ sage: G.is_distance_regular(True)
+ ([10, 5, 5, 5, None], [None, 1, 1, 1, 2])
.. NOTE::
@@ -1430,11 +1442,11 @@ def GeneralisedOctagonGraph(const int s, const int t):
TESTS::
- sage: G = graphs.GeneralisedOctagonGraph(8, 64)
+ sage: G = graphs.GeneralisedOctagonGraph(8, 64) # needs sage.libs.gap
Traceback (most recent call last):
...
NotImplementedError: Graph would be too big
- sage: G = graphs.GeneralisedOctagonGraph(4, 16)
+ sage: G = graphs.GeneralisedOctagonGraph(4, 16) # needs sage.libs.gap
Traceback (most recent call last):
...
ValueError: generalised octagons of order (q, q^2) are known only for odd powers q of 2
@@ -1517,6 +1529,7 @@ def GeneralisedHexagonGraph(const int s, const int t):
EXAMPLES::
+ sage: # needs sage.libs.gap
sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_packages internet
sage: G.is_distance_regular(True) # optional - gap_packages internet
([30, 25, 25, None], [None, 1, 1, 6])
@@ -1539,17 +1552,18 @@ def GeneralisedHexagonGraph(const int s, const int t):
TESTS::
- sage: G = graphs.GeneralisedHexagonGraph(4, 4) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: # optional - gap_packages internet
+ sage: G = graphs.GeneralisedHexagonGraph(4, 4)
+ sage: G.is_distance_regular(True)
([20, 16, 16, None], [None, 1, 1, 5])
- sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedHexagonGraph(3, 3)
+ sage: G.is_distance_regular(True)
([12, 9, 9, None], [None, 1, 1, 4])
- sage: G = graphs.GeneralisedHexagonGraph(2, 2) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedHexagonGraph(2, 2)
+ sage: G.is_distance_regular(True)
([6, 4, 4, None], [None, 1, 1, 3])
- sage: G = graphs.GeneralisedHexagonGraph(2, 8) # optional - gap_packages internet
- sage: G.is_distance_regular(True) # optional - gap_packages internet
+ sage: G = graphs.GeneralisedHexagonGraph(2, 8)
+ sage: G.is_distance_regular(True)
([18, 16, 16, None], [None, 1, 1, 9])
"""
from sage.arith.misc import is_prime_power
@@ -1672,6 +1686,7 @@ def _extract_lines(G):
EXAMPLES::
+ sage: # needs sage.libs.gap
sage: from sage.graphs.generators.distance_regular import _extract_lines
sage: G = graphs.GeneralisedHexagonGraph(1, 8)
sage: lines = _extract_lines(G)
@@ -1739,16 +1754,17 @@ def _line_graph_generalised_polygon(H):
EXAMPLES::
- sage: from sage.graphs.generators.distance_regular import \
- ....: _line_graph_generalised_polygon
- sage: G = graphs.GeneralisedHexagonGraph(1, 8)
- sage: H = _line_graph_generalised_polygon(G)
- sage: H.is_distance_regular(True)
- ([16, 8, 8, None], [None, 1, 1, 2])
- sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet
- sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet
- sage: G.is_isomorphic(H) # optional - gap_packages internet
- True
+ sage: # needs sage.libs.gap
+ sage: from sage.graphs.generators.distance_regular import \
+ ....: _line_graph_generalised_polygon
+ sage: G = graphs.GeneralisedHexagonGraph(1, 8)
+ sage: H = _line_graph_generalised_polygon(G)
+ sage: H.is_distance_regular(True)
+ ([16, 8, 8, None], [None, 1, 1, 2])
+ sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet
+ sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet
+ sage: G.is_isomorphic(H) # optional - gap_packages internet
+ True
REFERENCES:
@@ -1792,9 +1808,9 @@ def _intersection_array_from_graph(G):
sage: from sage.graphs.generators.distance_regular import \
....: _intersection_array_from_graph
- sage: _intersection_array_from_graph(graphs.FosterGraph())
+ sage: _intersection_array_from_graph(graphs.FosterGraph()) # needs networkx
[3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3]
- sage: graphs.FosterGraph().is_distance_regular(True)
+ sage: graphs.FosterGraph().is_distance_regular(True) # needs networkx
([3, 2, 2, 2, 2, 1, 1, 1, None], [None, 1, 1, 1, 1, 2, 2, 2, 3])
sage: graphs.DartGraph().is_distance_regular()
False
@@ -1877,7 +1893,7 @@ def is_classical_parameters_graph(list array):
sage: G = graphs.HammingGraph(5, 4)
sage: G.is_distance_regular(True)
([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5])
- sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5])
+ sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) # needs sage.combinat
(5, 1, 0, 3, 2)
REFERENCES:
@@ -1890,12 +1906,12 @@ def is_classical_parameters_graph(list array):
sage: from sage.graphs.generators.distance_regular import \
....: is_classical_parameters_graph
- sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg
+ sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg # needs sage.combinat
False
sage: G = graphs.GossetGraph() # sporadic classical parameters graph
sage: G.is_distance_regular(True)
([27, 10, 1, None], [None, 1, 10, 27])
- sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27])
+ sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) # needs sage.combinat
False
"""
from sage.misc.functional import log
@@ -2101,7 +2117,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma):
Hamming Graph with parameters 3,4: Graph on 64 vertices
sage: G = _; G.is_distance_regular(True)
([9, 6, 3, None], [None, 1, 2, 3])
- sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3])
+ sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) # needs sage.combinat
(3, 1, 0, 3, 2)
Two families of graphs are not implemented yet::
@@ -2125,7 +2141,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma):
sage: graph_with_classical_parameters(3, 1, 2, 3, 3)
Half 4 Cube: Graph on 8 vertices
- sage: graph_with_classical_parameters(3, 2, 0, 2, 9)
+ sage: graph_with_classical_parameters(3, 2, 0, 2, 9) # needs sage.libs.gap
Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices
sage: graph_with_classical_parameters(3, 2, 2, 14, 7) # long time
Grassmann graph J_2(6, 3): Graph on 1395 vertices
@@ -2389,7 +2405,7 @@ def is_near_polygon(array):
sage: from sage.graphs.generators.distance_regular import (
....: is_near_polygon, near_polygon_graph)
- sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3])
+ sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) # needs sage.combinat
(2, 7)
sage: near_polygon_graph(2, 7)
Odd Graph with parameter 7: Graph on 1716 vertices
@@ -2403,19 +2419,20 @@ def is_near_polygon(array):
TESTS::
+ sage: # needs sage.combinat sage.libs.pari
sage: from sage.graphs.generators.distance_regular import (
....: is_near_polygon, near_polygon_graph)
sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7])
(4, (2, 2))
sage: near_polygon_graph(4, (2, 2))
Double Grassmann graph (5, 2, 2): Graph on 310 vertices
- sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3]))
+ sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.rings.finite_rings
Generalised hexagon of order (1, 2): Graph on 14 vertices
sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4])
(6, (4, 5))
sage: is_near_polygon([])
False
- sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph
+ sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph
False
"""
from sage.arith.misc import is_prime_power
@@ -2525,12 +2542,11 @@ def near_polygon_graph(family, params):
EXAMPLES::
- sage: from sage.graphs.generators.distance_regular import (
- ....: is_near_polygon, near_polygon_graph)
- sage: near_polygon_graph(*is_near_polygon([6, 5, 5, 4, 4, 3, 3, 2, 2, \
- ....: 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]))
+ sage: from sage.graphs.generators.distance_regular import is_near_polygon, near_polygon_graph
+ sage: near_polygon_graph(*is_near_polygon( # needs sage.combinat
+ ....: [6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]))
Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices
- sage: G=_; G.is_distance_regular(True)
+ sage: G=_; G.is_distance_regular(True) # needs sage.combinat
([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],
[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
@@ -2541,6 +2557,7 @@ def near_polygon_graph(family, params):
TESTS::
+ sage: # needs sage.combinat
sage: near_polygon_graph(12, 9)
Traceback (most recent call last):
...
@@ -2695,8 +2712,8 @@ def distance_regular_graph(list arr, existence=False, check=True):
sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True)
True
- sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False)
- sage: G.is_distance_regular(True)
+ sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) # needs sage.combinat sage.modules
+ sage: G.is_distance_regular(True) # needs sage.combinat sage.modules
([12, 11, 10, 7, None], [None, 1, 2, 5, 12])
REFERENCES:
@@ -2705,16 +2722,18 @@ def distance_regular_graph(list arr, existence=False, check=True):
TESTS::
- sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3],
- ....: existence=True)
+ sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], # needs sage.combinat
+ ....: existence=True)
True
sage: graphs.distance_regular_graph([3, 2, 2, 1, 2, 1, 1, 2, 2, 3],
- ....: existence=True)
+ ....: existence=True)
False
sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_packages
Generalised hexagon of order (2, 8): Graph on 819 vertices
+
+ sage: # needs sage.combinat
sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2,
- ....: 1, 2, 3, 4, 5, 6, 7])
+ ....: 1, 2, 3, 4, 5, 6, 7])
Hamming Graph with parameters 7,3: Graph on 2187 vertices
sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30])
Graph on 1024 vertices
diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py
index 30396e1ab9e..3ef2c3a5556 100644
--- a/src/sage/graphs/generators/families.py
+++ b/src/sage/graphs/generators/families.py
@@ -40,13 +40,13 @@ def JohnsonGraph(n, k):
The Johnson graph is a Hamiltonian graph::
sage: g = graphs.JohnsonGraph(7, 3)
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
Every Johnson graph is vertex transitive::
sage: g = graphs.JohnsonGraph(6, 4)
- sage: g.is_vertex_transitive()
+ sage: g.is_vertex_transitive() # needs sage.groups
True
The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser
@@ -452,7 +452,7 @@ def HammingGraph(n, q, X=None):
True
sage: g.is_regular()
True
- sage: g.is_vertex_transitive() # optional - sage.groups
+ sage: g.is_vertex_transitive() # needs sage.groups
True
A Hamming graph with parameters (1,q) is isomorphic to the
@@ -526,9 +526,9 @@ def BalancedTree(r, h):
A balanced tree whose root node has degree `r = 2`, and of height
`h = 1`, has order 3 and size 2::
- sage: G = graphs.BalancedTree(2, 1); G # optional - networkx
+ sage: G = graphs.BalancedTree(2, 1); G # needs networkx
Balanced tree: Graph on 3 vertices
- sage: G.order(); G.size() # optional - networkx
+ sage: G.order(); G.size() # needs networkx
3
2
sage: r = 2; h = 1
@@ -539,21 +539,22 @@ def BalancedTree(r, h):
Plot a balanced tree of height 5, whose root node has degree `r = 3`::
- sage: G = graphs.BalancedTree(3, 5) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.BalancedTree(3, 5) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
A tree is bipartite. If its vertex set is finite, then it is planar. ::
+ sage: # needs networkx
sage: r = randint(2, 5); h = randint(1, 7)
- sage: T = graphs.BalancedTree(r, h) # optional - networkx
- sage: T.is_bipartite() # optional - networkx
+ sage: T = graphs.BalancedTree(r, h)
+ sage: T.is_bipartite()
True
- sage: T.is_planar() # optional - networkx
+ sage: T.is_planar()
True
- sage: v = (r^(h + 1) - 1) / (r - 1) # optional - networkx
- sage: T.order() == v # optional - networkx
+ sage: v = (r^(h + 1) - 1) / (r - 1)
+ sage: T.order() == v
True
- sage: T.size() == v - 1 # optional - networkx
+ sage: T.size() == v - 1
True
TESTS:
@@ -562,13 +563,13 @@ def BalancedTree(r, h):
has degree `r \geq 2`, but the construction degenerates
gracefully::
- sage: graphs.BalancedTree(1, 10) # optional - networkx
+ sage: graphs.BalancedTree(1, 10) # needs networkx
Balanced tree: Graph on 11 vertices
Similarly, we usually want the tree must have height `h \geq 1`
but the algorithm also degenerates gracefully here::
- sage: graphs.BalancedTree(3, 0) # optional - networkx
+ sage: graphs.BalancedTree(3, 0) # needs networkx
Balanced tree: Graph on 1 vertex
"""
import networkx
@@ -627,11 +628,13 @@ def BarbellGraph(n1, n2):
True
sage: K_n1 = graphs.CompleteGraph(n1)
sage: P_n2 = graphs.PathGraph(n2)
- sage: s_K = g.subgraph_search(K_n1, induced=True) # optional - sage.modules
- sage: s_P = g.subgraph_search(P_n2, induced=True) # optional - sage.modules
- sage: K_n1.is_isomorphic(s_K) # optional - sage.modules
+
+ sage: # needs sage.modules
+ sage: s_K = g.subgraph_search(K_n1, induced=True)
+ sage: s_P = g.subgraph_search(P_n2, induced=True)
+ sage: K_n1.is_isomorphic(s_K)
True
- sage: P_n2.is_isomorphic(s_P) # optional - sage.modules
+ sage: P_n2.is_isomorphic(s_P)
True
TESTS::
@@ -640,7 +643,7 @@ def BarbellGraph(n1, n2):
sage: g = graphs.BarbellGraph(n1, n2)
sage: g.num_verts() == 2 * n1 + n2
True
- sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1
+ sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 # needs sage.symbolic
True
sage: g.is_connected()
True
@@ -717,7 +720,7 @@ def LollipopGraph(n1, n2):
sage: g = graphs.LollipopGraph(n1, n2)
sage: g.num_verts() == n1 + n2
True
- sage: g.num_edges() == binomial(n1, 2) + n2
+ sage: g.num_edges() == binomial(n1, 2) + n2 # needs sage.symbolic
True
sage: g.is_connected()
True
@@ -1027,10 +1030,10 @@ def chang_graphs():
sage: c3c5 = graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5))
sage: c8 = graphs.CycleGraph(8)
- sage: s = [K8.subgraph_search(c8).edges(sort=False), # optional - sage.modules
+ sage: s = [K8.subgraph_search(c8).edges(sort=False), # needs sage.modules
....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)],
....: K8.subgraph_search(c3c5).edges(sort=False)]
- sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # optional - sage.modules
+ sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # needs sage.modules
....: for x, G in zip(s, chang_graphs)]
[True, True, True]
@@ -1076,51 +1079,54 @@ def CirculantGraph(n, adjacency):
EXAMPLES: Compare plotting using the predefined layout and
networkx::
- sage: import networkx # optional - networkx
- sage: n = networkx.cycle_graph(23) # optional - networkx
- sage: spring23 = Graph(n) # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: n = networkx.cycle_graph(23)
+ sage: spring23 = Graph(n)
sage: posdict23 = graphs.CirculantGraph(23,2)
- sage: spring23.show() # long time # optional - networkx
+ sage: spring23.show() # long time
sage: posdict23.show() # long time
We next view many cycle graphs as a Sage graphics array. First we
use the ``CirculantGraph`` constructor, which fills in
the position dictionary::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.CirculantGraph(i+4, i+1)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Compare to plotting with the spring-layout algorithm::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.cycle_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Passing a 1 into adjacency should give the cycle.
::
- sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6)
+ sage: graphs.CirculantGraph(6,1) == graphs.CycleGraph(6)
True
sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false)
[(0, 1),
@@ -1187,27 +1193,28 @@ def CubeGraph(n, embedding=1):
Plot several `n`-cubes in a Sage Graphics Array::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(6):
....: k = graphs.CubeGraph(i+1)
....: g.append(k)
...
- sage: for i in range(2): # optional - sage.plot
+ sage: for i in range(2):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show(figsize=[6,4]) # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show(figsize=[6,4]) # long time
Use the plot options to display larger `n`-cubes::
sage: g = graphs.CubeGraph(9, embedding=1)
- sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot
+ sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot
sage: g = graphs.CubeGraph(9, embedding=2)
- sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot
+ sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot
AUTHORS:
@@ -1306,9 +1313,9 @@ def GoethalsSeidelGraph(k, r):
EXAMPLES::
- sage: graphs.GoethalsSeidelGraph(3,3)
+ sage: graphs.GoethalsSeidelGraph(3,3) # needs sage.modules
Graph on 28 vertices
- sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True)
+ sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) # needs sage.modules
(28, 15, 6, 10)
"""
from sage.combinat.designs.bibd import balanced_incomplete_block_design
@@ -1353,8 +1360,8 @@ def DorogovtsevGoltsevMendesGraph(n):
EXAMPLES::
- sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # optional - networkx
- sage: G.size() # optional - networkx
+ sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # needs networkx
+ sage: G.size() # needs networkx
6561
REFERENCE:
@@ -1438,24 +1445,25 @@ def FriendshipGraph(n):
The first few friendship graphs. ::
+ sage: # needs sage.plot
sage: A = []; B = []
sage: for i in range(9):
....: g = graphs.FriendshipGraph(i + 1)
....: A.append(g)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for j in range(3):
....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False))
....: B.append(n)
- sage: G = graphics_array(B) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(B)
+ sage: G.show() # long time
For `n = 1`, the friendship graph `F_1` is isomorphic to the cycle
graph `C_3`, whose visual representation is a triangle. ::
sage: G = graphs.FriendshipGraph(1); G
Friendship graph: Graph on 3 vertices
- sage: G.show() # long time # optional - sage.plot
+ sage: G.show() # long time # needs sage.plot
sage: G.is_isomorphic(graphs.CycleGraph(3))
True
@@ -1538,7 +1546,7 @@ def FuzzyBallGraph(partition, q):
EXAMPLES::
sage: F = graphs.FuzzyBallGraph([3,1],2)
- sage: F.adjacency_matrix(vertices=list(F)) # optional - sage.modules
+ sage: F.adjacency_matrix(vertices=list(F)) # needs sage.modules
[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
@@ -1554,9 +1562,9 @@ def FuzzyBallGraph(partition, q):
Laplacian::
sage: m = 4; q = 2; k = 2
- sage: g_list = [graphs.FuzzyBallGraph(p,q) # optional - sage.combinat sage.modules
+ sage: g_list = [graphs.FuzzyBallGraph(p,q) # needs sage.combinat sage.modules
....: for p in Partitions(m, length=k)]
- sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), optional - sage.combinat sage.modules
+ sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), needs sage.combinat sage.modules
....: vertices=list(g)).charpoly()
....: for g in g_list)
{x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4
@@ -1588,15 +1596,15 @@ def FibonacciTree(n):
EXAMPLES::
- sage: g = graphs.FibonacciTree(3)
- sage: g.is_tree()
+ sage: g = graphs.FibonacciTree(3) # needs sage.libs.pari
+ sage: g.is_tree() # needs sage.libs.pari
True
::
- sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ]
- sage: l2 = list(fibonacci_sequence(2,8))
- sage: l1 == l2
+ sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] # needs sage.libs.pari
+ sage: l2 = list(fibonacci_sequence(2,8)) # needs sage.libs.pari
+ sage: l1 == l2 # needs sage.libs.pari
True
AUTHORS:
@@ -2074,15 +2082,15 @@ def HararyGraph(k, n):
9
sage: h.size()
23
- sage: h.vertex_connectivity()
+ sage: h.vertex_connectivity() # needs sage.numerical.mip
5
TESTS:
Connectivity of some Harary graphs::
- sage: n=10
- sage: for k in range(2,n):
+ sage: n = 10
+ sage: for k in range(2,n): # needs sage.numerical.mip
....: g = graphs.HararyGraph(k,n)
....: if k != g.vertex_connectivity():
....: print("Connectivity of Harary graphs not satisfied.")
@@ -2207,31 +2215,32 @@ def LCFGraph(n, shift_list, repeats):
EXAMPLES::
- sage: G = graphs.LCFGraph(4, [2,-2], 2) # optional - networkx
- sage: G.is_isomorphic(graphs.TetrahedralGraph()) # optional - networkx
+ sage: G = graphs.LCFGraph(4, [2,-2], 2) # needs networkx
+ sage: G.is_isomorphic(graphs.TetrahedralGraph()) # needs networkx
True
::
- sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # optional - networkx
- sage: G.is_isomorphic(graphs.DodecahedralGraph()) # optional - networkx
+ sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # needs networkx
+ sage: G.is_isomorphic(graphs.DodecahedralGraph()) # needs networkx
True
::
- sage: G = graphs.LCFGraph(14, [5,-5], 7) # optional - networkx
- sage: G.is_isomorphic(graphs.HeawoodGraph()) # optional - networkx
+ sage: G = graphs.LCFGraph(14, [5,-5], 7) # needs networkx
+ sage: G.is_isomorphic(graphs.HeawoodGraph()) # needs networkx
True
The largest cubic nonplanar graph of diameter three::
- sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, # optional - networkx
+ sage: # needs networkx
+ sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7,
....: -10,-7,6,-5,7,-10,-7,5,-6,7], 1)
- sage: G.degree() # optional - networkx
+ sage: G.degree()
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
- sage: G.diameter() # optional - networkx
+ sage: G.diameter()
3
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs sage.plot
PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the
middle, as described above.
@@ -2538,14 +2547,14 @@ def PaleyGraph(q):
EXAMPLES::
- sage: G = graphs.PaleyGraph(9); G
+ sage: G = graphs.PaleyGraph(9); G # needs sage.rings.finite_rings
Paley graph with parameter 9: Graph on 9 vertices
- sage: G.is_regular()
+ sage: G.is_regular() # needs sage.rings.finite_rings
True
A Paley graph is always self-complementary::
- sage: G.is_self_complementary()
+ sage: G.is_self_complementary() # needs sage.rings.finite_rings
True
TESTS:
@@ -2588,9 +2597,9 @@ def PasechnikGraph(n):
EXAMPLES::
- sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # optional - sage.combinat sage.modules
+ sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # needs sage.combinat sage.modules
(225, 98, 43, 42)
- sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, optional - sage.combinat sage.modules
+ sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, needs sage.combinat sage.modules
(361, 162, 73, 72)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not tested
(1225, 578, 273, 272)
@@ -2630,11 +2639,15 @@ def SquaredSkewHadamardMatrixGraph(n):
EXAMPLES::
- sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True)
+ sage: # needs sage.modules
+ sage: G = graphs.SquaredSkewHadamardMatrixGraph(4)
+ sage: G.is_strongly_regular(parameters=True)
(225, 112, 55, 56)
- sage: graphs.SquaredSkewHadamardMatrixGraph(5).is_strongly_regular(parameters=True) # long time
+ sage: G = graphs.SquaredSkewHadamardMatrixGraph(5)
+ sage: G.is_strongly_regular(parameters=True) # long time
(361, 180, 89, 90)
- sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # not tested
+ sage: G = graphs.SquaredSkewHadamardMatrixGraph(9)
+ sage: G.is_strongly_regular(parameters=True) # not tested
(1225, 612, 305, 306)
TESTS::
@@ -2680,13 +2693,14 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n):
EXAMPLES::
- sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)
- sage: g.is_strongly_regular(parameters=True)
+ sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) # needs sage.modules
+ sage: g.is_strongly_regular(parameters=True) # needs sage.modules
(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendant
- sage: twograph_descendant(g,0).is_strongly_regular(parameters=True)
+ sage: twograph_descendant(g, 0).is_strongly_regular(parameters=True) # needs sage.modules
(225, 112, 55, 56)
- sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True)
+ sage: gc = g.complement() # needs sage.modules
+ sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True) # needs sage.modules
(225, 112, 55, 56)
TESTS::
@@ -2817,7 +2831,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True):
::
sage: H = graphs.HanoiTowerGraph(3, 4, labels=False, positions=False)
- sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # optional - sage.groups
+ sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # needs sage.groups
True
sage: H.chromatic_number()
3
@@ -3065,10 +3079,10 @@ def petersen_family(generate=False):
The two different inputs generate the same graphs::
sage: F1 = graphs.petersen_family(generate=False)
- sage: F2 = graphs.petersen_family(generate=True)
+ sage: F2 = graphs.petersen_family(generate=True) # needs sage.modules
sage: F1 = [g.canonical_label().graph6_string() for g in F1]
- sage: F2 = [g.canonical_label().graph6_string() for g in F2]
- sage: set(F1) == set(F2)
+ sage: F2 = [g.canonical_label().graph6_string() for g in F2] # needs sage.modules
+ sage: set(F1) == set(F2) # needs sage.modules
True
"""
from sage.graphs.generators.smallgraphs import PetersenGraph
@@ -3183,6 +3197,7 @@ def SierpinskiGasketGraph(n):
EXAMPLES::
+ sage: # needs sage.modules
sage: s4 = graphs.SierpinskiGasketGraph(4); s4
Graph on 42 vertices
sage: s4.size()
@@ -3272,14 +3287,15 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None):
of `G` are isomorphic to Hanoi Tower graphs::
sage: k = randint(1, 5)
- sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k)
+ sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) # needs sage.modules
sage: H = graphs.HanoiTowerGraph(3, k)
- sage: S.is_isomorphic(H)
+ sage: S.is_isomorphic(H) # needs sage.modules
True
The generalized Sierpinski graph of dimension `k` of any graph `G` with `n`
vertices and `m` edges has `n^k` vertices and `m\sum_{i=0}^{k-1}n^i` edges::
+ sage: # needs sage.modules
sage: n = randint(2, 6)
sage: k = randint(1, 5)
sage: G = graphs.RandomGNP(n, .5)
@@ -3302,14 +3318,14 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None):
sage: G = graphs.HouseGraph()
sage: G.get_pos() is not None
True
- sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic
- sage: H.get_pos() is not None # optional - sage.symbolic
+ sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic
+ sage: H.get_pos() is not None # needs sage.symbolic
True
sage: G = Graph([(0, 1)])
sage: G.get_pos() is not None
False
- sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic
- sage: H.get_pos() is not None # optional - sage.symbolic
+ sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic
+ sage: H.get_pos() is not None # needs sage.symbolic
False
.. PLOT::
@@ -3318,6 +3334,7 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None):
TESTS::
+ sage: # needs sage.modules
sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3)
Generalized Sierpinski Graph of Graph on 0 vertices of dimension 3: Graph on 0 vertices
sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False)
@@ -3397,46 +3414,49 @@ def WheelGraph(n):
We view many wheel graphs with a Sage Graphics Array, first with this
constructor (i.e., the position dictionary filled)::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.WheelGraph(i+3)
....: g.append(k)
...
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Next, using the spring-layout algorithm::
- sage: import networkx # optional - networkx
+ sage: # needs networkx sage.plot
+ sage: import networkx
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: spr = networkx.wheel_graph(i+3)
....: k = Graph(spr)
....: g.append(k)
...
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
...
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
Compare the plotting::
- sage: n = networkx.wheel_graph(23) # optional - networkx
- sage: spring23 = Graph(n) # optional - networkx
+ sage: # needs networkx sage.plot
+ sage: n = networkx.wheel_graph(23)
+ sage: spring23 = Graph(n)
sage: posdict23 = graphs.WheelGraph(23)
- sage: spring23.show() # long time # optional - networkx
+ sage: spring23.show() # long time
sage: posdict23.show() # long time
"""
from sage.graphs.generators.basic import CycleGraph
@@ -3740,9 +3760,10 @@ def RingedTree(k, vertex_labels=True):
EXAMPLES::
+ sage: # needs networkx
sage: G = graphs.RingedTree(5)
- sage: P = G.plot(vertex_labels=False, vertex_size=10) # optional - sage.plot
- sage: P.show() # long time # optional - sage.plot
+ sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs sage.plot
+ sage: P.show() # long time # needs sage.plot
sage: G.vertices(sort=True)
['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01',
'010', '0100', '0101', '011', '0110', '0111', '1', '10', '100',
@@ -3755,8 +3776,8 @@ def RingedTree(k, vertex_labels=True):
Traceback (most recent call last):
...
ValueError: The number of levels must be >= 1.
- sage: G = graphs.RingedTree(5, vertex_labels = False)
- sage: G.vertices(sort=True)
+ sage: G = graphs.RingedTree(5, vertex_labels=False) # needs networkx
+ sage: G.vertices(sort=True) # needs networkx
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
"""
@@ -3828,13 +3849,13 @@ def MathonPseudocyclicMergingGraph(M, t):
sage: G = mer(ES(3), 2) # long time
sage: G.is_strongly_regular(parameters=True) # long time
(784, 297, 116, 110)
- sage: G = mer(ES(2), 2)
+ sage: G = mer(ES(2), 2) # needs sage.libs.gap
Traceback (most recent call last):
...
AssertionError...
- sage: M = ES(3)
- sage: M = [M[1],M[0],M[2],M[3]]
- sage: G = mer(M, 2)
+ sage: M = ES(3) # needs sage.libs.gap
+ sage: M = [M[1],M[0],M[2],M[3]] # needs sage.libs.gap
+ sage: G = mer(M, 2) # needs sage.libs.gap
Traceback (most recent call last):
...
AssertionError...
@@ -3889,13 +3910,14 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None):
Using default ``G`` and ``L``. ::
sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph
- sage: G=MathonPseudocyclicStronglyRegularGraph(1); G
+ sage: G = MathonPseudocyclicStronglyRegularGraph(1); G # needs sage.modules sage.rings.finite_rings
Mathon's PC SRG on 45 vertices: Graph on 45 vertices
- sage: G.is_strongly_regular(parameters=True)
+ sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings
(45, 22, 10, 11)
Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). ::
+ sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings
sage: G = graphs.PaleyGraph(9)
sage: a = G.automorphism_group(partition=[sorted(G)])
sage: it = (x for x in a.normal_subgroups() if x.order() == 9)
@@ -3915,21 +3937,22 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None):
[-4 -3 -2 2 3 4 -1 0 1]
[-2 -4 -3 4 2 3 1 -1 0]
+ sage: # needs sage.modules sage.rings.finite_rings
sage: G.relabel(range(9))
- sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L)
+ sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) # needs sage.groups sage.libs.gap
sage: G3x3.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
- sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
+ sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
- sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2)
+ sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2)
sage: G9.is_strongly_regular(parameters=True)
(441, 220, 109, 110)
- sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
+ sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9
TESTS::
- sage: graphs.MathonPseudocyclicStronglyRegularGraph(5)
+ sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) # needs sage.modules
Traceback (most recent call last):
...
ValueError: 21 must be a sum of two squares!...
@@ -4123,18 +4146,20 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False):
EXAMPLES::
- sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True)
+ sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings
(378, 116, 34, 36)
- sage: phi={(2,(0,2)):0,(1,(1,3)):1,(0,(0,3)):1,(2,(1,2)):1,(1,(1,
- ....: 2)):0,(0,(0,2)):0,(3,(0,3)):0,(3,(1,3)):1}
- sage: graphs.MuzychukS6Graph(2,2,Phi=phi).is_strongly_regular(parameters=True)
+ sage: phi = {(2,(0,2)):0, (1,(1,3)):1, (0,(0,3)):1, (2,(1,2)):1, # needs sage.modules
+ ....: (1,(1,2)):0, (0,(0,2)):0, (3,(0,3)):0, (3,(1,3)):1}
+ sage: graphs.MuzychukS6Graph(2, 2, # needs sage.modules sage.rings.finite_rings
+ ....: Phi=phi).is_strongly_regular(parameters=True)
(16, 5, 0, 2)
TESTS::
- sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True)
+ sage: # needs sage.modules
+ sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
(16, 5, 0, 2)
- sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True)
+ sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
(378, 116, 34, 36)
sage: graphs.MuzychukS6Graph(3,2)
Traceback (most recent call last):
@@ -4148,11 +4173,11 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False):
Traceback (most recent call last):
...
AssertionError: d must be at least 2
- sage: graphs.MuzychukS6Graph(3,3,Phi=42)
+ sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.rings.finite_rings
Traceback (most recent call last):
...
AssertionError: Phi must be a dictionary or 'random' or 'fixed'
- sage: graphs.MuzychukS6Graph(3,3,Sigma=42)
+ sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.rings.finite_rings
Traceback (most recent call last):
...
ValueError: Sigma must be 'random' or 'fixed'
diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py
index f2cd8b248ad..0de3715e0e1 100644
--- a/src/sage/graphs/generators/intersection.py
+++ b/src/sage/graphs/generators/intersection.py
@@ -417,9 +417,10 @@ def OrthogonalArrayBlockGraph(k, n, OA=None):
EXAMPLES::
- sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G
+ sage: # needs sage.modules
+ sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G # needs sage.schemes
OA(5,5): Graph on 25 vertices
- sage: G.is_strongly_regular(parameters=True)
+ sage: G.is_strongly_regular(parameters=True) # needs sage.schemes
(25, 20, 15, 20)
sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G
OA(4,10): Graph on 100 vertices
@@ -428,20 +429,21 @@ def OrthogonalArrayBlockGraph(k, n, OA=None):
Two graphs built from different orthogonal arrays are also different::
- sage: k=4;n=10
+ sage: # needs sage.modules
+ sage: k = 4; n = 10
sage: OAa = designs.orthogonal_arrays.build(k,n)
sage: OAb = [[(x+1)%n for x in R] for R in OAa]
sage: set(map(tuple,OAa)) == set(map(tuple,OAb))
False
- sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa)
- sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb)
+ sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa)
+ sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb)
sage: Ga == Gb
False
As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are
isomorphic::
- sage: Ga.is_isomorphic(Gb)
+ sage: Ga.is_isomorphic(Gb) # needs sage.modules
True
But there are examples of `OA(k,n)` for which the resulting graphs are not
@@ -455,31 +457,31 @@ def OrthogonalArrayBlockGraph(k, n, OA=None):
....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1],
....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3],
....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]]
- sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0)
- sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
- sage: g0.is_isomorphic(g1)
+ sage: g0 = graphs.OrthogonalArrayBlockGraph(3, 4, oa0) # needs sage.modules
+ sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1) # needs sage.modules
+ sage: g0.is_isomorphic(g1) # needs sage.modules
False
But nevertheless isospectral::
- sage: g0.spectrum()
+ sage: g0.spectrum() # needs sage.modules
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
- sage: g1.spectrum()
+ sage: g1.spectrum() # needs sage.modules
[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
Note that the graph ``g0`` is actually isomorphic to the affine polar graph
`VO^+(4,2)`::
- sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
+ sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) # needs sage.modules
True
TESTS::
- sage: G = graphs.OrthogonalArrayBlockGraph(4,6)
+ sage: G = graphs.OrthogonalArrayBlockGraph(4,6) # needs sage.modules
Traceback (most recent call last):
...
NotImplementedError: I don't know how to build an OA(4,6)!
- sage: G = graphs.OrthogonalArrayBlockGraph(8,2)
+ sage: G = graphs.OrthogonalArrayBlockGraph(8,2) # needs sage.modules
Traceback (most recent call last):
...
ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) !
diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py
index f36fa8ecf66..38e070a054a 100644
--- a/src/sage/graphs/generators/platonic_solids.py
+++ b/src/sage/graphs/generators/platonic_solids.py
@@ -39,28 +39,29 @@ def TetrahedralGraph():
Construct and show a Tetrahedral graph::
sage: g = graphs.TetrahedralGraph()
- sage: g.show() # long time
+ sage: g.show() # long time # needs sage.plot
The following example requires networkx::
- sage: import networkx as NX # optional - networkx
+ sage: import networkx as NX # needs networkx
Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted
with the spring-layout algorithm below in a Sage graphics array::
+ sage: # needs networkx sage.plot
sage: tetra_pos = graphs.TetrahedralGraph()
- sage: tetra_spring = Graph(NX.tetrahedral_graph()) # optional - networkx
+ sage: tetra_spring = Graph(NX.tetrahedral_graph())
sage: wheel = graphs.WheelGraph(4)
sage: complete = graphs.CompleteGraph(4)
- sage: g = [tetra_pos, tetra_spring, wheel, complete] # optional - networkx
+ sage: g = [tetra_pos, tetra_spring, wheel, complete]
sage: j = []
- sage: for i in range(2): # optional - networkx sage.plot
+ sage: for i in range(2):
....: n = []
....: for m in range(2):
....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
pos = {0: (0, 0),
@@ -88,23 +89,24 @@ def HexahedralGraph():
Construct and show a Hexahedral graph::
sage: g = graphs.HexahedralGraph()
- sage: g.show() # long time
+ sage: g.show() # long time # needs sage.plot
Create several hexahedral graphs in a Sage graphics array. They will be
drawn differently due to the use of the spring-layout algorithm::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.HexahedralGraph()
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]}
pos = {
@@ -145,18 +147,19 @@ def OctahedralGraph():
Create several octahedral graphs in a Sage graphics array They will be drawn
differently due to the use of the spring-layout algorithm::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.OctahedralGraph()
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]}
G = Graph(adj, format='dict_of_lists', name="Octahedron")
@@ -184,23 +187,24 @@ def IcosahedralGraph():
Construct and show an Octahedral graph::
sage: g = graphs.IcosahedralGraph()
- sage: g.show() # long time
+ sage: g.show() # long time # needs sage.plot
Create several icosahedral graphs in a Sage graphics array. They will be
drawn differently due to the use of the spring-layout algorithm::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.IcosahedralGraph()
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9],
3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11],
@@ -228,23 +232,24 @@ def DodecahedralGraph():
Construct and show a Dodecahedral graph::
sage: g = graphs.DodecahedralGraph()
- sage: g.show() # long time
+ sage: g.show() # long time # needs sage.plot
Create several dodecahedral graphs in a Sage graphics array They will be
drawn differently due to the use of the spring-layout algorithm::
+ sage: # needs sage.plot
sage: g = []
sage: j = []
sage: for i in range(9):
....: k = graphs.DodecahedralGraph()
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17],
5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11],
diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py
index 288515ac397..5dab4071f49 100644
--- a/src/sage/graphs/generators/random.py
+++ b/src/sage/graphs/generators/random.py
@@ -78,13 +78,13 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'):
sage: for i in range(9):
....: k = graphs.RandomGNP(i+3,.43)
....: g.append(k)
- sage: for i in range(3): # optional - sage.plot
+ sage: for i in range(3): # needs sage.plot
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - sage.plot
- sage: G.show() # long time # optional - sage.plot
+ sage: G = graphics_array(j) # needs sage.plot
+ sage: G.show() # long time # needs sage.plot
sage: graphs.RandomGNP(4,1)
Complete graph: Graph on 4 vertices
@@ -97,7 +97,7 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'):
sage: set_random_seed(0)
sage: graphs.RandomGNP(50,.2, algorithm="Sage").size()
243
- sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # optional - networkx
+ sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # needs networkx
279 # 32-bit
209 # 64-bit
"""
@@ -149,35 +149,36 @@ def RandomBarabasiAlbert(n, m, seed=None):
We show the edge list of a random graph on 6 nodes with `m = 2`::
- sage: G = graphs.RandomBarabasiAlbert(6,2) # optional - networkx
- sage: G.order(), G.size() # optional - networkx
+ sage: G = graphs.RandomBarabasiAlbert(6,2) # needs networkx
+ sage: G.order(), G.size() # needs networkx
(6, 8)
- sage: G.degree_sequence() # random # optional - networkx
+ sage: G.degree_sequence() # random # needs networkx
[4, 3, 3, 2, 2, 2]
We plot a random graph on 12 nodes with `m = 3`::
- sage: ba = graphs.RandomBarabasiAlbert(12,3) # optional - networkx
- sage: ba.show() # long time # optional - networkx sage.plot
+ sage: ba = graphs.RandomBarabasiAlbert(12,3) # needs networkx
+ sage: ba.show() # long time # needs networkx sage.plot
We view many random graphs using a graphics array::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(1,10): # optional - networkx
+ sage: for i in range(1,10):
....: k = graphs.RandomBarabasiAlbert(i+3, 3)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
When `m = 1`, the generated graph is a tree::
- sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # optional - networkx
+ sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # needs networkx
True
"""
if seed is None:
@@ -206,35 +207,36 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None):
EXAMPLES::
- sage: g = graphs.RandomBipartite(5, 2, 0.5) # optional - numpy
- sage: g.vertices(sort=True) # optional - numpy
+ sage: g = graphs.RandomBipartite(5, 2, 0.5) # needs numpy
+ sage: g.vertices(sort=True) # needs numpy
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]
TESTS::
- sage: g = graphs.RandomBipartite(5, -3, 0.5) # optional - numpy
+ sage: g = graphs.RandomBipartite(5, -3, 0.5) # needs numpy
Traceback (most recent call last):
...
ValueError: n1 and n2 should be integers strictly greater than 0
- sage: g = graphs.RandomBipartite(5, 3, 1.5) # optional - numpy
+ sage: g = graphs.RandomBipartite(5, 3, 1.5) # needs numpy
Traceback (most recent call last):
...
ValueError: parameter p is a probability, and so should be a real value between 0 and 1
:trac:`12155`::
- sage: graphs.RandomBipartite(5, 6, .2).complement() # optional - numpy
+ sage: graphs.RandomBipartite(5, 6, .2).complement() # needs numpy
complement(Random bipartite graph of order 5+6 with edge probability 0.200000000000000): Graph on 11 vertices
Test assigned positions::
- sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() # optional - numpy
+ sage: # needs numpy
+ sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos()
{(0, 0): (1, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)}
- sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() # optional - numpy
+ sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos()
{(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (1, 0.0)}
- sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos() # optional - numpy
+ sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos()
{(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)}
- sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos() # optional - numpy
+ sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos()
"""
if not (p >= 0 and p <= 1):
@@ -512,7 +514,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None):
sage: m, k = 6, 4
sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True)
sage: from sage.combinat.designs.incidence_structures import IncidenceStructure
- sage: IncidenceStructure(IS)
+ sage: IncidenceStructure(IS) # needs sage.modules
Incidence structure with 19 points and 6 blocks
sage: m*(k-1)+1
19
@@ -679,28 +681,29 @@ def RandomGNM(n, m, dense=False, seed=None):
We show the edge list of a random graph on 5 nodes with 10 edges::
- sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # optional - networkx
+ sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # needs networkx
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
We plot a random graph on 12 nodes with m = 12::
- sage: gnm = graphs.RandomGNM(12, 12) # optional - networkx
- sage: gnm.show() # long time # optional - networkx sage.plot
+ sage: gnm = graphs.RandomGNM(12, 12) # needs networkx
+ sage: gnm.show() # long time # needs networkx sage.plot
We view many random graphs using a graphics array::
+ sage: # needs networkx sage.plot
sage: g = []
sage: j = []
- sage: for i in range(9): # optional - networkx
+ sage: for i in range(9):
....: k = graphs.RandomGNM(i+3, i^2-i)
....: g.append(k)
- sage: for i in range(3): # optional - networkx sage.plot
+ sage: for i in range(3):
....: n = []
....: for m in range(3):
....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
....: j.append(n)
- sage: G = graphics_array(j) # optional - networkx sage.plot
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphics_array(j)
+ sage: G.show() # long time
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
@@ -737,33 +740,34 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None):
We check that the generated graph contains a cycle of order `n`::
- sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) # optional - networkx
- sage: G.order() # optional - networkx
+ sage: # needs networkx
+ sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2)
+ sage: G.order()
7
- sage: C7 = graphs.CycleGraph(7) # optional - networkx
- sage: G.subgraph_search(C7) # optional - networkx
+ sage: C7 = graphs.CycleGraph(7)
+ sage: G.subgraph_search(C7)
Subgraph of (): Graph on 7 vertices
- sage: G.diameter() <= C7.diameter() # optional - networkx
+ sage: G.diameter() <= C7.diameter()
True
::
- sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
TESTS:
We check that when `k = 2` and `p = 0`, the generated graph is a cycle::
- sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # optional - networkx
- sage: G.is_cycle() # optional - networkx
+ sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # needs networkx
+ sage: G.is_cycle() # needs networkx
True
We check that when `k = 4` and `p = 0`, the generated graph is a circulant
graph of parameters ``[1, 2]``::
- sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # optional - networkx
- sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # optional - networkx
+ sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # needs networkx
+ sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # needs networkx
True
REFERENCE:
@@ -807,8 +811,8 @@ def RandomHolmeKim(n, m, p, seed=None):
EXAMPLES::
- sage: G = graphs.RandomHolmeKim(12, 3, .3) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.RandomHolmeKim(12, 3, .3) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
REFERENCE:
@@ -952,8 +956,8 @@ def connecting_nodes(T, l):
sage: from sage.graphs.generators.random import connecting_nodes
sage: T = graphs.RandomTree(10)
- sage: S = connecting_nodes(T, 5) # optional - numpy
- sage: len(S) # optional - numpy
+ sage: S = connecting_nodes(T, 5) # needs numpy
+ sage: len(S) # needs numpy
10
"""
from sage.combinat.permutation import Permutations
@@ -1178,8 +1182,8 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s
sage: T = RandomChordalGraph(20, algorithm="growing", k=5)
sage: T.is_chordal()
True
- sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # optional - numpy
- sage: T.is_chordal() # optional - numpy
+ sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # needs numpy
+ sage: T.is_chordal() # needs numpy
True
sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5)
sage: T.is_chordal()
@@ -1303,13 +1307,14 @@ def RandomLobster(n, p, q, seed=None):
We check a random graph with 12 backbone
nodes and probabilities `p = 0.7` and `q = 0.3`::
- sage: G = graphs.RandomLobster(12, 0.7, 0.3) # optional - networkx
- sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx
- sage: G.delete_vertices(leaves) # caterpillar # optional - networkx
- sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx
- sage: G.delete_vertices(leaves) # path # optional - networkx
- sage: s = G.degree_sequence() # optional - networkx
- sage: if G: # optional - networkx
+ sage: # needs networkx
+ sage: G = graphs.RandomLobster(12, 0.7, 0.3)
+ sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
+ sage: G.delete_vertices(leaves) # caterpillar
+ sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
+ sage: G.delete_vertices(leaves) # path
+ sage: s = G.degree_sequence()
+ sage: if G:
....: if G.num_verts() == 1:
....: assert s == [0]
....: else:
@@ -1318,8 +1323,8 @@ def RandomLobster(n, p, q, seed=None):
::
- sage: G = graphs.RandomLobster(9, .6, .3) # optional - networkx
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G = graphs.RandomLobster(9, .6, .3) # needs networkx
+ sage: G.show() # long time # needs networkx sage.plot
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
@@ -1434,16 +1439,16 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None):
We check that the generated graph is a tree::
- sage: G = graphs.RandomTreePowerlaw(10, 3) # optional - networkx
- sage: G.is_tree() # optional - networkx
+ sage: G = graphs.RandomTreePowerlaw(10, 3) # needs networkx
+ sage: G.is_tree() # needs networkx
True
- sage: G.order(), G.size() # optional - networkx
+ sage: G.order(), G.size() # needs networkx
(10, 9)
::
- sage: G = graphs.RandomTreePowerlaw(15, 2) # optional - networkx
- sage: if G: # random output, long time # optional - networkx sage.plot
+ sage: G = graphs.RandomTreePowerlaw(15, 2) # needs networkx
+ sage: if G: # random output # long time, needs networkx sage.plot
....: G.show()
"""
if seed is None:
@@ -1474,16 +1479,16 @@ def RandomRegular(d, n, seed=None):
We check that a random graph with 8 nodes each of degree 3 is 3-regular::
- sage: G = graphs.RandomRegular(3, 8) # optional - networkx
- sage: G.is_regular(k=3) # optional - networkx
+ sage: G = graphs.RandomRegular(3, 8) # needs networkx
+ sage: G.is_regular(k=3) # needs networkx
True
- sage: G.degree_histogram() # optional - networkx
+ sage: G.degree_histogram() # needs networkx
[0, 0, 0, 8]
::
- sage: G = graphs.RandomRegular(3, 20) # optional - networkx
- sage: if G: # random output, long time # optional - networkx sage.plot
+ sage: G = graphs.RandomRegular(3, 20) # needs networkx
+ sage: if G: # random output # long time, needs networkx sage.plot
....: G.show()
REFERENCES:
@@ -1524,10 +1529,10 @@ def RandomShell(constructor, seed=None):
EXAMPLES::
- sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # optional - networkx
- sage: G.order(), G.size() # optional - networkx
+ sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # needs networkx
+ sage: G.order(), G.size() # needs networkx
(30, 52)
- sage: G.show() # long time # optional - networkx sage.plot
+ sage: G.show() # long time # needs networkx sage.plot
"""
if seed is None:
seed = int(current_randstate().long_seed() % sys.maxsize)
@@ -1889,7 +1894,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None):
True
sage: G.girth()
3
- sage: G.plot(vertex_size=0, vertex_labels=False) # optional - sage.plot
+ sage: G.plot(vertex_size=0, vertex_labels=False) # needs sage.plot
Graphics object consisting of 13 graphics primitives
sage: H = graphs.RandomTriangulation(7, k=5)
@@ -2005,16 +2010,16 @@ def blossoming_contour(t, shift=0, seed=None):
sage: print(blossoming_contour(BinaryTrees(1).an_element()))
[('i', 0), ('xb',), ('i', 0), ('xb',), ('i', 0)]
- sage: t = BinaryTrees(2).random_element() # optional - sage.combinat
- sage: print(blossoming_contour(t)) # random # optional - sage.combinat
+ sage: t = BinaryTrees(2).random_element() # needs sage.combinat
+ sage: print(blossoming_contour(t)) # random # needs sage.combinat
[('i', 0), ('xb',), ('i', 0), ('n', 2), ('i', 1), ('xb',), ('i', 1),
('xb',), ('i', 1), ('n', 2), ('x',), ('n', 2), ('i', 0)]
- sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # optional - sage.combinat
+ sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # needs sage.combinat
21
- sage: w.count(('xb',)) # optional - sage.combinat
+ sage: w.count(('xb',)) # needs sage.combinat
4
- sage: w.count(('x',)) # optional - sage.combinat
+ sage: w.count(('x',)) # needs sage.combinat
2
TESTS::
@@ -2098,17 +2103,18 @@ def RandomBicubicPlanar(n, seed=None):
EXAMPLES::
+ sage: # needs sage.combinat
sage: n = randint(200, 300)
- sage: G = graphs.RandomBicubicPlanar(n) # optional - sage.combinat
- sage: G.order() == 2*n # optional - sage.combinat
+ sage: G = graphs.RandomBicubicPlanar(n)
+ sage: G.order() == 2*n
True
- sage: G.size() == 3*n # optional - sage.combinat
+ sage: G.size() == 3*n
True
- sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) # optional - sage.combinat
+ sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)
True
- sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], # optional - sage.combinat
+ sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'],
....: 'blue': [v for v in G.vertices(sort=False) if v[0] != 'n']}
- sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # optional - sage.combinat sage.plot
+ sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.plot
Graphics object consisting of ... graphics primitives
.. PLOT::
@@ -2210,23 +2216,24 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None):
When using twice the same seed, the vertices get the same positions::
+ sage: # needs scipy
sage: from sage.misc.randstate import current_randstate
sage: seed = current_randstate().seed()
- sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) # optional - scipy
- sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) # optional - scipy
- sage: H.is_subgraph(G, induced=False) # optional - scipy
+ sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed)
+ sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed)
+ sage: H.is_subgraph(G, induced=False)
True
- sage: H.size() <= G.size() # optional - scipy
+ sage: H.size() <= G.size()
True
- sage: Gpos = G.get_pos() # optional - scipy
- sage: Hpos = H.get_pos() # optional - scipy
- sage: all(Gpos[u] == Hpos[u] for u in G) # optional - scipy
+ sage: Gpos = G.get_pos()
+ sage: Hpos = H.get_pos()
+ sage: all(Gpos[u] == Hpos[u] for u in G)
True
When the radius is more than `\sqrt{2 \text{side}}`, the graph is a clique::
- sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # optional - scipy
- sage: G.is_clique() # optional - scipy
+ sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # needs scipy
+ sage: G.is_clique() # needs scipy
True
"""
if seed is not None:
diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py
index 36275b2ce57..e58248f05c8 100644
--- a/src/sage/graphs/generators/smallgraphs.py
+++ b/src/sage/graphs/generators/smallgraphs.py
@@ -139,21 +139,22 @@ def HarriesGraph(embedding=1):
EXAMPLES::
- sage: g = graphs.HarriesGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.HarriesGraph()
+ sage: g.order()
70
- sage: g.size() # optional - networkx
+ sage: g.size()
105
- sage: g.girth() # optional - networkx
+ sage: g.girth()
10
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
6
- sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot
- sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
+ sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot
TESTS::
- sage: graphs.HarriesGraph(embedding=3) # optional - networkx
+ sage: graphs.HarriesGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -257,25 +258,26 @@ def HarriesWongGraph(embedding=1):
EXAMPLES::
- sage: g = graphs.HarriesWongGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.HarriesWongGraph()
+ sage: g.order()
70
- sage: g.size() # optional - networkx
+ sage: g.size()
105
- sage: g.girth() # optional - networkx
+ sage: g.girth()
10
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
6
- sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # optional - networkx sage.groups
- sage: g.show(figsize=[15, 15], partition=orbits) # long time # optional - networkx sage.groups sage.plot
+ sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # needs sage.groups
+ sage: g.show(figsize=[15, 15], partition=orbits) # long time # needs sage.groups sage.plot
Alternative embedding::
- sage: graphs.HarriesWongGraph(embedding=2).show() # long time # optional - networkx sage.plot
+ sage: graphs.HarriesWongGraph(embedding=2).show() # long time # needs networkx sage.plot
TESTS::
- sage: graphs.HarriesWongGraph(embedding=3) # optional - networkx
+ sage: graphs.HarriesWongGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -453,12 +455,13 @@ def Cell600(embedding=1):
EXAMPLES::
- sage: g = graphs.Cell600() # long time
- sage: g.size() # long time
+ sage: # long time
+ sage: g = graphs.Cell600()
+ sage: g.size()
720
- sage: g.is_regular(12) # long time
+ sage: g.is_regular(12)
True
- sage: g.is_vertex_transitive() # long time
+ sage: g.is_vertex_transitive()
True
"""
from sage.rings.polynomial.polynomial_ring import polygen
@@ -528,12 +531,13 @@ def Cell120():
EXAMPLES::
- sage: g = graphs.Cell120() # long time
- sage: g.size() # long time
+ sage: # long time
+ sage: g = graphs.Cell120()
+ sage: g.size()
1200
- sage: g.is_regular(4) # long time
+ sage: g.is_regular(4)
True
- sage: g.is_vertex_transitive() # long time
+ sage: g.is_vertex_transitive()
True
"""
from sage.rings.polynomial.polynomial_ring import polygen
@@ -679,7 +683,7 @@ def HallJankoGraph(from_string=True):
sage: g = graphs.HallJankoGraph()
sage: g.is_regular(36)
True
- sage: g.is_vertex_transitive() # optional - sage.groups
+ sage: g.is_vertex_transitive() # needs sage.groups
True
Is it really strongly regular with parameters 14, 12? ::
@@ -702,7 +706,7 @@ def HallJankoGraph(from_string=True):
2
sage: g.girth()
3
- sage: factor(g.characteristic_polynomial())
+ sage: factor(g.characteristic_polynomial()) # needs sage.libs.pari sage.modules
(x - 36) * (x - 6)^36 * (x + 4)^63
TESTS::
@@ -804,20 +808,21 @@ def Balaban10Cage(embedding=1):
EXAMPLES::
- sage: g = graphs.Balaban10Cage() # optional - networkx
- sage: g.girth() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.Balaban10Cage()
+ sage: g.girth()
10
- sage: g.chromatic_number() # optional - networkx
+ sage: g.chromatic_number()
2
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
6
- sage: g.is_hamiltonian() # optional - networkx
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
- sage: g.show(figsize=[10,10]) # long time # optional - networkx sage.plot
+ sage: g.show(figsize=[10,10]) # long time # needs sage.plot
TESTS::
- sage: graphs.Balaban10Cage(embedding='foo') # optional - networkx
+ sage: graphs.Balaban10Cage(embedding='foo') # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -897,21 +902,21 @@ def Balaban11Cage(embedding=1):
11
sage: g.diameter()
8
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
64
Our many embeddings::
sage: g1 = graphs.Balaban11Cage(embedding=1)
- sage: g2 = graphs.Balaban11Cage(embedding=2)
- sage: g3 = graphs.Balaban11Cage(embedding=3)
- sage: g1.show(figsize=[10,10]) # long time # optional - sage.plot
- sage: g2.show(figsize=[10,10]) # long time # optional - sage.plot
- sage: g3.show(figsize=[10,10]) # long time # optional - sage.plot
+ sage: g2 = graphs.Balaban11Cage(embedding=2) # needs networkx
+ sage: g3 = graphs.Balaban11Cage(embedding=3) # needs networkx
+ sage: g1.show(figsize=[10,10]) # long time # needs sage.plot
+ sage: g2.show(figsize=[10,10]) # long time # needs networkx sage.plot
+ sage: g3.show(figsize=[10,10]) # long time # needs sage.plot
Proof that the embeddings are the same graph::
- sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic
+ sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic # needs networkx
True
TESTS::
@@ -1071,7 +1076,7 @@ def BidiakisCube():
It is a Hamiltonian graph with diameter 3 and girth 4::
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
sage: g.diameter()
3
@@ -1084,11 +1089,11 @@ def BidiakisCube():
sage: g.is_planar()
True
- sage: char_poly = g.characteristic_polynomial()
- sage: x = char_poly.parent()('x')
- sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2
+ sage: char_poly = g.characteristic_polynomial() # needs sage.modules
+ sage: x = char_poly.parent()('x') # needs sage.modules
+ sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 # needs sage.modules
True
- sage: g.chromatic_number()
+ sage: g.chromatic_number() # needs sage.modules
3
"""
edge_dict = {
@@ -1114,26 +1119,27 @@ def BiggsSmithGraph(embedding=1):
Basic properties::
- sage: g = graphs.BiggsSmithGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.BiggsSmithGraph()
+ sage: g.order()
102
- sage: g.size() # optional - networkx
+ sage: g.size()
153
- sage: g.girth() # optional - networkx
+ sage: g.girth()
9
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
7
- sage: g.automorphism_group().cardinality() # long time # optional - networkx
+ sage: g.automorphism_group().cardinality() # long time
2448
- sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
The other embedding::
- sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # optional - networkx
+ sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # needs networkx
TESTS::
- sage: graphs.BiggsSmithGraph(embedding='xyzzy') # optional - networkx
+ sage: graphs.BiggsSmithGraph(embedding='xyzzy') # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -1199,16 +1205,16 @@ def BlanusaFirstSnarkGraph():
EXAMPLES::
- sage: g = graphs.BlanusaFirstSnarkGraph() # optional - sage.groups
- sage: g.order() # optional - sage.groups
+ sage: g = graphs.BlanusaFirstSnarkGraph()
+ sage: g.order()
18
- sage: g.size() # optional - sage.groups
+ sage: g.size()
27
- sage: g.diameter() # optional - sage.groups
+ sage: g.diameter()
4
- sage: g.girth() # optional - sage.groups
+ sage: g.girth()
5
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
8
"""
g = Graph({17: [4, 7, 1], 0: [5], 3: [8], 13: [9], 12: [16],
@@ -1234,16 +1240,16 @@ def BlanusaSecondSnarkGraph():
EXAMPLES::
- sage: g = graphs.BlanusaSecondSnarkGraph() # optional - sage.groups
- sage: g.order() # optional - sage.groups
+ sage: g = graphs.BlanusaSecondSnarkGraph()
+ sage: g.order()
18
- sage: g.size() # optional - sage.groups
+ sage: g.size()
27
- sage: g.diameter() # optional - sage.groups
+ sage: g.diameter()
4
- sage: g.girth() # optional - sage.groups
+ sage: g.girth()
5
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
4
"""
c0 = (-1, 0)
@@ -1312,15 +1318,15 @@ def BrinkmannGraph():
The Brinkmann graph is also Hamiltonian with chromatic number 4::
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
sage: G.chromatic_number()
4
Its automorphism group is isomorphic to `D_7`::
- sage: ag = G.automorphism_group()
- sage: ag.is_isomorphic(DihedralGroup(7))
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(7)) # needs sage.groups
True
"""
edge_dict = {
@@ -1361,18 +1367,17 @@ def BrouwerHaemersGraph():
EXAMPLES::
- sage: g = graphs.BrouwerHaemersGraph() # optional - sage.modules
- sage: g # optional - sage.modules
+ sage: g = graphs.BrouwerHaemersGraph(); g # needs sage.modules
Brouwer-Haemers: Graph on 81 vertices
It is indeed strongly regular with parameters `(81,20,1,6)`::
- sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.modules
+ sage: g.is_strongly_regular(parameters=True) # long time # needs sage.modules sage.rings.finite_rings
(81, 20, 1, 6)
Its has as eigenvalues `20,2` and `-7`::
- sage: set(g.spectrum()) == {20,2,-7} # optional - sage.modules
+ sage: set(g.spectrum()) == {20,2,-7} # needs sage.modules sage.rings.finite_rings
True
"""
from sage.rings.finite_rings.finite_field_constructor import FiniteField
@@ -1419,16 +1424,17 @@ def BuckyBall():
The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky
Ball polyhedron, but this is much slower::
- sage: g = polytopes.buckyball().vertex_graph() # optional - sage.geometry.polyhedron
- sage: g.remove_loops() # optional - sage.geometry.polyhedron
+ sage: # needs sage.geometry.polyhedron sage.rings.number_field
+ sage: g = polytopes.buckyball().vertex_graph()
+ sage: g.remove_loops()
sage: h = graphs.BuckyBall()
- sage: g.is_isomorphic(h) # optional - sage.geometry.polyhedron
+ sage: g.is_isomorphic(h)
True
The graph is returned along with an attractive embedding::
sage: g = graphs.BuckyBall() # long time
- sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time # optional - sage.plot
+ sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time, needs sage.plot
"""
edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58),
(2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12),
@@ -1573,11 +1579,11 @@ def DoubleStarSnark():
45
sage: g.chromatic_number()
3
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
False
- sage: g.automorphism_group().cardinality()
+ sage: g.automorphism_group().cardinality() # needs sage.groups
80
- sage: g.show() # optional - sage.plot
+ sage: g.show() # needs sage.plot
"""
d = {0: [1, 14, 15],
1: [0, 2, 11],
@@ -1641,7 +1647,7 @@ def MeredithGraph():
4
sage: g.chromatic_number()
3
- sage: g.is_hamiltonian() # long time
+ sage: g.is_hamiltonian() # long time # needs sage.numerical.mip
False
"""
g = Graph(name="Meredith Graph")
@@ -1735,12 +1741,13 @@ def CameronGraph():
EXAMPLES::
- sage: g = graphs.CameronGraph() # optional - sage.groups
- sage: g.order() # optional - sage.groups
+ sage: # needs sage.groups
+ sage: g = graphs.CameronGraph()
+ sage: g.order()
231
- sage: g.size() # optional - sage.groups
+ sage: g.size()
3465
- sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.groups
+ sage: g.is_strongly_regular(parameters=True) # long time
(231, 30, 9, 3)
"""
from sage.groups.perm_gps.permgroup_named import MathieuGroup
@@ -1804,9 +1811,9 @@ def ChvatalGraph():
TESTS::
- sage: import networkx # optional - networkx
+ sage: import networkx # needs networkx
sage: G = graphs.ChvatalGraph()
- sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # optional - networkx
+ sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # needs networkx
True
"""
edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9],
@@ -1828,7 +1835,7 @@ def ClebschGraph():
EXAMPLES::
sage: g = graphs.ClebschGraph()
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
1920
sage: g.girth()
4
@@ -1836,7 +1843,7 @@ def ClebschGraph():
4
sage: g.diameter()
2
- sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
"""
g = Graph(pos={})
x = 0
@@ -1865,7 +1872,7 @@ def CoxeterGraph():
EXAMPLES::
sage: g = graphs.CoxeterGraph()
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
336
sage: g.girth()
7
@@ -1873,7 +1880,7 @@ def CoxeterGraph():
3
sage: g.diameter()
4
- sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
"""
g = Graph({
27: [6, 22, 14],
@@ -1904,11 +1911,11 @@ def DejterGraph():
EXAMPLES::
- sage: g = graphs.DejterGraph(); g # optional - sage.rings.finite_rings
+ sage: g = graphs.DejterGraph(); g # needs sage.rings.finite_rings
Dejter Graph: Graph on 112 vertices
- sage: g.is_regular(k=6) # optional - sage.rings.finite_rings
+ sage: g.is_regular(k=6) # needs sage.rings.finite_rings
True
- sage: g.girth() # optional - sage.rings.finite_rings
+ sage: g.girth() # needs sage.rings.finite_rings
4
"""
from sage.graphs.generators.families import CubeGraph
@@ -1931,10 +1938,10 @@ def DesarguesGraph():
EXAMPLES::
sage: D = graphs.DesarguesGraph()
- sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # optional - networkx
- sage: D.is_isomorphic(L) # optional - networkx
+ sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # needs networkx
+ sage: D.is_isomorphic(L) # needs networkx
True
- sage: D.show() # long time # optional - sage.plot
+ sage: D.show() # long time # needs sage.plot
"""
from sage.graphs.generators.families import GeneralizedPetersenGraph
G = GeneralizedPetersenGraph(10, 3)
@@ -1973,8 +1980,8 @@ def DurerGraph():
Its automorphism group is isomorphic to `D_6`::
- sage: ag = G.automorphism_group()
- sage: ag.is_isomorphic(DihedralGroup(6))
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups
True
"""
from sage.graphs.generators.families import GeneralizedPetersenGraph
@@ -2012,7 +2019,7 @@ def DyckGraph():
sage: G.is_planar()
False
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
sage: G.is_bipartite()
True
@@ -2030,12 +2037,12 @@ def DyckGraph():
sage: G.chromatic_number()
2
- sage: G.automorphism_group().cardinality()
+ sage: G.automorphism_group().cardinality() # needs sage.groups
192
It is a non-integral graph as it has irrational eigenvalues::
- sage: G.characteristic_polynomial().factor()
+ sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules
(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6
It is a toroidal graph, and its embedding on a torus is dual to an embedding
@@ -2085,22 +2092,23 @@ def HortonGraph():
EXAMPLES::
- sage: g = graphs.HortonGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.HortonGraph()
+ sage: g.order()
96
- sage: g.size() # optional - networkx
+ sage: g.size()
144
- sage: g.radius() # optional - networkx
+ sage: g.radius()
10
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
10
- sage: g.girth() # optional - networkx
+ sage: g.girth()
6
- sage: g.automorphism_group().cardinality() # optional - networkx
+ sage: g.automorphism_group().cardinality()
96
- sage: g.chromatic_number() # optional - networkx
+ sage: g.chromatic_number()
2
- sage: g.is_hamiltonian() # not tested -- veeeery long # optional - networkx
+ sage: g.is_hamiltonian() # not tested (veeeery long) # needs sage.numerical.mip
False
"""
g = Graph(name="Horton Graph")
@@ -2160,14 +2168,14 @@ def EllinghamHorton54Graph():
It is 3-connected and bipartite::
- sage: g.vertex_connectivity() # not tested - too long
+ sage: g.vertex_connectivity() # not tested - too long
3
sage: g.is_bipartite()
True
It is not Hamiltonian::
- sage: g.is_hamiltonian() # not tested - too long
+ sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip
False
... and it has a nice drawing ::
@@ -2237,23 +2245,23 @@ def EllinghamHorton78Graph():
It is 3-connected and bipartite::
- sage: g.vertex_connectivity() # not tested - too long
+ sage: g.vertex_connectivity() # not tested (too long)
3
sage: g.is_bipartite()
True
It is not Hamiltonian::
- sage: g.is_hamiltonian() # not tested - too long
+ sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip
False
... and it has a nice drawing ::
- sage: g.show(figsize=[10,10]) # not tested - too long
+ sage: g.show(figsize=[10,10]) # not tested (too long)
TESTS::
- sage: g.show(figsize=[10, 10]) # not tested - too long
+ sage: g.show(figsize=[10, 10]) # not tested (too long)
"""
g = Graph({
0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9],
@@ -2321,7 +2329,7 @@ def ErreraGraph():
The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and
chromatic number 4::
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
sage: G.radius()
3
@@ -2343,8 +2351,8 @@ def ErreraGraph():
The automorphism group of the Errera graph is isomorphic to the dihedral
group of order 20::
- sage: ag = G.automorphism_group()
- sage: ag.is_isomorphic(DihedralGroup(10))
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(10)) # needs sage.groups
True
"""
edge_dict = {
@@ -2374,17 +2382,18 @@ def F26AGraph():
EXAMPLES::
- sage: g = graphs.F26AGraph(); g # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.F26AGraph(); g
F26A Graph: Graph on 26 vertices
- sage: g.order(), g.size() # optional - networkx
+ sage: g.order(), g.size()
(26, 39)
- sage: g.automorphism_group().cardinality() # optional - networkx
+ sage: g.automorphism_group().cardinality()
78
- sage: g.girth() # optional - networkx
+ sage: g.girth()
6
- sage: g.is_bipartite() # optional - networkx
+ sage: g.is_bipartite()
True
- sage: g.characteristic_polynomial().factor() # optional - networkx
+ sage: g.characteristic_polynomial().factor()
(x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6
"""
from sage.graphs.generators.families import LCFGraph
@@ -2435,26 +2444,27 @@ def FolkmanGraph():
EXAMPLES::
- sage: g = graphs.FolkmanGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.FolkmanGraph()
+ sage: g.order()
20
- sage: g.size() # optional - networkx
+ sage: g.size()
40
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
4
- sage: g.girth() # optional - networkx
+ sage: g.girth()
4
- sage: g.charpoly().factor() # optional - networkx
+ sage: g.charpoly().factor()
(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4
- sage: g.chromatic_number() # optional - networkx
+ sage: g.chromatic_number()
2
- sage: g.is_eulerian() # optional - networkx
+ sage: g.is_eulerian()
True
- sage: g.is_hamiltonian() # optional - networkx
+ sage: g.is_hamiltonian() # needs sage.numerical_mip
True
- sage: g.is_vertex_transitive() # optional - networkx
+ sage: g.is_vertex_transitive()
False
- sage: g.is_bipartite() # optional - networkx
+ sage: g.is_bipartite()
True
"""
from sage.graphs.generators.families import LCFGraph
@@ -2471,18 +2481,19 @@ def FosterGraph():
EXAMPLES::
- sage: g = graphs.FosterGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.FosterGraph()
+ sage: g.order()
90
- sage: g.size() # optional - networkx
+ sage: g.size()
135
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
8
- sage: g.girth() # optional - networkx
+ sage: g.girth()
10
- sage: g.automorphism_group().cardinality() # optional - networkx
+ sage: g.automorphism_group().cardinality()
4320
- sage: g.is_hamiltonian() # optional - networkx
+ sage: g.is_hamiltonian() # needs sage.numerical_mip
True
"""
from sage.graphs.generators.families import LCFGraph
@@ -2514,7 +2525,7 @@ def FranklinGraph():
The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter
3, and girth 4::
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical_mip
True
sage: G.is_bipartite()
True
@@ -2565,18 +2576,18 @@ def FruchtGraph():
EXAMPLES::
- sage: FRUCHT = graphs.FruchtGraph() # optional - networkx
- sage: FRUCHT # optional - networkx
+ sage: FRUCHT = graphs.FruchtGraph()
+ sage: FRUCHT
Frucht graph: Graph on 12 vertices
- sage: FRUCHT.graph6_string() # optional - networkx
+ sage: FRUCHT.graph6_string()
'KhCKM?_EGK?L'
- sage: (graphs.FruchtGraph()).show() # long time # optional - networkx
+ sage: (graphs.FruchtGraph()).show() # long time # needs networkx
TESTS::
- sage: import networkx # optional - networkx
- sage: G = graphs.FruchtGraph() # optional - networkx
- sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: G = graphs.FruchtGraph()
+ sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # needs networkx
True
"""
edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9],
@@ -2624,8 +2635,8 @@ def GoldnerHararyGraph():
sage: G.chromatic_number()
4
- sage: ag = G.automorphism_group()
- sage: ag.is_isomorphic(DihedralGroup(6))
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups
True
"""
edge_dict = {
@@ -2668,12 +2679,12 @@ def GolombGraph():
and 18 edges. It has chromatic number 4, diameter 3, radius 2 and
girth 3. It can be drawn in the plane as a unit distance graph::
- sage: G = graphs.GolombGraph(); G # optional - sage.symbolic
+ sage: G = graphs.GolombGraph(); G # needs sage.symbolic
Golomb graph: Graph on 10 vertices
- sage: pos = G.get_pos() # optional - sage.symbolic
+ sage: pos = G.get_pos() # needs sage.symbolic
sage: def dist2(u, v):
....: return (u[0]-v[0])**2 + (u[1]-v[1])**2
- sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # optional - sage.symbolic
+ sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # needs sage.symbolic
True
"""
edge_dict = {
@@ -2713,6 +2724,7 @@ def GrayGraph(embedding=1):
EXAMPLES::
+ sage: # needs networkx
sage: g = graphs.GrayGraph()
sage: g.order()
54
@@ -2722,12 +2734,12 @@ def GrayGraph(embedding=1):
8
sage: g.diameter()
6
- sage: g.show(figsize=[10, 10]) # long time
- sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
+ sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot
TESTS::
- sage: graphs.GrayGraph(embedding=3)
+ sage: graphs.GrayGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1, 2, or 3
@@ -2762,7 +2774,7 @@ def GrotzschGraph():
sage: G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
sage: G.order()
11
@@ -2786,8 +2798,8 @@ def GrotzschGraph():
sage: G.chromatic_number()
4
- sage: ag = G.automorphism_group()
- sage: ag.is_isomorphic(DihedralGroup(5))
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(5)) # needs sage.groups
True
"""
edges = [(0, u) for u in range(1, 6)]
@@ -2836,9 +2848,9 @@ def HeawoodGraph():
TESTS::
- sage: import networkx # optional - networkx
+ sage: import networkx # needs networkx
sage: G = graphs.HeawoodGraph()
- sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # optional - networkx
+ sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # needs networkx
True
"""
edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9],
@@ -2888,8 +2900,8 @@ def HerschelGraph():
sage: G.chromatic_number()
2
- sage: ag = G.automorphism_group() # optional - sage.groups
- sage: ag.is_isomorphic(DihedralGroup(6)) # optional - sage.groups
+ sage: ag = G.automorphism_group() # needs sage.groups
+ sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups
True
"""
edge_dict = {
@@ -2919,9 +2931,9 @@ def GritsenkoGraph():
EXAMPLES::
- sage: H = graphs.GritsenkoGraph(); H # optional - sage.groups
+ sage: H = graphs.GritsenkoGraph(); H # needs sage.groups
Gritsenko strongly regular graph: Graph on 65 vertices
- sage: H.is_strongly_regular(parameters=True) # optional - sage.groups
+ sage: H.is_strongly_regular(parameters=True) # needs sage.groups
(65, 32, 15, 16)
"""
from sage.groups.perm_gps.permgroup import PermutationGroup
@@ -3000,13 +3012,13 @@ def HigmanSimsGraph(relabel=True):
which is of index 2 and is simple. It is known as the Higman-Sims group::
sage: H = graphs.HigmanSimsGraph()
- sage: G = H.automorphism_group() # optional - sage.groups
- sage: g = G.order(); g # optional - sage.groups
+ sage: G = H.automorphism_group() # needs sage.groups
+ sage: g = G.order(); g # needs sage.groups
88704000
- sage: K = G.normal_subgroups()[1] # optional - sage.groups
- sage: K.is_simple() # optional - sage.groups
+ sage: K = G.normal_subgroups()[1] # needs sage.groups
+ sage: K.is_simple() # needs sage.groups
True
- sage: g//K.order() # optional - sage.groups
+ sage: g//K.order() # needs sage.groups
2
AUTHOR:
@@ -3186,13 +3198,13 @@ def HoffmanGraph():
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()
True
- sage: g.is_hamiltonian() # long time
+ sage: g.is_hamiltonian() # long time # needs sage.numerical.mip
True
sage: g.radius()
3
sage: g.diameter()
4
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
48
"""
g = Graph({
@@ -3231,11 +3243,11 @@ def HoltGraph():
Holt graph: Graph on 27 vertices
sage: g.is_regular()
True
- sage: g.is_vertex_transitive() # optional - sage.groups
+ sage: g.is_vertex_transitive() # needs sage.groups
True
sage: g.chromatic_number()
3
- sage: g.is_hamiltonian() # long time
+ sage: g.is_hamiltonian() # long time # needs sage.numerical.mip
True
sage: g.radius()
3
@@ -3243,7 +3255,7 @@ def HoltGraph():
3
sage: g.girth()
5
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
54
"""
g = Graph(loops=False, name="Holt graph", pos={})
@@ -3295,9 +3307,9 @@ def KrackhardtKiteGraph():
TESTS::
- sage: import networkx # optional - networkx
+ sage: import networkx # needs networkx
sage: G = graphs.KrackhardtKiteGraph()
- sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # optional - networkx
+ sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # needs networkx
True
"""
edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6],
@@ -3324,7 +3336,7 @@ def Klein3RegularGraph():
(56, 84)
sage: g.girth()
7
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
336
sage: g.chromatic_number()
3
@@ -3357,7 +3369,7 @@ def Klein7RegularGraph():
(24, 84)
sage: g.girth()
3
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
336
sage: g.chromatic_number()
4
@@ -3413,21 +3425,22 @@ def LjubljanaGraph(embedding=1):
EXAMPLES::
- sage: g = graphs.LjubljanaGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.LjubljanaGraph()
+ sage: g.order()
112
- sage: g.size() # optional - networkx
+ sage: g.size()
168
- sage: g.girth() # optional - networkx
+ sage: g.girth()
10
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
8
- sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot
- sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot
+ sage: g.show(figsize=[10, 10]) # long time # needs sage.plot
+ sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot
TESTS::
- sage: graphs.LjubljanaGraph(embedding=3) # optional - networkx
+ sage: graphs.LjubljanaGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -3486,16 +3499,17 @@ def LivingstoneGraph():
EXAMPLES::
- sage: g = graphs.LivingstoneGraph() # optional - internet
- sage: g.order() # optional - internet
+ sage: # optional - internet
+ sage: g = graphs.LivingstoneGraph()
+ sage: g.order()
266
- sage: g.size() # optional - internet
+ sage: g.size()
1463
- sage: g.girth() # optional - internet
+ sage: g.girth()
5
- sage: g.is_vertex_transitive() # optional - internet
+ sage: g.is_vertex_transitive()
True
- sage: g.is_distance_regular() # optional - internet
+ sage: g.is_distance_regular()
True
"""
from sage.groups.perm_gps.permgroup_named import JankoGroup
@@ -3518,12 +3532,13 @@ def M22Graph():
EXAMPLES::
- sage: g = graphs.M22Graph() # optional - sage.groups
- sage: g.order() # optional - sage.groups
+ sage: # needs sage.groups
+ sage: g = graphs.M22Graph()
+ sage: g.order()
77
- sage: g.size() # optional - sage.groups
+ sage: g.size()
616
- sage: g.is_strongly_regular(parameters=True) # optional - sage.groups
+ sage: g.is_strongly_regular(parameters=True)
(77, 16, 0, 4)
"""
from sage.groups.perm_gps.permgroup_named import MathieuGroup
@@ -3561,11 +3576,11 @@ def MarkstroemGraph():
True
sage: g.is_regular(3)
True
- sage: g.subgraph_search(graphs.CycleGraph(4)) is None # optional - sage.modules
+ sage: g.subgraph_search(graphs.CycleGraph(4)) is None # needs sage.modules
True
- sage: g.subgraph_search(graphs.CycleGraph(8)) is None # optional - sage.modules
+ sage: g.subgraph_search(graphs.CycleGraph(8)) is None # needs sage.modules
True
- sage: g.subgraph_search(graphs.CycleGraph(16)) # optional - sage.modules
+ sage: g.subgraph_search(graphs.CycleGraph(16)) # needs sage.modules
Subgraph of (Markstroem Graph): Graph on 16 vertices
"""
g = Graph(name="Markstroem Graph")
@@ -3602,21 +3617,22 @@ def McGeeGraph(embedding=2):
EXAMPLES::
- sage: g = graphs.McGeeGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.McGeeGraph()
+ sage: g.order()
24
- sage: g.size() # optional - networkx
+ sage: g.size()
36
- sage: g.girth() # optional - networkx
+ sage: g.girth()
7
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
4
- sage: g.show() # optional - networkx sage.plot
- sage: graphs.McGeeGraph(embedding=1).show() # long time # optional - networkx sage.plot
+ sage: g.show() # needs sage.plot
+ sage: graphs.McGeeGraph(embedding=1).show() # long time # needs sage.plot
TESTS::
- sage: graphs.McGeeGraph(embedding=3) # optional - networkx
+ sage: graphs.McGeeGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -3726,7 +3742,7 @@ def MoebiusKantorGraph():
Moebius-Kantor Graph: Graph on 16 vertices
sage: MK.graph6_string()
'OhCGKE?O@?ACAC@I?Q_AS'
- sage: (graphs.MoebiusKantorGraph()).show() # long time # optional - sage.plot
+ sage: (graphs.MoebiusKantorGraph()).show() # long time # needs sage.plot
"""
from sage.graphs.generators.families import GeneralizedPetersenGraph
G = GeneralizedPetersenGraph(8, 3)
@@ -3744,38 +3760,41 @@ def MoserSpindle():
The Moser spindle is a planar graph having 7 vertices and 11 edges::
- sage: G = graphs.MoserSpindle(); G # optional - sage.symbolic
+ sage: # needs sage.symbolic
+ sage: G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices
- sage: G.is_planar() # optional - sage.symbolic
+ sage: G.is_planar()
True
- sage: G.order() # optional - sage.symbolic
+ sage: G.order()
7
- sage: G.size() # optional - sage.symbolic
+ sage: G.size()
11
It is a Hamiltonian graph with radius 2, diameter 2, and girth 3::
- sage: G.is_hamiltonian() # optional - sage.symbolic
+ sage: # needs sage.symbolic
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
- sage: G.radius() # optional - sage.symbolic
+ sage: G.radius()
2
- sage: G.diameter() # optional - sage.symbolic
+ sage: G.diameter()
2
- sage: G.girth() # optional - sage.symbolic
+ sage: G.girth()
3
The Moser spindle can be drawn in the plane as a unit distance graph,
has chromatic number 4, and its automorphism group is isomorphic to
the dihedral group `D_4`::
- sage: pos = G.get_pos() # optional - sage.symbolic
- sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 # optional - sage.symbolic
+ sage: # needs sage.symbolic
+ sage: pos = G.get_pos()
+ sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1
....: for u, v in G.edge_iterator(labels=None))
True
- sage: G.chromatic_number() # optional - sage.symbolic
+ sage: G.chromatic_number()
4
- sage: ag = G.automorphism_group() # optional - sage.symbolic
- sage: ag.is_isomorphic(DihedralGroup(4)) # optional - sage.symbolic
+ sage: ag = G.automorphism_group()
+ sage: ag.is_isomorphic(DihedralGroup(4))
True
"""
edge_dict = {
@@ -3821,8 +3840,8 @@ def NauruGraph(embedding=2):
6
sage: g.diameter()
4
- sage: g.show() # optional - sage.plot
- sage: graphs.NauruGraph(embedding=1).show() # long time # optional - sage.plot
+ sage: g.show() # needs sage.plot
+ sage: graphs.NauruGraph(embedding=1).show() # long time # needs sage.plot
TESTS::
@@ -3830,7 +3849,7 @@ def NauruGraph(embedding=2):
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
- sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # optional - networkx
+ sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # needs networkx
True
"""
@@ -3857,10 +3876,10 @@ def PappusGraph():
EXAMPLES::
sage: G = graphs.PappusGraph()
- sage: G.show() # long time # optional - sage.plot
- sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # optional - networkx
- sage: L.show() # long time # optional - networkx sage.plot
- sage: G.is_isomorphic(L) # optional - networkx
+ sage: G.show() # long time # needs sage.plot
+ sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # needs networkx
+ sage: L.show() # long time # needs networkx sage.plot
+ sage: G.is_isomorphic(L) # needs networkx
True
"""
edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11],
@@ -3923,9 +3942,9 @@ def PetersenGraph():
....: 3:[2,4,8], 4:[0,3,9], 5:[0,7,8],
....: 6:[1,8,9], 7:[2,5,9], 8:[3,5,6],
....: 9:[4,6,7]})
- sage: petersen_spring.show() # long time # optional - sage.plot
+ sage: petersen_spring.show() # long time # needs sage.plot
sage: petersen_database = graphs.PetersenGraph()
- sage: petersen_database.show() # long time # optional - sage.plot
+ sage: petersen_database.show() # long time # needs sage.plot
"""
from sage.graphs.generators.families import GeneralizedPetersenGraph
P = GeneralizedPetersenGraph(5, 2)
@@ -3970,23 +3989,24 @@ def RobertsonGraph():
EXAMPLES::
- sage: g = graphs.RobertsonGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.RobertsonGraph()
+ sage: g.order()
19
- sage: g.size() # optional - networkx
+ sage: g.size()
38
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
3
- sage: g.girth() # optional - networkx
+ sage: g.girth()
5
- sage: g.charpoly().factor() # optional - networkx
+ sage: g.charpoly().factor()
(x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1)
* (x^2 - 3)^2 * (x^2 + x - 4)^2 * (x^2 + x - 3)^2
- sage: g.chromatic_number() # optional - networkx
+ sage: g.chromatic_number()
3
- sage: g.is_hamiltonian() # optional - networkx
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
- sage: g.is_vertex_transitive() # optional - networkx
+ sage: g.is_vertex_transitive()
False
"""
from sage.graphs.generators.families import LCFGraph
@@ -4024,7 +4044,7 @@ def SchlaefliGraph():
The graph is vertex-transitive::
- sage: S.is_vertex_transitive() # optional - sage.groups
+ sage: S.is_vertex_transitive() # needs sage.groups
True
The neighborhood of each vertex is isomorphic to the complement of the
@@ -4079,7 +4099,7 @@ def ShrikhandeGraph():
sage: G.is_planar()
False
- sage: G.is_hamiltonian()
+ sage: G.is_hamiltonian() # needs sage.numerical.mip
True
sage: G.is_eulerian()
True
@@ -4097,12 +4117,12 @@ def ShrikhandeGraph():
sage: G.chromatic_number()
4
- sage: G.automorphism_group().cardinality()
+ sage: G.automorphism_group().cardinality() # needs sage.groups
192
It is an integral graph since it has only integral eigenvalues::
- sage: G.characteristic_polynomial().factor()
+ sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules
(x - 6) * (x - 2)^6 * (x + 2)^9
It is a toroidal graph, and its embedding on a torus is dual to an
@@ -4236,12 +4256,12 @@ def SousselierGraph():
2
sage: g.diameter()
3
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
2
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
"""
g = Graph(name="Sousselier Graph")
@@ -4317,7 +4337,7 @@ def ThomsenGraph():
Thomsen graph: Graph on 6 vertices
sage: T.graph6_string()
'EFz_'
- sage: (graphs.ThomsenGraph()).show() # long time # optional - sage.plot
+ sage: (graphs.ThomsenGraph()).show() # long time # needs sage.plot
"""
from sage.graphs.generators.basic import CompleteBipartiteGraph
G = CompleteBipartiteGraph(3, 3)
@@ -4343,9 +4363,9 @@ def TietzeGraph():
3
sage: g.girth()
3
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
12
- sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # optional - sage.groups
+ sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # needs sage.groups
True
"""
g = Graph([(0, 9), (3, 10), (6, 11), (1, 5), (2, 7), (4, 8)],
@@ -4370,11 +4390,11 @@ def TruncatedIcosidodecahedralGraph():
Unfortunately, this graph can not be constructed currently, due to numerical issues::
- sage: g = graphs.TruncatedIcosidodecahedralGraph(); g
+ sage: g = graphs.TruncatedIcosidodecahedralGraph(); g # needs sage.geometry.polyhedron sage.groups sage.rings.number_field
Traceback (most recent call last):
...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic.
- sage: g.order(), g.size() # not tested
+ sage: g.order(), g.size() # not tested # needs sage.geometry.polyhedron sage.groups sage.rings.number_field
(120, 180)
"""
from sage.geometry.polyhedron.library import polytopes
@@ -4397,7 +4417,7 @@ def TruncatedTetrahedralGraph():
Truncated Tetrahedron: Graph on 12 vertices
sage: g.order(), g.size()
(12, 18)
- sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # optional - sage.geometry.polyhedron
+ sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # needs sage.geometry.polyhedron
True
"""
g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False)
@@ -4416,16 +4436,17 @@ def Tutte12Cage():
EXAMPLES::
- sage: g = graphs.Tutte12Cage() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.Tutte12Cage()
+ sage: g.order()
126
- sage: g.size() # optional - networkx
+ sage: g.size()
189
- sage: g.girth() # optional - networkx
+ sage: g.girth()
12
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
6
- sage: g.show() # optional - networkx sage.plot
+ sage: g.show() # needs sage.plot
"""
L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11,
-21, -57, 59, -17]
@@ -4449,21 +4470,22 @@ def TutteCoxeterGraph(embedding=2):
EXAMPLES::
- sage: g = graphs.TutteCoxeterGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.TutteCoxeterGraph()
+ sage: g.order()
30
- sage: g.size() # optional - networkx
+ sage: g.size()
45
- sage: g.girth() # optional - networkx
+ sage: g.girth()
8
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
4
- sage: g.show() # optional - networkx sage.plot
- sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # optional - networkx sage.plot
+ sage: g.show() # needs sage.plot
+ sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # needs sage.plot
TESTS::
- sage: graphs.TutteCoxeterGraph(embedding=3) # optional - networkx
+ sage: graphs.TutteCoxeterGraph(embedding=3) # needs networkx
Traceback (most recent call last):
...
ValueError: the value of embedding must be 1 or 2
@@ -4516,9 +4538,9 @@ def TutteGraph():
3
sage: g.girth()
4
- sage: g.automorphism_group().cardinality() # optional - sage.groups
+ sage: g.automorphism_group().cardinality() # needs sage.groups
3
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
False
"""
g = Graph(name="Tutte Graph")
@@ -4562,16 +4584,17 @@ def WagnerGraph():
EXAMPLES::
- sage: g = graphs.WagnerGraph() # optional - networkx
- sage: g.order() # optional - networkx
+ sage: # needs networkx
+ sage: g = graphs.WagnerGraph()
+ sage: g.order()
8
- sage: g.size() # optional - networkx
+ sage: g.size()
12
- sage: g.girth() # optional - networkx
+ sage: g.girth()
4
- sage: g.diameter() # optional - networkx
+ sage: g.diameter()
2
- sage: g.show() # optional - networkx sage.plot
+ sage: g.show() # needs sage.plot
"""
from sage.graphs.generators.families import LCFGraph
g = LCFGraph(8, [4], 8)
@@ -4637,10 +4660,10 @@ def WienerArayaGraph():
4
sage: g.is_planar()
True
- sage: g.is_hamiltonian() # not tested -- around 30s long
+ sage: g.is_hamiltonian() # not tested (30s) # needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
"""
g = Graph(name="Wiener-Araya Graph")
@@ -4695,7 +4718,7 @@ def _EllipticLinesProjectivePlaneScheme(k):
TESTS::
sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme
- sage: _EllipticLinesProjectivePlaneScheme(2)
+ sage: _EllipticLinesProjectivePlaneScheme(2) # needs sage.libs.gap
[
[1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1]
[0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0]
@@ -4738,11 +4761,12 @@ def MathonStronglyRegularGraph(t):
TESTS::
- sage: G = graphs.MathonStronglyRegularGraph(1) # long time
- sage: G.is_strongly_regular(parameters=True) # long time
+ sage: # long time
+ sage: G = graphs.MathonStronglyRegularGraph(1)
+ sage: G.is_strongly_regular(parameters=True)
(784, 270, 98, 90)
- sage: G = graphs.MathonStronglyRegularGraph(2) # long time
- sage: G.is_strongly_regular(parameters=True) # long time
+ sage: G = graphs.MathonStronglyRegularGraph(2)
+ sage: G.is_strongly_regular(parameters=True)
(784, 297, 116, 110)
"""
@@ -5009,12 +5033,12 @@ def IoninKharaghani765Graph():
EXAMPLES::
- sage: g = graphs.IoninKharaghani765Graph(); g
+ sage: g = graphs.IoninKharaghani765Graph(); g # needs sage.modules sage.rings.finite_rings
Ionin-Kharaghani: Graph on 765 vertices
TESTS::
- sage: graphs.strongly_regular_graph(765, 192, 48, 48)
+ sage: graphs.strongly_regular_graph(765, 192, 48, 48) # needs sage.modules sage.rings.finite_rings
Ionin-Kharaghani: Graph on 765 vertices
.. TODO::
diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py
index a083ed43e5e..0c2dc0a79df 100644
--- a/src/sage/graphs/generic_graph.py
+++ b/src/sage/graphs/generic_graph.py
@@ -4964,15 +4964,15 @@ def spanning_trees_count(self, root_vertex=None):
EXAMPLES::
sage: G = graphs.PetersenGraph()
- sage: G.spanning_trees_count()
+ sage: G.spanning_trees_count() # needs sage.modules
2000
::
sage: n = 11
sage: G = graphs.CompleteGraph(n)
- sage: ST = G.spanning_trees_count()
- sage: ST == n ^ (n - 2)
+ sage: ST = G.spanning_trees_count() # needs sage.modules
+ sage: ST == n ^ (n - 2) # needs sage.modules
True
::
@@ -6860,34 +6860,36 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
The Petersen Graph does have a spanning tree (it is connected)::
sage: g = graphs.PetersenGraph()
- sage: [T] = g.edge_disjoint_spanning_trees(1)
- sage: T.is_tree()
+ sage: [T] = g.edge_disjoint_spanning_trees(1) # needs sage.numerical.mip
+ sage: T.is_tree() # needs sage.numerical.mip
True
Though, it does not have 2 edge-disjoint trees (as it has less than
`2(|V|-1)` edges)::
- sage: g.edge_disjoint_spanning_trees(2)
+ sage: g.edge_disjoint_spanning_trees(2) # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: this graph does not contain the required number of trees/arborescences
- By Edmond's theorem, a graph which is `k`-connected always has `k`
+ By Edmonds' theorem, a graph which is `k`-connected always has `k`
edge-disjoint arborescences, regardless of the root we pick::
+ sage: # needs sage.numerical.mip
sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169
sage: k = Integer(g.edge_connectivity())
sage: while not k:
....: g = digraphs.RandomDirectedGNP(11, .3)
....: k = Integer(g.edge_connectivity())
- sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011)
- sage: all(a.is_directed_acyclic() for a in arborescences) # long time
+ sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011)
+ sage: all(a.is_directed_acyclic() for a in arborescences) # long time
True
sage: all(a.is_connected() for a in arborescences) # long time
True
In the undirected case, we can only ensure half of it::
+ sage: # needs sage.numerical.mip
sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169
sage: while not g.is_biconnected():
....: g = graphs.RandomGNP(14, .3)
@@ -6898,6 +6900,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
Check the validity of the algorithms for undirected graphs::
+ sage: # needs sage.numerical.mip
sage: g = graphs.RandomGNP(12, .7)
sage: k = Integer(g.edge_connectivity()) // 2
sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP")
@@ -6919,7 +6922,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
sage: G = DiGraph(d6, format='dig6')
sage: G.edge_connectivity()
5
- sage: G.edge_disjoint_spanning_trees(5) # long time
+ sage: G.edge_disjoint_spanning_trees(5) # long time # needs sage.numerical.mip
[Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices,
@@ -6928,6 +6931,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
Small cases::
+ sage: # needs sage.numerical.mip
sage: Graph().edge_disjoint_spanning_trees(0)
[]
sage: Graph(1).edge_disjoint_spanning_trees(0)
@@ -6947,11 +6951,11 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
Choice of the algorithm::
- sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None)
+ sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) # needs sage.numerical.mip
[]
sage: Graph().edge_disjoint_spanning_trees(0, algorithm="Roskind-Tarjan")
[]
- sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP")
+ sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip
[]
sage: Graph().edge_disjoint_spanning_trees(0, algorithm="foo")
Traceback (most recent call last):
@@ -6959,7 +6963,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None
ValueError: algorithm must be None, "Rosking-Tarjan" or "MILP" for undirected graphs
sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm=None)
[]
- sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP")
+ sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip
[]
sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="foo")
Traceback (most recent call last):
@@ -7370,25 +7374,25 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose
A basic application in the Pappus graph::
sage: g = graphs.PappusGraph()
- sage: g.vertex_cut(1, 16, value_only=True)
+ sage: g.vertex_cut(1, 16, value_only=True) # needs sage.numerical.mip
3
In the bipartite complete graph `K_{2,8}`, a cut between the two
vertices in the size `2` part consists of the other `8` vertices::
sage: g = graphs.CompleteBipartiteGraph(2, 8)
- sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False)
- sage: print(value)
+ sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) # needs sage.numerical.mip
+ sage: print(value) # needs sage.numerical.mip
8
- sage: vertices == list(range(2, 10))
+ sage: vertices == list(range(2, 10)) # needs sage.numerical.mip
True
Clearly, in this case the two sides of the cut are singletons::
- sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True)
- sage: len(set1) == 1
+ sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) # needs sage.numerical.mip
+ sage: len(set1) == 1 # needs sage.numerical.mip
True
- sage: len(set2) == 1
+ sage: len(set2) == 1 # needs sage.numerical.mip
True
"""
from sage.numerical.mip import MixedIntegerLinearProgram
@@ -7495,35 +7499,35 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False,
edge cut::
sage: g = graphs.PetersenGraph()
- sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True)
+ sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only=True) # needs sage.numerical.mip
True
As Petersen's graph is `3`-regular, a minimum multiway cut between three
vertices contains at most `2\times 3` edges (which could correspond to
the neighborhood of 2 vertices)::
- sage: g.multiway_cut([0,3,9], value_only = True) == 2*3
+ sage: g.multiway_cut([0,3,9], value_only=True) == 2*3 # needs sage.numerical.mip
True
In this case, though, the vertices are an independent set. If we pick
instead vertices `0,9,` and `7`, we can save `4` edges in the multiway
cut::
- sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1
+ sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1 # needs sage.numerical.mip
True
This example, though, does not work in the directed case anymore, as it
is not possible in Petersen's graph to mutualise edges::
sage: g = DiGraph(g)
- sage: g.multiway_cut([0,7,9], value_only = True) == 3*3
+ sage: g.multiway_cut([0,7,9], value_only=True) == 3*3 # needs sage.numerical.mip
True
Of course, a multiway cut between the whole vertex set contains all the
edges of the graph::
- sage: C = g.multiway_cut(g.vertices(sort=False))
- sage: set(C) == set(g.edges(sort=False))
+ sage: C = g.multiway_cut(g.vertices(sort=False)) # needs sage.numerical.mip
+ sage: set(C) == set(g.edges(sort=False)) # needs sage.numerical.mip
True
"""
self._scream_if_not_simple(allow_loops=True)
@@ -7633,18 +7637,20 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False,
Quite obviously, the max cut of a bipartite graph is the number of
edges, and the two sets of vertices are the two sides::
+ sage: # needs sage.numerical.mip
sage: g = graphs.CompleteBipartiteGraph(5,6)
sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)
sage: value == 5*6
True
- sage: bsetA, bsetB = map(list,g.bipartite_sets())
- sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA ))
+ sage: bsetA, bsetB = map(list, g.bipartite_sets())
+ sage: ((bsetA == setA and bsetB == setB)
+ ....: or (bsetA == setB and bsetB == setA))
True
The max cut of a Petersen graph::
- sage: g=graphs.PetersenGraph()
- sage: g.max_cut()
+ sage: g = graphs.PetersenGraph()
+ sage: g.max_cut() # needs sage.numerical.mip
12
TESTS::
@@ -7809,8 +7815,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
`n - 2`::
sage: g = graphs.PetersenGraph()
- sage: lp = g.longest_path()
- sage: lp.order() >= g.order() - 2
+ sage: lp = g.longest_path() # needs sage.numerical.mip
+ sage: lp.order() >= g.order() - 2 # needs sage.numerical.mip
True
The heuristic totally agrees::
@@ -7831,8 +7837,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
sage: g = graphs.RandomGNP(15, 0.3)
sage: for u, v in g.edge_iterator(labels=False):
....: g.set_edge_label(u, v, random())
- sage: lp = g.longest_path()
- sage: (not lp.is_forest() or not max(lp.degree()) <= 2
+ sage: lp = g.longest_path() # needs sage.numerical.mip
+ sage: (not lp.is_forest() or not max(lp.degree()) <= 2 # needs sage.numerical.mip
....: or not lp.is_connected())
False
@@ -7850,9 +7856,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
sage: g1 = graphs.PetersenGraph()
sage: g2 = 2 * g1
- sage: lp1 = g1.longest_path()
- sage: lp2 = g2.longest_path()
- sage: len(lp1) == len(lp2)
+ sage: lp1 = g1.longest_path() # needs sage.numerical.mip
+ sage: lp2 = g2.longest_path() # needs sage.numerical.mip
+ sage: len(lp1) == len(lp2) # needs sage.numerical.mip
True
Disconnected graphs weighted::
@@ -7861,13 +7867,14 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
sage: for u,v in g.edge_iterator(labels=False):
....: g.set_edge_label(u, v, random())
sage: g2 = 2 * g1
- sage: lp1 = g1.longest_path(use_edge_labels=True)
- sage: lp2 = g2.longest_path(use_edge_labels=True)
- sage: lp1[0] == lp2[0]
+ sage: lp1 = g1.longest_path(use_edge_labels=True) # needs sage.numerical.mip
+ sage: lp2 = g2.longest_path(use_edge_labels=True) # needs sage.numerical.mip
+ sage: lp1[0] == lp2[0] # needs sage.numerical.mip
True
Empty graphs::
+ sage: # needs sage.numerical.mip
sage: Graph().longest_path()
Graph on 0 vertices
sage: Graph().longest_path(use_edge_labels=True)
@@ -7879,6 +7886,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
Trivial graphs::
+ sage: # needs sage.numerical.mip
sage: G = Graph()
sage: G.add_vertex(0)
sage: G.longest_path()
@@ -7895,8 +7903,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
sage: g = digraphs.RandomDirectedGNP(15, 0.3)
sage: for u, v in g.edge_iterator(labels=False):
....: g.set_edge_label(u, v, random())
- sage: lp = g.longest_path()
- sage: (not lp.is_directed_acyclic() or
+ sage: lp = g.longest_path() # needs sage.numerical.mip
+ sage: (not lp.is_directed_acyclic() or # needs sage.numerical.mip
....: not max(lp.out_degree()) <= 1 or
....: not max(lp.in_degree()) <= 1 or
....: not lp.is_connected())
@@ -7905,7 +7913,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
:trac:`13019`::
sage: g = graphs.CompleteGraph(5).to_directed()
- sage: g.longest_path(s=1, t=2)
+ sage: g.longest_path(s=1, t=2) # needs sage.numerical.mip
Subgraph of (Complete graph): Digraph on 5 vertices
:trac:`14412`::
@@ -7913,7 +7921,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP",
sage: l = [(0, 1), (0, 3), (2, 0), (3, 4)]
sage: G = DiGraph(l)
sage: H = {(0, 3), (2, 0), (3, 4)}
- sage: H == {x for x in G.longest_path().edge_iterator(labels=False)}
+ sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip
True
"""
self._scream_if_not_simple()
@@ -8189,6 +8197,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False,
starting from vertex `(0, 0)` and ending at vertex `(2, 2)`, but no
Hamiltonian path starting from `(0, 0)` and ending at `(0, 1)`::
+ sage: # needs sage.numerical.mip
sage: g = graphs.Grid2dGraph(3, 3)
sage: g.hamiltonian_path()
Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices
@@ -8206,13 +8215,13 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False,
Empty and one-element graphs::
sage: g = Graph()
- sage: g.hamiltonian_path()
+ sage: g.hamiltonian_path() # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: the Hamiltonian path problem is not well defined
for empty and one-element (di)graphs
sage: g = Graph(1)
- sage: g.hamiltonian_path()
+ sage: g.hamiltonian_path() # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: the Hamiltonian path problem is not well defined
@@ -8221,20 +8230,22 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False,
A non-connected (di)graph has no hamiltonian path::
sage: g = Graph(2)
- sage: g.hamiltonian_path() is None
+ sage: g.hamiltonian_path() is None # needs sage.numerical.mip
True
- sage: g.hamiltonian_path(use_edge_labels=True)
+ sage: g.hamiltonian_path(use_edge_labels=True) # needs sage.numerical.mip
(0, None)
sage: g = DiGraph(2)
- sage: g.hamiltonian_path() is None
+ sage: g.hamiltonian_path() is None # needs sage.numerical.mip
True
Asking for a minimum (resp., maximum) weight Hamiltonian path::
sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)])
- sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=False)[0])
+ sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip
+ ....: maximize=False)[0])
3
- sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=True)[0])
+ sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip
+ ....: maximize=True)[0])
5
Parameter ``algorithm`` must be either ``'backtrack'`` or ``'MILP'``::
@@ -8444,29 +8455,28 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
The Heawood graph is known to be Hamiltonian::
sage: g = graphs.HeawoodGraph()
- sage: tsp = g.traveling_salesman_problem()
- sage: tsp
+ sage: tsp = g.traveling_salesman_problem(); tsp # needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices
The solution to the TSP has to be connected::
- sage: tsp.is_connected()
+ sage: tsp.is_connected() # needs sage.numerical.mip
True
It must also be a `2`-regular graph::
- sage: tsp.is_regular(k=2)
+ sage: tsp.is_regular(k=2) # needs sage.numerical.mip
True
And obviously it is a subgraph of the Heawood graph::
- sage: tsp.is_subgraph(g, induced=False)
+ sage: tsp.is_subgraph(g, induced=False) # needs sage.numerical.mip
True
On the other hand, the Petersen Graph is known not to be Hamiltonian::
sage: g = graphs.PetersenGraph()
- sage: tsp = g.traveling_salesman_problem()
+ sage: tsp = g.traveling_salesman_problem() # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: the given graph is not Hamiltonian
@@ -8485,8 +8495,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
....: g.add_edge(u, v)
....: g.set_edge_label(u, v, 2)
- sage: tsp = g.traveling_salesman_problem(use_edge_labels=True)
- sage: sum( tsp.edge_labels() ) < 2 * 10
+ sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip
+ sage: sum( tsp.edge_labels() ) < 2 * 10 # needs sage.numerical.mip
True
If we pick `1/2` instead of `2` as a cost for these new edges, they
@@ -8495,17 +8505,20 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
sage: for u, v in cycle.edges(labels=None, sort=False):
....: g.set_edge_label(u,v,1/2)
- sage: tsp = g.traveling_salesman_problem(use_edge_labels=True)
- sage: sum(tsp.edge_labels()) == (1/2) * 10
+ sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip
+ sage: sum(tsp.edge_labels()) == (1/2) * 10 # needs sage.numerical.mip
True
Search for a minimum and a maximum weight Hamiltonian cycle::
+ sage: # needs sage.numerical.mip
sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)])
- sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=False)
+ sage: tsp = G.traveling_salesman_problem(use_edge_labels=True,
+ ....: maximize=False)
sage: print(sum(tsp.edge_labels()))
4
- sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=True)
+ sage: tsp = G.traveling_salesman_problem(use_edge_labels=True,
+ ....: maximize=True)
sage: print(sum(tsp.edge_labels()))
6
@@ -8523,9 +8536,10 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
sage: for u, v in graphs.CycleGraph(n).edges(labels=False, sort=False):
....: if not g.has_edge(u, v):
....: g.add_edge(u, v, ZZ.random_element(1,100000))
- sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True)
- sage: v2 = g.traveling_salesman_problem(use_edge_labels=True)
- sage: sum(v1.edge_labels()) == sum(v2.edge_labels())
+ sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip
+ ....: use_edge_labels=True)
+ sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip
+ sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip
True
Then for digraphs::
@@ -8539,13 +8553,15 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
sage: for u, v in digraphs.Circuit(n).edges(labels=False, sort=False):
....: if not g.has_edge(u, v):
....: g.add_edge(u, v, ZZ.random_element(1,100000))
- sage: v2 = g.traveling_salesman_problem(use_edge_labels=True)
- sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True)
- sage: sum(v1.edge_labels()) == sum(v2.edge_labels())
+ sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip
+ sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip
+ ....: use_edge_labels=True)
+ sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip
True
Simple tests for multiple edges and loops::
+ sage: # needs sage.numerical.mip
sage: G = DiGraph(multiedges=True, loops=True)
sage: G.is_hamiltonian()
False
@@ -8573,6 +8589,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
Graphs on 2 vertices::
+ sage: # needs sage.numerical.mip
sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian()
True
sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian()
@@ -8592,8 +8609,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False,
Check that weight 0 edges are handled correctly (see :trac:`16214`)::
sage: G = Graph([(0, 1, 1), (0, 2, 0), (0, 3, 1), (1, 2, 1), (1, 3, 0), (2, 3, 1)])
- sage: tsp = G.traveling_salesman_problem(use_edge_labels=True)
- sage: sum(tsp.edge_labels())
+ sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip
+ sage: sum(tsp.edge_labels()) # needs sage.numerical.mip
2
"""
from sage.categories.sets_cat import EmptySetError
@@ -8953,13 +8970,13 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation=
The Heawood Graph is known to be Hamiltonian ::
sage: g = graphs.HeawoodGraph()
- sage: g.hamiltonian_cycle()
+ sage: g.hamiltonian_cycle() # needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices
The Petersen Graph, though, is not ::
sage: g = graphs.PetersenGraph()
- sage: g.hamiltonian_cycle()
+ sage: g.hamiltonian_cycle() # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: the given graph is not Hamiltonian
@@ -9092,6 +9109,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0,
The necessary example::
+ sage: # needs sage.numerical.mip
sage: g = graphs.PetersenGraph()
sage: fvs = g.feedback_vertex_set()
sage: len(fvs)
@@ -9106,6 +9124,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0,
of its neighbors removed: a feedback vertex set is in this situation a
vertex cover::
+ sage: # needs sage.numerical.mip
sage: cycle = graphs.CycleGraph(5)
sage: dcycle = DiGraph(cycle)
sage: cycle.vertex_cover(value_only=True)
@@ -9120,7 +9139,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0,
For a circuit, the minimum feedback arc set is clearly `1`::
sage: circuit = digraphs.Circuit(5)
- sage: circuit.feedback_vertex_set(value_only=True) == 1
+ sage: circuit.feedback_vertex_set(value_only=True) == 1 # needs sage.numerical.mip
True
TESTS:
@@ -9128,16 +9147,16 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0,
Comparing with/without constraint generation::
sage: g = digraphs.RandomDirectedGNP(10, .3)
- sage: x = g.feedback_vertex_set(value_only=True)
- sage: y = g.feedback_vertex_set(value_only=True,
- ....: constraint_generation=False)
- sage: x == y
+ sage: x = g.feedback_vertex_set(value_only=True) # needs sage.numerical.mip
+ sage: y = g.feedback_vertex_set(value_only=True, # needs sage.numerical.mip
+ ....: constraint_generation=False)
+ sage: x == y # needs sage.numerical.mip
True
Bad algorithm::
sage: g = graphs.PetersenGraph()
- sage: g.feedback_vertex_set(constraint_generation=False)
+ sage: g.feedback_vertex_set(constraint_generation=False) # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: the only implementation available for undirected graphs is with constraint_generation set to True
@@ -9621,19 +9640,19 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler
4-nowhere zero flow::
sage: g = graphs.PetersenGraph()
- sage: h = g.nowhere_zero_flow(k=5)
- sage: sorted(set(h.edge_labels()))
+ sage: h = g.nowhere_zero_flow(k=5) # needs sage.numerical.mip
+ sage: sorted(set(h.edge_labels())) # needs sage.numerical.mip
[1, 2, 3, 4]
- sage: h = g.nowhere_zero_flow(k=3)
+ sage: h = g.nowhere_zero_flow(k=3) # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: the problem has no feasible solution
The de Bruijn digraph admits a 2-nowhere zero flow::
- sage: g = digraphs.DeBruijn(2, 3)
- sage: h = g.nowhere_zero_flow(k=2)
- sage: sorted(set(h.edge_labels()))
+ sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat
+ sage: h = g.nowhere_zero_flow(k=2) # needs sage.combinat sage.numerical.mip
+ sage: sorted(set(h.edge_labels())) # needs sage.combinat sage.numerical.mip
[-1, 1]
TESTS:
@@ -9641,7 +9660,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler
Empty graph::
sage: G = Graph()
- sage: G.nowhere_zero_flow()
+ sage: G.nowhere_zero_flow() # needs sage.numerical.mip
Digraph on 0 vertices
Graph with one vertex::
@@ -9649,11 +9668,12 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler
sage: G = Graph([[1], []])
sage: G
Graph on 1 vertex
- sage: G.nowhere_zero_flow()
+ sage: G.nowhere_zero_flow() # needs sage.numerical.mip
Digraph on 1 vertex
Loops and multiple edges::
+ sage: # needs sage.numerical.mip
sage: g = Graph([(0, 0), (0, 0)], loops=True, multiedges=True)
sage: g.nowhere_zero_flow().edges(sort=True)
[(0, 0, 1), (0, 0, 1)]
@@ -9670,26 +9690,26 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler
Multiple connected components::
sage: g = graphs.CycleGraph(3) * 2
- sage: h = g.nowhere_zero_flow()
- sage: h.connected_components_sizes()
+ sage: h = g.nowhere_zero_flow() # needs sage.numerical.mip
+ sage: h.connected_components_sizes() # needs sage.numerical.mip
[3, 3]
(Di)Graphs with bridges::
sage: g = graphs.PathGraph(2)
- sage: g.nowhere_zero_flow()
+ sage: g.nowhere_zero_flow() # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: (di)graphs with bridges have no feasible solution
sage: g = digraphs.Path(2)
- sage: g.nowhere_zero_flow()
+ sage: g.nowhere_zero_flow() # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: (di)graphs with bridges have no feasible solution
Too small value of ``k``::
- sage: Graph().nowhere_zero_flow(k=1)
+ sage: Graph().nowhere_zero_flow(k=1) # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: parameter 'k' must be at least 2
@@ -10010,22 +10030,22 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False,
matching in a graph, and to consider the paired vertices as terminals ::
sage: g = graphs.PetersenGraph()
- sage: matching = [(u,v) for u,v,_ in g.matching()]
- sage: h = g.multicommodity_flow(matching)
- sage: len(h)
+ sage: matching = [(u,v) for u,v,_ in g.matching()] # needs networkx
+ sage: h = g.multicommodity_flow(matching) # needs networkx
+ sage: len(h) # needs networkx
5
We could also have considered ``g`` as symmetric and computed the
multicommodity flow in this version instead. In this case, however edges
can be used in both directions at the same time::
- sage: h = DiGraph(g).multicommodity_flow(matching)
- sage: len(h)
+ sage: h = DiGraph(g).multicommodity_flow(matching) # needs networkx
+ sage: len(h) # needs networkx
5
An exception is raised when the problem has no solution ::
- sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching])
+ sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) # needs networkx
Traceback (most recent call last):
...
EmptySetError: the multicommodity flow problem has no solution
@@ -10182,7 +10202,7 @@ def _build_flow_graph(self, flow, integer):
Isolated zero-cost flow cycles are also removed::
- sage: g = digraphs.DeBruijn(2, 3)
+ sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat
sage: flow = {('000', '001'): 1, ('010', '101'): 1, ('101', '010'): 1}
sage: flow_graph = g._build_flow_graph(flow, True)
sage: flow_graph.edges(sort=True)
@@ -10258,13 +10278,13 @@ def disjoint_routed_paths(self, pairs, solver=None, verbose=0,
top-right corner to the bottom-right corner is easy::
sage: g = graphs.Grid2dGraph(5, 5)
- sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))])
+ sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) # needs sage.numerical.mip
Though there is obviously no solution to the problem in which each
corner is sending information to the opposite one::
sage: g = graphs.Grid2dGraph(5, 5)
- sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))])
+ sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) # needs sage.numerical.mip
Traceback (most recent call last):
...
EmptySetError: the disjoint routed paths do not exist
@@ -10384,7 +10404,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0,
In a complete bipartite graph ::
sage: g = graphs.CompleteBipartiteGraph(2, 3)
- sage: g.vertex_disjoint_paths(0, 1)
+ sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip
[[0, 2, 1], [0, 3, 1], [0, 4, 1]]
TESTS:
@@ -10392,9 +10412,9 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0,
Fix issues reported in :trac:`22990`::
sage: g = digraphs.Path(2)
- sage: g.vertex_disjoint_paths(0, 1)
+ sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip
[[0, 1]]
- sage: g.vertex_disjoint_paths(1, 0)
+ sage: g.vertex_disjoint_paths(1, 0) # needs sage.numerical.mip
[]
"""
obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False,
@@ -10507,14 +10527,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}
- sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs scipy
+ sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs networkx scipy
{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}
- sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs scipy
+ sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs networkx scipy
{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
@@ -10528,14 +10548,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False,
4: 0.23749999999999993,
5: 0.17775603392041744,
6: 0.10054631441617742}
- sage: G.pagerank() # abs tol 1e-9
+ sage: G.pagerank() # abs tol 1e-9 # needs networkx
{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}
- sage: G.pagerank(by_weight=True) # abs tol 1e-9
+ sage: G.pagerank(by_weight=True) # abs tol 1e-9 # needs networkx
{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
@@ -11393,11 +11413,12 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None):
are first-class objects in Python, we can specify precisely the function
from the Sage library that we wish to use as the key::
+ sage: # needs sage.libs.flint
sage: t = polygen(QQ, 't')
sage: K = Graph({5*t: [t^2], t^2: [t^2+2], t^2+2: [4*t^2-6], 4*t^2-6: [5*t]})
- sage: dsc = sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.discriminant
- sage: verts = K.vertices(sort=True, key=dsc)
- sage: verts
+ sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint
+ sage: dsc = Polynomial_rational_flint.discriminant
+ sage: verts = K.vertices(sort=True, key=dsc); verts
[t^2 + 2, t^2, 5*t, 4*t^2 - 6]
sage: [x.discriminant() for x in verts]
[-8, 0, 1, 96]
@@ -13924,7 +13945,7 @@ def subgraph_search_count(self, G, induced=False):
sage: T3 = digraphs.TransitiveTournament(3)
sage: T5.subgraph_search_count(T3) # needs sage.modules
10
- sage: binomial(5,3)
+ sage: binomial(5,3) # needs sage.symbolic
10
sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2])) # needs sage.modules
True
@@ -15275,9 +15296,10 @@ def clustering_average(self, implementation=None):
The result is the same with all implementations::
+ sage: # needs networkx
sage: G = graphs.RandomGNM(10,20)
- sage: impls = ['boost','sparse_copy','dense_copy']
- sage: impls += ['networkx'] # needs networkx
+ sage: impls = ['boost', 'sparse_copy', 'dense_copy']
+ sage: impls += ['networkx']
sage: coeffs = [G.clustering_average(implementation=impl)
....: for impl in impls]
sage: max(coeffs) - min(coeffs) # tol abs 1e-12
@@ -15355,7 +15377,7 @@ def clustering_coeff(self,
{0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3,
6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0}
- sage: (graphs.FruchtGraph()).clustering_coeff(weight=True)
+ sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) # needs networkx
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0,
3: 0.3333333333333333, 4: 0.3333333333333333,
5: 0.3333333333333333, 6: 0.3333333333333333,
@@ -15365,8 +15387,8 @@ def clustering_coeff(self,
sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2])
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0}
- sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2],
- ....: weight=True)
+ sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], # needs networkx
+ ....: weight=True)
{0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0}
sage: (graphs.GridGraph([5,5])).clustering_coeff(nodes=[(0,0),(0,1),(2,2)])
@@ -15390,6 +15412,7 @@ def clustering_coeff(self,
Check that the result is the same with all implementations::
+ sage: # needs networkx
sage: G = graphs.RandomGNM(10, 20)
sage: G.relabel(list("abcdefghik"))
sage: coeffs = [G.clustering_coeff(implementation=impl)
@@ -15774,8 +15797,8 @@ def odd_girth(self, algorithm="bfs", certificate=False):
Bipartite graphs have no odd cycle and consequently have
infinite odd girth::
- sage: G = graphs.RandomBipartite(6, 6, .5)
- sage: G.odd_girth()
+ sage: G = graphs.RandomBipartite(6, 6, .5) # needs numpy
+ sage: G.odd_girth() # needs numpy
+Infinity
sage: G = graphs.Grid2dGraph(3, 4)
sage: G.odd_girth()
@@ -16182,6 +16205,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None,
The result does not depend on the algorithm::
+ sage: # needs networkx
sage: import random
sage: import itertools
sage: n = random.randint(2,20)
@@ -16208,20 +16232,21 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None,
sage: m = random.randint(0, n*(n-1)/2)
sage: g = digraphs.RandomDirectedGNM(n,m)
sage: c1 = g.centrality_closeness(algorithm='BFS')
- sage: c2 = g.centrality_closeness(algorithm='NetworkX')
+ sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx
sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost')
sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython')
sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python')
sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost')
- sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6)
+ sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx
True
- sage: c = [c1,c2,c3,c4,c5,c6]
- sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12
+ sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx
+ sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 # needs networkx
....: for ci, cj in itertools.combinations(c, 2) )
True
Weighted graphs::
+ sage: # needs networkx
sage: import random
sage: import itertools
sage: n = random.randint(2,20)
@@ -16370,29 +16395,29 @@ def triangles_count(self, algorithm=None):
have::
sage: G = graphs.CompleteGraph(15)
- sage: G.triangles_count() == binomial(15, 3)
+ sage: G.triangles_count() == binomial(15, 3) # needs sage.symbolic
True
The 2-dimensional DeBruijn graph of 2 symbols has 2 directed `C_3`::
- sage: G = digraphs.DeBruijn(2,2)
- sage: G.triangles_count()
+ sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat
+ sage: G.triangles_count() # needs sage.combinat
2
The directed `n`-cycle is trivially triangle free for `n > 3`::
sage: G = digraphs.Circuit(10)
- sage: G.triangles_count()
+ sage: G.triangles_count() # needs sage.modules
0
TESTS:
Comparison of algorithms::
- sage: G = graphs.RandomBarabasiAlbert(50,2)
+ sage: G = graphs.RandomBarabasiAlbert(50,2) # needs networkx
sage: results = []
sage: results.append(G.triangles_count(algorithm='matrix'))
- sage: results.append(G.triangles_count(algorithm='iter'))
+ sage: results.append(G.triangles_count(algorithm='iter')) # needs sage.modules
sage: results.append(G.triangles_count(algorithm='sparse_copy'))
sage: results.append(G.triangles_count(algorithm='dense_copy'))
sage: any(x != results[0] for x in results)
@@ -17050,7 +17075,8 @@ def shortest_paths(self, u, by_weight=False, algorithm=None,
However, if ``check_weight`` is set to ``False``, unexpected behavior
may occur::
- sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', weight_function=lambda e:e[2], check_weight=False)
+ sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', # needs networkx
+ ....: weight_function=lambda e:e[2], check_weight=False)
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'int' and 'dict'
@@ -17093,7 +17119,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None,
Traceback (most recent call last):
...
RuntimeError: Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead
- sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True)
+ sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) # needs networkx
Traceback (most recent call last):
...
ValueError: ('Contradictory paths found:', 'negative weights?')
@@ -17500,12 +17526,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None,
sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS")
sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython")
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")
- sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
+ sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
- sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
- sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
+ sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy
+ sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy
True
Checking that distances are equal regardless of the algorithm used::
@@ -17514,12 +17540,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None,
sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS")
sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython")
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")
- sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
+ sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
- sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
- sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
+ sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy
+ sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy
True
Checking that weighted distances are equal regardless of the algorithm
@@ -17530,12 +17556,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None,
sage: for v, w in g.edges(labels=False, sort=False):
....: g.add_edge(v, w, random.uniform(1, 10))
sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")
- sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
+ sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
- sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
- sage: d1 == d2 == d3 == d4 == d5 == d6
+ sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy
+ sage: d1 == d2 == d3 == d4 == d5 == d6 # needs networkx scipy
True
Checking a random path is valid::
@@ -17562,7 +17588,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None,
sage: g.shortest_path_all_pairs(algorithm='BFS')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
- sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX')
+ sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') # needs networkx
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 1, 2: 1}, 1: {1: None, 2: 2}, 2: {2: None}})
sage: g.shortest_path_all_pairs(algorithm='Dijkstra_Boost')
@@ -17574,7 +17600,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None,
sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Cython')
({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
- sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy')
+ sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') # needs scipy
({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}},
{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})
@@ -17846,7 +17872,7 @@ def wiener_index(self, by_weight=False, algorithm=None,
15
sage: G.wiener_index(algorithm='Johnson_Boost')
15
- sage: G.wiener_index(algorithm='Dijkstra_NetworkX')
+ sage: G.wiener_index(algorithm='Dijkstra_NetworkX') # needs networkx
15
Wiener index of complete (di)graphs::
@@ -19000,6 +19026,7 @@ def tensor_product(self, other):
The tensor product of two DeBruijn digraphs of same diameter is a DeBruijn digraph::
+ sage: # needs sage.combinat
sage: B1 = digraphs.DeBruijn(2, 3)
sage: B2 = digraphs.DeBruijn(3, 3)
sage: T = B1.tensor_product(B2)
@@ -20243,16 +20270,17 @@ def layout_graphviz(self, dim=2, prog='dot', **options):
By default, an acyclic layout is computed using ``graphviz``'s ``dot``
layout program. One may specify an alternative layout program::
- sage: g.plot(layout="graphviz", prog="dot") # optional - dot2tex graphviz
+ sage: # optional - dot2tex graphviz
+ sage: g.plot(layout="graphviz", prog="dot")
Graphics object consisting of 29 graphics primitives
- sage: g.plot(layout="graphviz", prog="neato") # optional - dot2tex graphviz
+ sage: g.plot(layout="graphviz", prog="neato")
Graphics object consisting of 29 graphics primitives
- sage: g.plot(layout="graphviz", prog="twopi") # optional - dot2tex graphviz
+ sage: g.plot(layout="graphviz", prog="twopi")
Graphics object consisting of 29 graphics primitives
- sage: g.plot(layout="graphviz", prog="fdp") # optional - dot2tex graphviz
+ sage: g.plot(layout="graphviz", prog="fdp")
Graphics object consisting of 29 graphics primitives
sage: g = graphs.BalancedTree(5,2) # needs networkx
- sage: g.plot(layout="graphviz", prog="circo") # optional - dot2tex graphviz, needs networkx
+ sage: g.plot(layout="graphviz", prog="circo") # needs networkx
Graphics object consisting of 62 graphics primitives
.. TODO::
@@ -20277,13 +20305,14 @@ def layout_graphviz(self, dim=2, prog='dot', **options):
Make sure that :trac:`12364` is fixed::
+ sage: # needs sage.combinat sage.modules
sage: m = WordMorphism('a->abb,b->ba')
sage: w = m.fixed_point('a')
sage: prefix = Word(list(w[:100]))
sage: pals = prefix.palindromes()
sage: poset = Poset((pals, lambda x,y: x.is_factor(y)))
sage: H = poset.hasse_diagram()
- sage: d = H.layout_graphviz() # optional - dot2tex graphviz
+ sage: d = H.layout_graphviz() # optional - dot2tex graphviz
"""
assert_have_dot2tex()
assert dim == 2, "3D graphviz layout not implemented"
@@ -20750,6 +20779,7 @@ def plot(self, **options):
::
+ sage: # needs sage.plot
sage: from sage.plot.colors import rainbow
sage: C = graphs.CubeGraph(5)
sage: R = rainbow(5)
@@ -20758,7 +20788,7 @@ def plot(self, **options):
....: for i in range(5):
....: if u[i] != v[i]:
....: edge_colors[R[i]].append((u, v, l))
- sage: C.plot(vertex_labels=False, vertex_size=0, # needs sage.plot
+ sage: C.plot(vertex_labels=False, vertex_size=0,
....: edge_colors=edge_colors).show()
::
@@ -20887,6 +20917,7 @@ def plot(self, **options):
::
+ sage: # needs sage.modular
sage: S = SupersingularModule(389)
sage: H = S.hecke_matrix(2)
sage: D = DiGraph(H, sparse=True)
@@ -21074,9 +21105,9 @@ def plot3d(self, bgcolor=(1, 1, 1),
::
sage: P = graphs.PetersenGraph().to_directed()
- sage: from sage.plot.colors import rainbow
- sage: R = rainbow(P.size(), 'rgbtuple')
- sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())}
+ sage: from sage.plot.colors import rainbow # needs sage.plot
+ sage: R = rainbow(P.size(), 'rgbtuple') # needs sage.plot
+ sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} # needs sage.plot
sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time, needs sage.plot
@@ -21816,12 +21847,12 @@ def graphviz_string(self, **options):
Check that :trac:`25121` is fixed::
sage: G = Graph([(0, 1)])
- sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]})
+ sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) # needs sage.plot
'graph {\n node_0 [label="0"];\n node_1 [label="1"];\n\n node_0 -- node_1 [color = "#4080ff"];\n}'
sage: G = Graph([(0, 1)])
- sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)})
- sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz
+ sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) # needs sage.plot
+ sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz, needs sage.plot
\begin{tikzpicture}[>=latex,line join=bevel,]
...
\definecolor{strokecolor}{rgb}{0.25,0.5,1.0};
@@ -22069,26 +22100,26 @@ def spectrum(self, laplacian=False):
EXAMPLES::
sage: P = graphs.PetersenGraph()
- sage: P.spectrum() # needs sage.modules
+ sage: P.spectrum() # needs sage.modules sage.rings.number_field
[3, 1, 1, 1, 1, 1, -2, -2, -2, -2]
- sage: P.spectrum(laplacian=True) # needs sage.modules
+ sage: P.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field
[5, 5, 5, 5, 2, 2, 2, 2, 2, 0]
sage: D = P.to_directed()
sage: D.delete_edge(7, 9)
- sage: D.spectrum() # needs sage.modules
+ sage: D.spectrum() # needs sage.modules sage.rings.number_field
[2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2]
::
sage: C = graphs.CycleGraph(8)
- sage: C.spectrum() # needs sage.modules
+ sage: C.spectrum() # needs sage.modules sage.rings.number_field
[2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623..., -2]
A digraph may have complex eigenvalues. Previously, the complex parts of
graph eigenvalues were being dropped. For a 3-cycle, we have::
sage: T = DiGraph({0: [1], 1: [2], 2: [0]})
- sage: T.spectrum() # needs sage.modules
+ sage: T.spectrum() # needs sage.modules sage.rings.number_field
[1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I]
TESTS:
@@ -22101,11 +22132,12 @@ def spectrum(self, laplacian=False):
test both the Laplacian construction and the computation of
eigenvalues. ::
+ sage: # needs sage.modules sage.rings.number_field
sage: H = graphs.HoffmanSingletonGraph()
- sage: evals = H.spectrum() # needs sage.modules
- sage: lap = [7 - x for x in evals] # needs sage.modules
- sage: lap.sort(reverse=True) # needs sage.modules
- sage: lap == H.spectrum(laplacian=True) # needs sage.modules
+ sage: evals = H.spectrum()
+ sage: lap = [7 - x for x in evals]
+ sage: lap.sort(reverse=True)
+ sage: lap == H.spectrum(laplacian=True)
True
"""
# Ideally the spectrum should return something like a Factorization object
@@ -22191,7 +22223,7 @@ def eigenvectors(self, laplacian=False):
EXAMPLES::
sage: P = graphs.PetersenGraph()
- sage: P.eigenvectors() # needs sage.modules
+ sage: P.eigenvectors() # needs sage.modules sage.rings.number_field
[(3, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (-2, [
@@ -22211,7 +22243,7 @@ def eigenvectors(self, laplacian=False):
graph is regular. However, since the output also contains the
eigenvalues, the two outputs are slightly different::
- sage: P.eigenvectors(laplacian=True) # needs sage.modules
+ sage: P.eigenvectors(laplacian=True) # needs sage.modules sage.rings.number_field
[(0, [
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
], 1), (5, [
@@ -22230,7 +22262,7 @@ def eigenvectors(self, laplacian=False):
::
sage: C = graphs.CycleGraph(8)
- sage: C.eigenvectors() # needs sage.modules
+ sage: C.eigenvectors() # needs sage.modules sage.rings.number_field
[(2,
[
(1, 1, 1, 1, 1, 1, 1, 1)
@@ -22260,7 +22292,7 @@ def eigenvectors(self, laplacian=False):
graph eigenvalues were being dropped. For a 3-cycle, we have::
sage: T = DiGraph({0:[1], 1:[2], 2:[0]})
- sage: T.eigenvectors() # needs sage.modules
+ sage: T.eigenvectors() # needs sage.modules sage.rings.number_field
[(1,
[
(1, 1, 1)
@@ -22301,7 +22333,7 @@ def eigenspaces(self, laplacian=False):
EXAMPLES::
sage: P = graphs.PetersenGraph()
- sage: P.eigenspaces() # needs sage.modules
+ sage: P.eigenspaces() # needs sage.modules sage.rings.number_field
[
(3, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:
@@ -22325,7 +22357,7 @@ def eigenspaces(self, laplacian=False):
graph is regular. However, since the output also contains the
eigenvalues, the two outputs are slightly different::
- sage: P.eigenspaces(laplacian=True) # needs sage.modules
+ sage: P.eigenspaces(laplacian=True) # needs sage.modules sage.rings.number_field
[
(0, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:
@@ -22350,7 +22382,7 @@ def eigenspaces(self, laplacian=False):
corresponding eigenspace::
sage: C = graphs.CycleGraph(8)
- sage: C.eigenspaces() # needs sage.modules
+ sage: C.eigenspaces() # needs sage.modules sage.rings.number_field
[
(2, Vector space of degree 8 and dimension 1 over Rational Field
User basis matrix:
@@ -22373,7 +22405,7 @@ def eigenspaces(self, laplacian=False):
we have::
sage: T = DiGraph({0: [1], 1: [2], 2: [0]})
- sage: T.eigenspaces() # needs sage.modules
+ sage: T.eigenspaces() # needs sage.modules sage.rings.number_field
[
(1, Vector space of degree 3 and dimension 1 over Rational Field
User basis matrix:
@@ -22962,6 +22994,7 @@ def automorphism_group(self, partition=None, verbosity=0,
Graphs::
+ sage: # needs sage.groups
sage: graphs_query = GraphQuery(display_cols=['graph6'],num_vertices=4)
sage: L = graphs_query.get_graphs_list()
sage: graphs_list.show_graphs(L) # needs sage.plot
@@ -22989,6 +23022,7 @@ def automorphism_group(self, partition=None, verbosity=0,
::
+ sage: # needs sage.groups
sage: D = graphs.DodecahedralGraph()
sage: G = D.automorphism_group()
sage: A5 = AlternatingGroup(5)
@@ -23003,34 +23037,35 @@ def automorphism_group(self, partition=None, verbosity=0,
sage: G.add_edge(('a', 'b'))
sage: G.add_edge(('a', 'b'))
sage: G.add_edge(('a', 'b'))
- sage: G.automorphism_group()
+ sage: G.automorphism_group() # needs sage.groups
Permutation Group with generators [('a','b')]
Digraphs::
sage: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } )
- sage: D.automorphism_group()
+ sage: D.automorphism_group() # needs sage.groups
Permutation Group with generators [(0,1,2,3,4)]
Edge labeled graphs::
sage: G = Graph(sparse=True)
sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] )
- sage: G.automorphism_group(edge_labels=True)
+ sage: G.automorphism_group(edge_labels=True) # needs sage.groups
Permutation Group with generators [(1,4)(2,3)]
sage: G.automorphism_group(edge_labels=True, algorithm="bliss") # optional - bliss
Permutation Group with generators [(1,4)(2,3)]
- sage: G.automorphism_group(edge_labels=True, algorithm="sage")
+ sage: G.automorphism_group(edge_labels=True, algorithm="sage") # needs sage.groups
Permutation Group with generators [(1,4)(2,3)]
::
sage: G = Graph({0 : {1 : 7}})
- sage: G.automorphism_group(edge_labels=True)
+ sage: G.automorphism_group(edge_labels=True) # needs sage.groups
Permutation Group with generators [(0,1)]
+ sage: # needs sage.groups
sage: foo = Graph(sparse=True)
sage: bar = Graph(sparse=True)
sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)])
@@ -23045,13 +23080,14 @@ def automorphism_group(self, partition=None, verbosity=0,
You can also ask for just the order of the group::
sage: G = graphs.PetersenGraph()
- sage: G.automorphism_group(return_group=False, order=True)
+ sage: G.automorphism_group(return_group=False, order=True) # needs sage.groups
120
Or, just the orbits (note that each graph here is vertex transitive)
::
+ sage: # needs sage.groups
sage: G = graphs.PetersenGraph()
sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage')
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
@@ -23069,9 +23105,9 @@ def automorphism_group(self, partition=None, verbosity=0,
sage: # optional - bliss
sage: G = graphs.HallJankoGraph()
- sage: A1 = G.automorphism_group()
+ sage: A1 = G.automorphism_group() # needs sage.groups
sage: A2 = G.automorphism_group(algorithm='bliss')
- sage: A1.is_isomorphic(A2)
+ sage: A1.is_isomorphic(A2) # needs sage.groups
True
TESTS:
@@ -23080,13 +23116,14 @@ def automorphism_group(self, partition=None, verbosity=0,
sage: g=graphs.CubeGraph(3)
sage: g.relabel()
- sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage')
+ sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') # needs sage.groups
Traceback (most recent call last):
...
KeyError: ...
Labeled automorphism group::
+ sage: # needs sage.combinat sage.groups
sage: d = digraphs.DeBruijn(3,2)
sage: A = d.automorphism_group(algorithm='sage')
sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')",
@@ -23103,24 +23140,24 @@ def automorphism_group(self, partition=None, verbosity=0,
The labeling is correct::
sage: g = graphs.PetersenGraph()
- sage: ag = g.automorphism_group()
- sage: all(len(ag.orbit(e, action="OnPairs")) == 30
+ sage: ag = g.automorphism_group() # needs sage.groups
+ sage: all(len(ag.orbit(e, action="OnPairs")) == 30 # needs sage.groups
....: for e in g.edge_iterator(labels=False))
True
Empty group, correct domain::
- sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group()
- sage: ag
+ sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() # needs sage.groups
+ sage: ag # needs sage.groups
Permutation Group with generators [()]
- sage: sorted(ag.domain())
+ sage: sorted(ag.domain()) # needs sage.groups
['a', 'b']
We can check that the subgroups are labelled correctly
(:trac:`15656`)::
sage: G1 = Graph(':H`ECw@HGXGAGUG`e')
- sage: G = G1.automorphism_group()
+ sage: G = G1.automorphism_group() # needs sage.groups
sage: G.subgroups()
[Subgroup generated by [()] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]),
Subgroup generated by [(0,7)(1,4)(2,3)(6,8)] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)])]
@@ -23128,6 +23165,7 @@ def automorphism_group(self, partition=None, verbosity=0,
We check that the representations of the groups returned with ``'sage'``
and ``'bliss'`` are the same (:trac:`27571`)::
+ sage: # needs sage.groups sage.libs.pari
sage: G = graphs.PaleyGraph(9)
sage: a1 = G.automorphism_group(algorithm='sage')
sage: V = sorted(G, reverse=True)
@@ -23139,8 +23177,9 @@ def automorphism_group(self, partition=None, verbosity=0,
sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss
sage: str(a1) == str(b1) # optional - bliss
True
- sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss
- sage: str(a2) == str(b2) # optional - bliss
+ sage: b2 = G.automorphism_group(algorithm='bliss', # optional - bliss
+ ....: partition=[V])
+ sage: str(a2) == str(b2) # optional - bliss
True
"""
from sage.features.bliss import Bliss
@@ -23387,19 +23426,19 @@ def is_hamiltonian(self, solver=None, constraint_generation=None,
The Heawood Graph is known to be Hamiltonian ::
sage: g = graphs.HeawoodGraph()
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
The Petergraph, though, is not ::
sage: g = graphs.PetersenGraph()
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
False
TESTS::
sage: g = graphs.ChvatalGraph()
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
:trac:`16210`::
@@ -23407,7 +23446,7 @@ def is_hamiltonian(self, solver=None, constraint_generation=None,
sage: g = graphs.CycleGraph(10)
sage: g.allow_loops(True)
sage: g.add_edge(0,0)
- sage: g.is_hamiltonian()
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
True
"""
from sage.categories.sets_cat import EmptySetError
@@ -23904,7 +23943,7 @@ class by some canonization function `c`. If `G` and `H` are graphs,
sage: algos = ['sage']
sage: algos.append('bliss') # optional - bliss
sage: S = Set([0,1,2])
- sage: for (algo, edges) in product(algos, edges_list):
+ sage: for (algo, edges) in product(algos, edges_list): # needs sage.combinat
....: L = cartesian_product([S] * len(edges))
....: O = OrderedSetPartitions([0,1,2,3])
....: P = Permutations([0,1,2,3])
@@ -24058,11 +24097,12 @@ def is_cayley(self, return_group=False, mapping=False,
Graphs with loops and multiedges will have identity and repeated
elements, respectively, among the generators::
+ sage: # needs sage.rings.finite_rings
sage: g = Graph(graphs.PaleyGraph(9), loops=True, multiedges=True)
sage: g.add_edges([(u, u) for u in g])
sage: g.add_edges([(u, u+1) for u in g])
- sage: _, S = g.is_cayley(generators=True)
- sage: S # random
+ sage: _, S = g.is_cayley(generators=True) # needs sage.groups
+ sage: S # random # needs sage.groups
[(),
(0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1),
(0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1),
@@ -24075,24 +24115,27 @@ def is_cayley(self, return_group=False, mapping=False,
Cayley graphs can be reconstructed from the group and generating set::
- sage: g = graphs.PaleyGraph(9)
- sage: _, G, S = g.is_cayley(return_group=True, generators=True)
- sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g)
+ sage: g = graphs.PaleyGraph(9) # needs sage.rings.finite_rings
+ sage: _, G, S = g.is_cayley(return_group=True, generators=True) # needs sage.groups sage.rings.finite_rings
+ sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) # needs sage.groups sage.rings.finite_rings
True
A disconnected graphs may also be a Cayley graph::
+ sage: # needs sage.rings.finite_rings
sage: g = graphs.PaleyGraph(9)
sage: h = g.disjoint_union(g)
sage: h = h.disjoint_union(h)
sage: h = h.disjoint_union(g)
- sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, generators=True, allow_disconnected=True)
- sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) for v in h)
+ sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, # needs sage.groups
+ ....: generators=True, allow_disconnected=True)
+ sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) # needs sage.groups
+ ....: for v in h)
True
The method also works efficiently with dense simple graphs::
- sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley()
+ sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() # needs sage.groups
True
TESTS::
@@ -24198,8 +24241,8 @@ def is_self_complementary(self):
Every Paley graph is self-complementary::
- sage: G = graphs.PaleyGraph(9)
- sage: G.is_self_complementary()
+ sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari
+ sage: G.is_self_complementary() # needs sage.libs.pari
True
TESTS:
@@ -24327,7 +24370,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
We find the Katz matrix of an undirected 4-cycle. ::
sage: G = graphs.CycleGraph(4)
- sage: G.katz_matrix(1/20) # needs sage.modules
+ sage: G.katz_matrix(1/20) # needs sage.modules sage.rings.number_field
[1/198 5/99 1/198 5/99]
[ 5/99 1/198 5/99 1/198]
[1/198 5/99 1/198 5/99]
@@ -24336,7 +24379,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
We find the Katz matrix of an undirected 4-cycle with all entries
other than those which correspond to non-edges zeroed out. ::
- sage: G.katz_matrix(1/20, True) # needs sage.modules
+ sage: G.katz_matrix(1/20, True) # needs sage.modules sage.rings.number_field
[ 0 0 1/198 0]
[ 0 0 0 1/198]
[1/198 0 0 0]
@@ -24348,7 +24391,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
We find the Katz matrix in a fan on 6 vertices. ::
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
- sage: H.katz_matrix(1/10) # needs sage.modules
+ sage: H.katz_matrix(1/10) # needs sage.modules sage.rings.number_field
[ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512]
[ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024]
[ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376]
@@ -24364,7 +24407,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
TESTS::
- sage: # needs sage.modules
+ sage: # needs sage.modules sage.rings.number_field
sage: (graphs.CompleteGraph(4)).katz_matrix(1/4)
[3/5 4/5 4/5 4/5]
[4/5 3/5 4/5 4/5]
@@ -24683,7 +24726,7 @@ def symmetric_edge_polytope(self, backend=None):
....: break
....: else:
....: polys.append(P)
- sage: len(polys)
+ sage: len(polys) # needs sage.geometry.polyhedron
25
A non-trivial example of two graphs with isomorphic SEPs::
diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx
index 45867176382..0e05f3a4ec9 100644
--- a/src/sage/graphs/generic_graph_pyx.pyx
+++ b/src/sage/graphs/generic_graph_pyx.pyx
@@ -400,7 +400,7 @@ cdef inline double sqrt_approx(double x, double y, double xx, double yy):
....: y = abs(y)
....: return max(x,y) + min(x,y)**2/(2*max(x,y))
- sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # optional - sage.plot
+ sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # needs sage.plot
Graphics object consisting of 2 graphics primitives
"""
if xx < yy:
@@ -651,7 +651,7 @@ cdef class SubgraphSearch:
EXAMPLES::
sage: g = graphs.PetersenGraph()
- sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules
+ sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices
TESTS:
@@ -661,11 +661,11 @@ cdef class SubgraphSearch:
computations with it::
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
- sage: SubgraphSearch(Graph(5), Graph(1)) # optional - sage.modules
+ sage: SubgraphSearch(Graph(5), Graph(1)) # needs sage.modules
Traceback (most recent call last):
...
ValueError: searched graph should have at least 2 vertices
- sage: SubgraphSearch(Graph(5), Graph(2)) # optional - sage.modules
+ sage: SubgraphSearch(Graph(5), Graph(2)) # needs sage.modules
"""
if H.order() <= 1:
@@ -691,8 +691,8 @@ cdef class SubgraphSearch:
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: g = graphs.PathGraph(5)
sage: h = graphs.PathGraph(3)
- sage: S = SubgraphSearch(g, h) # optional - sage.modules
- sage: for p in S: # optional - sage.modules
+ sage: S = SubgraphSearch(g, h) # needs sage.modules
+ sage: for p in S: # needs sage.modules
....: print(p)
[0, 1, 2]
[1, 2, 3]
@@ -722,8 +722,8 @@ cdef class SubgraphSearch:
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: g = graphs.PathGraph(5)
sage: h = graphs.PathGraph(3)
- sage: S = SubgraphSearch(g, h) # optional - sage.modules
- sage: S.cardinality() # optional - sage.modules
+ sage: S = SubgraphSearch(g, h) # needs sage.modules
+ sage: S.cardinality() # needs sage.modules
6
Check that the method is working even when vertices or edges are of
@@ -734,8 +734,8 @@ cdef class SubgraphSearch:
sage: G.add_cycle(['A', 1, 2, 3, ('a', 1)])
sage: H = Graph()
sage: H.add_path("xyz")
- sage: S = SubgraphSearch(G, H) # optional - sage.modules
- sage: S.cardinality() # optional - sage.modules
+ sage: S = SubgraphSearch(G, H) # needs sage.modules
+ sage: S.cardinality() # needs sage.modules
10
"""
if self.nh > self.ng:
@@ -769,18 +769,18 @@ cdef class SubgraphSearch:
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: g = graphs.PathGraph(5)
sage: h = graphs.PathGraph(3)
- sage: S = SubgraphSearch(g, h) # optional - sage.modules
- sage: S.__next__() # optional - sage.modules
+ sage: S = SubgraphSearch(g, h) # needs sage.modules
+ sage: S.__next__() # needs sage.modules
[0, 1, 2]
- sage: S._initialization() # optional - sage.modules
- sage: S.__next__() # optional - sage.modules
+ sage: S._initialization() # needs sage.modules
+ sage: S.__next__() # needs sage.modules
[0, 1, 2]
TESTS:
Check that :trac:`21828` is fixed::
- sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # optional - sage.modules
+ sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # needs sage.modules
True
"""
cdef int i
@@ -815,7 +815,7 @@ cdef class SubgraphSearch:
EXAMPLES::
sage: g = graphs.PetersenGraph()
- sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules
+ sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices
"""
self.mem = MemoryAllocator()
@@ -904,8 +904,8 @@ cdef class SubgraphSearch:
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: g = graphs.PathGraph(5)
sage: h = graphs.PathGraph(3)
- sage: S = SubgraphSearch(g, h) # optional - sage.modules
- sage: S.__next__() # optional - sage.modules
+ sage: S = SubgraphSearch(g, h) # needs sage.modules
+ sage: S.__next__() # needs sage.modules
[0, 1, 2]
"""
if not self.ng:
diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py
index e2c86f69d40..30a63bff8a7 100644
--- a/src/sage/graphs/graph.py
+++ b/src/sage/graphs/graph.py
@@ -106,16 +106,17 @@
5: [7, 8], 6: [8,9], 7: [9]}
sage: G = Graph(d); G
Graph on 10 vertices
- sage: G.plot().show() # or G.show() # optional - sage.plot
+ sage: G.plot().show() # or G.show() # needs sage.plot
- A NetworkX graph:
::
- sage: import networkx # optional - networkx
- sage: K = networkx.complete_bipartite_graph(12,7) # optional - networkx
- sage: G = Graph(K) # optional - networkx
- sage: G.degree() # optional - networkx
+ sage: # needs networkx
+ sage: import networkx
+ sage: K = networkx.complete_bipartite_graph(12,7)
+ sage: G = Graph(K)
+ sage: G.degree()
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12]
- graph6 or sparse6 format:
@@ -125,7 +126,7 @@
sage: s = ':I`AKGsaOs`cI]Gb~'
sage: G = Graph(s, sparse=True); G
Looped multi-graph on 10 vertices
- sage: G.plot().show() # or G.show() # optional - sage.plot
+ sage: G.plot().show() # or G.show() # needs sage.plot
Note that the ``\`` character is an escape character in Python, and also a
character used by graph6 strings:
@@ -142,17 +143,18 @@
::
sage: G = Graph('Ihe\\n@GUA')
- sage: G.plot().show() # or G.show() # optional - sage.plot
+ sage: G.plot().show() # or G.show() # needs sage.plot
- adjacency matrix: In an adjacency matrix, each column and each row represent a
vertex. If a 1 shows up in row `i`, column `j`, there is an edge `(i,j)`.
::
- sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \
- (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \
- (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \
- (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)])
+ sage: # needs sage.modules
+ sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0),
+ ....: (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),
+ ....: (1,0,0,1,0,0,0,0,0,1), (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),
+ ....: (0,0,1,0,0,1,0,0,0,1), (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)])
sage: M
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
@@ -166,13 +168,14 @@
[0 0 0 0 1 0 1 1 0 0]
sage: G = Graph(M); G
Graph on 10 vertices
- sage: G.plot().show() # or G.show() # optional - sage.plot
+ sage: G.plot().show() # or G.show() # needs sage.plot
- incidence matrix: In an incidence matrix, each row represents a vertex and
each column represents an edge.
::
+ sage: # needs sage.modules
sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0),
....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0),
....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0),
@@ -196,8 +199,8 @@
[ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1]
sage: G = Graph(M); G
Graph on 10 vertices
- sage: G.plot().show() # or G.show() # optional - sage.plot
- sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix")
+ sage: G.plot().show() # or G.show() # needs sage.plot
+ sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix")
Traceback (most recent call last):
...
ValueError: there must be two nonzero entries (-1 & 1) per column
@@ -254,10 +257,10 @@
::
sage: G = graphs.PetersenGraph()
- sage: G.plot().show() # or G.show() # optional - sage.plot
+ sage: G.plot().show() # or G.show() # needs sage.plot
sage: G.degree_histogram()
[0, 0, 0, 10]
- sage: G.adjacency_matrix()
+ sage: G.adjacency_matrix() # needs sage.modules
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 1 0 0]
@@ -272,7 +275,7 @@
::
sage: S = G.subgraph([0,1,2,3])
- sage: S.plot().show() # or S.show() # optional - sage.plot
+ sage: S.plot().show() # or S.show() # needs sage.plot
sage: S.density()
1/2
@@ -280,7 +283,7 @@
sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5)
sage: L = G.get_graphs_list()
- sage: graphs_list.show_graphs(L) # optional - sage.plot
+ sage: graphs_list.show_graphs(L) # needs sage.plot
.. _Graph:labels:
@@ -295,8 +298,8 @@
Note that vertex labels themselves cannot be mutable items::
- sage: M = Matrix( [[0,0],[0,0]] )
- sage: G = Graph({ 0 : { M : None } })
+ sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules
+ sage: G = Graph({ 0 : { M : None } }) # needs sage.modules
Traceback (most recent call last):
...
TypeError: mutable matrices are unhashable
@@ -349,7 +352,7 @@
Show each graph as you iterate through the results::
- sage: for g in Q: # optional - sage.plot
+ sage: for g in Q: # needs sage.plot
....: show(g)
Visualization
@@ -359,11 +362,11 @@
view the graph in two dimensions via matplotlib with ``show()``. ::
sage: G = graphs.RandomGNP(15,.3)
- sage: G.show() # optional - sage.plot
+ sage: G.show() # needs sage.plot
And you can view it in three dimensions via jmol with ``show3d()``. ::
- sage: G.show3d() # optional - sage.plot
+ sage: G.show3d() # needs sage.plot
Or it can be rendered with `\LaTeX`. This requires the right additions to a
standard `\mbox{\rm\TeX}` installation. Then standard Sage commands, such as
@@ -608,8 +611,8 @@ class Graph(GenericGraph):
'out' is the label for the edge on 2 and 5. Labels can be used as
weights, if all the labels share some common parent.::
- sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # optional - sage.groups
- sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # optional - sage.groups
+ sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # needs sage.groups
+ sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # needs sage.groups
Graph on 4 vertices
#. A dictionary of lists::
@@ -623,10 +626,10 @@ class Graph(GenericGraph):
Construct the Paley graph over GF(13).::
- sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()])
- sage: g.vertices(sort=True)
+ sage: g = Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) # needs sage.rings.finite_rings
+ sage: g.vertices(sort=True) # needs sage.rings.finite_rings
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
- sage: g.adjacency_matrix()
+ sage: g.adjacency_matrix() # needs sage.modules sage.rings.finite_rings
[0 1 0 1 1 0 0 0 0 1 1 0 1]
[1 0 1 0 1 1 0 0 0 0 1 1 0]
[0 1 0 1 0 1 1 0 0 0 0 1 1]
@@ -649,7 +652,7 @@ class Graph(GenericGraph):
loops=False)
sage: line_graph.vertices(sort=True)
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
- sage: line_graph.adjacency_matrix()
+ sage: line_graph.adjacency_matrix() # needs sage.modules
[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
@@ -697,7 +700,7 @@ class Graph(GenericGraph):
- an adjacency matrix::
- sage: M = graphs.PetersenGraph().am(); M
+ sage: M = graphs.PetersenGraph().am(); M # needs sage.modules
[0 1 0 0 1 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 1 0 0]
@@ -708,82 +711,85 @@ class Graph(GenericGraph):
[0 0 1 0 0 1 0 0 0 1]
[0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 1 0 1 1 0 0]
- sage: Graph(M)
+ sage: Graph(M) # needs sage.modules
Graph on 10 vertices
::
- sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True)
+ sage: Graph(matrix([[1,2], [2,4]]), loops=True, sparse=True) # needs sage.modules
Looped multi-graph on 2 vertices
- sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M
+ sage: M = Matrix([[0,1,-1], [1,0,-1/2], [-1,-1/2,0]]); M # needs sage.modules
[ 0 1 -1]
[ 1 0 -1/2]
[ -1 -1/2 0]
- sage: G = Graph(M,sparse=True); G
+ sage: G = Graph(M, sparse=True); G # needs sage.modules
Graph on 3 vertices
- sage: G.weighted()
+ sage: G.weighted() # needs sage.modules
True
- an incidence matrix::
- sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M
+ sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules
+ ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M
[-1 0 0 0 1]
[ 1 -1 0 0 0]
[ 0 1 -1 0 0]
[ 0 0 1 -1 0]
[ 0 0 0 1 -1]
[ 0 0 0 0 0]
- sage: Graph(M)
+ sage: Graph(M) # needs sage.modules
Graph on 6 vertices
- sage: Graph(Matrix([[1],[1],[1]]))
+ sage: Graph(Matrix([[1],[1],[1]])) # needs sage.modules
Traceback (most recent call last):
...
- ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0
- sage: Graph(Matrix([[1],[1],[0]]))
+ ValueError: there must be one or two nonzero entries per column
+ in an incidence matrix, got entries [1, 1, 1] in column 0
+ sage: Graph(Matrix([[1],[1],[0]])) # needs sage.modules
Graph on 3 vertices
- sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M
+ sage: M = Matrix([[0,1,-1], [1,0,-1], [-1,-1,0]]); M # needs sage.modules
[ 0 1 -1]
[ 1 0 -1]
[-1 -1 0]
- sage: Graph(M,sparse=True)
+ sage: Graph(M, sparse=True) # needs sage.modules
Graph on 3 vertices
- sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M
+ sage: M = Matrix([[0,1,1], [1,0,1], [-1,-1,0]]); M # needs sage.modules
[ 0 1 1]
[ 1 0 1]
[-1 -1 0]
- sage: Graph(M)
+ sage: Graph(M) # needs sage.modules
Traceback (most recent call last):
...
ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1] in column 2
Check that :trac:`9714` is fixed::
+ sage: # needs sage.modules
sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]])
sage: GA = Graph(MA, format='adjacency_matrix')
- sage: MI = GA.incidence_matrix(oriented=False)
- sage: MI
+ sage: MI = GA.incidence_matrix(oriented=False); MI
[2 1 1 0 0 0]
[0 1 1 2 2 0]
[0 0 0 0 0 2]
sage: Graph(MI).edges(sort=True, labels=None)
[(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]
- sage: M = Matrix([[1], [-1]]); M
+ sage: M = Matrix([[1], [-1]]); M # needs sage.modules
[ 1]
[-1]
- sage: Graph(M).edges(sort=True)
+ sage: Graph(M).edges(sort=True) # needs sage.modules
[(0, 1, None)]
#. A Seidel adjacency matrix::
- sage: from sage.combinat.matrices.hadamard_matrix import \
- ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd
- sage: m=rshcd(16,1)- matrix.identity(16)
- sage: Graph(m,format="seidel_adjacency_matrix").is_strongly_regular(parameters=True)
+ sage: from sage.combinat.matrices.hadamard_matrix import ( # needs sage.modules
+ ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd)
+ sage: m = rshcd(16,1) - matrix.identity(16) # needs sage.modules
+ sage: Graph(m, # needs sage.modules
+ ....: format="seidel_adjacency_matrix").is_strongly_regular(parameters=True)
(16, 6, 2, 2)
#. List of edges, or labelled edges::
@@ -801,16 +807,16 @@ class Graph(GenericGraph):
#. A NetworkX MultiGraph::
- sage: import networkx # optional - networkx
- sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # optional - networkx
- sage: Graph(g) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # needs networkx
+ sage: Graph(g) # needs networkx
Multi-graph on 5 vertices
#. A NetworkX graph::
- sage: import networkx # optional - networkx
- sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # optional - networkx
- sage: DiGraph(g) # optional - networkx
+ sage: import networkx # needs networkx
+ sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # needs networkx
+ sage: DiGraph(g) # needs networkx
Digraph on 5 vertices
#. An igraph Graph (see also
@@ -824,11 +830,12 @@ class Graph(GenericGraph):
If ``vertex_labels`` is ``True``, the names of the vertices are given by
the vertex attribute ``'name'``, if available::
- sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) # optional - python_igraph
- sage: Graph(g).vertices(sort=True) # optional - python_igraph
+ sage: # optional - python_igraph
+ sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']})
+ sage: Graph(g).vertices(sort=True)
['a', 'b', 'c']
- sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) # optional - python_igraph
- sage: Graph(g).vertices(sort=True) # optional - python_igraph
+ sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']})
+ sage: Graph(g).vertices(sort=True)
[0, 1, 2]
If the igraph Graph has edge attributes, they are used as edge labels::
@@ -883,6 +890,7 @@ class Graph(GenericGraph):
...
ValueError: An *undirected* igraph graph was expected. To build an directed graph, call the DiGraph constructor.
+ sage: # needs sage.modules
sage: m = matrix([[0, -1], [-1, 0]])
sage: Graph(m, format="seidel_adjacency_matrix")
Graph on 2 vertices
@@ -892,8 +900,8 @@ class Graph(GenericGraph):
...
ValueError: the adjacency matrix of a Seidel graph must be symmetric
- sage: m[0,1] = -1; m[1,1] = 1
- sage: Graph(m, format="seidel_adjacency_matrix")
+ sage: m[0,1] = -1; m[1,1] = 1 # needs sage.modules
+ sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules
Traceback (most recent call last):
...
ValueError: the adjacency matrix of a Seidel graph must have 0s on the main diagonal
@@ -907,7 +915,7 @@ class Graph(GenericGraph):
Check that :trac:`27505` is fixed::
- sage: Graph(Graph().networkx_graph(), weighted=None, format='NX')
+ sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') # needs networkx
Graph on 0 vertices
"""
_directed = False
@@ -923,12 +931,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
sage: G = Graph()
sage: loads(dumps(G)) == G
True
- sage: a = matrix(2,2,[1,0,0,1])
- sage: Graph(a).adjacency_matrix() == a
+ sage: a = matrix(2,2,[1,0,0,1]) # needs sage.modules
+ sage: Graph(a).adjacency_matrix() == a # needs sage.modules
True
- sage: a = matrix(2,2,[2,0,0,1])
- sage: Graph(a,sparse=True).adjacency_matrix() == a
+ sage: a = matrix(2,2,[2,0,0,1]) # needs sage.modules
+ sage: Graph(a,sparse=True).adjacency_matrix() == a # needs sage.modules
True
The positions are copied when the graph is built from another graph ::
@@ -973,7 +981,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
Verify that the int format works as expected (:trac:`12557`)::
- sage: Graph(2).adjacency_matrix()
+ sage: Graph(2).adjacency_matrix() # needs sage.modules
[0 0]
[0 0]
sage: Graph(3) == Graph(3,format='int')
@@ -982,10 +990,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
Problem with weighted adjacency matrix (:trac:`13919`)::
sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{6:7}}
- sage: grafo3 = Graph(B,weighted=True)
- sage: matad = grafo3.weighted_adjacency_matrix()
- sage: grafo4 = Graph(matad,format = "adjacency_matrix", weighted=True)
- sage: grafo4.shortest_path(0,6,by_weight=True)
+ sage: grafo3 = Graph(B, weighted=True)
+ sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules
+ sage: grafo4 = Graph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules
+ sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules
[0, 1, 2, 5, 4, 6]
Graphs returned when setting ``immutable=False`` are mutable::
@@ -1003,15 +1011,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
Check error messages for graphs built from incidence matrices (see
:trac:`18440`)::
- sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]]))
+ sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) # needs sage.modules
Traceback (most recent call last):
...
- ValueError: column 1 of the (oriented) incidence matrix contains only one nonzero value
- sage: Graph(matrix([[1,1],[1,1],[1,0]]))
+ ValueError: column 1 of the (oriented) incidence matrix
+ contains only one nonzero value
+ sage: Graph(matrix([[1,1],[1,1],[1,0]])) # needs sage.modules
Traceback (most recent call last):
...
- ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0
- sage: Graph(matrix([[3,1,1],[0,1,1]]))
+ ValueError: there must be one or two nonzero entries per column
+ in an incidence matrix, got entries [1, 1, 1] in column 0
+ sage: Graph(matrix([[3,1,1],[0,1,1]])) # needs sage.modules
Traceback (most recent call last):
...
ValueError: each column of a non-oriented incidence matrix must sum to 2, but column 0 does not
@@ -1695,7 +1705,7 @@ def is_cactus(self):
Test a graph that is not outerplanar, see :trac:`24480`::
- sage: graphs.Balaban10Cage().is_cactus()
+ sage: graphs.Balaban10Cage().is_cactus() # needs networkx
False
"""
self._scream_if_not_simple()
@@ -1816,7 +1826,7 @@ def is_cograph(self):
sage: graphs.HouseXGraph().is_cograph()
True
- sage: graphs.HouseGraph().is_cograph()
+ sage: graphs.HouseGraph().is_cograph() # needs sage.modules
False
.. TODO::
@@ -1827,9 +1837,9 @@ def is_cograph(self):
TESTS::
- sage: [graphs.PathGraph(i).is_cograph() for i in range(6)]
+ sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] # needs sage.modules
[True, True, True, True, False, False]
- sage: graphs.CycleGraph(5).is_cograph() # Self-complemented
+ sage: graphs.CycleGraph(5).is_cograph() # Self-complemented # needs sage.modules
False
"""
# A cograph has no 4-vertex path as an induced subgraph.
@@ -2136,7 +2146,7 @@ def is_overfull(self):
sage: g = graphs.ClawGraph()
sage: g
Claw graph: Graph on 4 vertices
- sage: edge_coloring(g, value_only=True)
+ sage: edge_coloring(g, value_only=True) # needs sage.numerical_mip
3
sage: g.is_overfull()
False
@@ -2191,7 +2201,7 @@ def is_overfull(self):
sage: g.is_overfull()
False
sage: from sage.graphs.graph_coloring import edge_coloring
- sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True)
+ sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) # needs sage.numerical_mip
True
"""
# # A possible optimized version. But the gain in speed is very little.
@@ -2226,25 +2236,25 @@ def is_even_hole_free(self, certificate=False):
Is the Petersen Graph even-hole-free ::
sage: g = graphs.PetersenGraph()
- sage: g.is_even_hole_free()
+ sage: g.is_even_hole_free() # needs sage.modules
False
As any chordal graph is hole-free, interval graphs behave the same way::
sage: g = graphs.RandomIntervalGraph(20)
- sage: g.is_even_hole_free()
+ sage: g.is_even_hole_free() # needs sage.modules
True
It is clear, though, that a random Bipartite Graph which is not a forest
has an even hole::
- sage: g = graphs.RandomBipartite(10, 10, .5)
- sage: g.is_even_hole_free() and not g.is_forest()
+ sage: g = graphs.RandomBipartite(10, 10, .5) # needs numpy
+ sage: g.is_even_hole_free() and not g.is_forest() # needs numpy sage.modules
False
We can check the certificate returned is indeed an even cycle::
- sage: if not g.is_forest():
+ sage: if not g.is_forest(): # needs numpy sage.modules
....: cycle = g.is_even_hole_free(certificate=True)
....: if cycle.order() % 2 == 1:
....: print("Error !")
@@ -2259,17 +2269,18 @@ def is_even_hole_free(self, certificate=False):
Bug reported in :trac:`9925`, and fixed by :trac:`9420`::
- sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', loops=False, multiedges=False)
- sage: g.is_even_hole_free()
+ sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF',
+ ....: loops=False, multiedges=False)
+ sage: g.is_even_hole_free() # needs sage.modules
False
- sage: g.is_even_hole_free(certificate=True)
+ sage: g.is_even_hole_free(certificate=True) # needs sage.modules
Subgraph of (): Graph on 4 vertices
Making sure there are no other counter-examples around ::
sage: t = lambda x: (Graph(x).is_forest() or
....: isinstance(Graph(x).is_even_hole_free(certificate=True), Graph))
- sage: all( t(graphs.RandomBipartite(10, 10, .5)) for i in range(100) )
+ sage: all(t(graphs.RandomBipartite(10, 10, .5)) for i in range(100)) # needs numpy sage.modules
True
"""
girth = self.girth()
@@ -2326,7 +2337,7 @@ def is_odd_hole_free(self, certificate=False):
Is the Petersen Graph odd-hole-free ::
sage: g = graphs.PetersenGraph()
- sage: g.is_odd_hole_free()
+ sage: g.is_odd_hole_free() # needs sage.modules
False
Which was to be expected, as its girth is 5 ::
@@ -2336,14 +2347,14 @@ def is_odd_hole_free(self, certificate=False):
We can check the certificate returned is indeed a 5-cycle::
- sage: cycle = g.is_odd_hole_free(certificate=True)
- sage: cycle.is_isomorphic(graphs.CycleGraph(5))
+ sage: cycle = g.is_odd_hole_free(certificate=True) # needs sage.modules
+ sage: cycle.is_isomorphic(graphs.CycleGraph(5)) # needs sage.modules
True
As any chordal graph is hole-free, no interval graph has an odd hole::
sage: g = graphs.RandomIntervalGraph(20)
- sage: g.is_odd_hole_free()
+ sage: g.is_odd_hole_free() # needs sage.modules
True
"""
girth = self.odd_girth()
@@ -2409,7 +2420,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False):
or a complete Bipartite Graph::
sage: G = graphs.CompleteBipartiteGraph(5,6)
- sage: G.is_triangle_free(algorithm='matrix')
+ sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules
True
sage: G.is_triangle_free(algorithm='bitset')
True
@@ -2419,7 +2430,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False):
a tripartite graph, though, contains many triangles::
sage: G = (3 * graphs.CompleteGraph(5)).complement()
- sage: G.is_triangle_free(algorithm='matrix')
+ sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules
False
sage: G.is_triangle_free(algorithm='bitset')
False
@@ -2542,8 +2553,11 @@ def is_split(self):
graph if and only if does not contain the 4-cycle, 5-cycle or `2K_2` as
an induced subgraph. Hence for the above graph we have::
- sage: forbidden_subgraphs = [graphs.CycleGraph(4), graphs.CycleGraph(5), 2 * graphs.CompleteGraph(2)]
- sage: sum(g.subgraph_search_count(H,induced=True) for H in forbidden_subgraphs)
+ sage: forbidden_subgraphs = [graphs.CycleGraph(4),
+ ....: graphs.CycleGraph(5),
+ ....: 2 * graphs.CompleteGraph(2)]
+ sage: sum(g.subgraph_search_count(H, induced=True) # needs sage.modules
+ ....: for H in forbidden_subgraphs)
0
"""
self._scream_if_not_simple()
@@ -2593,45 +2607,45 @@ def is_perfect(self, certificate=False):
A Bipartite Graph is always perfect ::
- sage: g = graphs.RandomBipartite(8,4,.5)
- sage: g.is_perfect()
+ sage: g = graphs.RandomBipartite(8,4,.5) # needs numpy
+ sage: g.is_perfect() # needs numpy sage.modules
True
So is the line graph of a bipartite graph::
- sage: g = graphs.RandomBipartite(4,3,0.7)
- sage: g.line_graph().is_perfect() # long time
+ sage: g = graphs.RandomBipartite(4,3,0.7) # needs numpy
+ sage: g.line_graph().is_perfect() # long time # needs numpy sage.modules
True
As well as the Cartesian product of two complete graphs::
sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3))
- sage: g.is_perfect()
+ sage: g.is_perfect() # needs sage.modules
True
Interval Graphs, which are chordal graphs, too ::
sage: g = graphs.RandomIntervalGraph(7)
- sage: g.is_perfect()
+ sage: g.is_perfect() # needs sage.modules
True
The PetersenGraph, which is triangle-free and has chromatic number 3 is
obviously not perfect::
sage: g = graphs.PetersenGraph()
- sage: g.is_perfect()
+ sage: g.is_perfect() # needs sage.modules
False
We can obtain an induced 5-cycle as a certificate::
- sage: g.is_perfect(certificate=True)
+ sage: g.is_perfect(certificate=True) # needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices
TESTS:
Check that :trac:`13546` has been fixed::
- sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect()
+ sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() # needs sage.modules
False
sage: g = Graph({0: [2, 3, 4, 5],
....: 1: [3, 4, 5, 6],
@@ -2640,12 +2654,12 @@ def is_perfect(self, certificate=False):
....: 4: [0, 1, 2, 6],
....: 5: [0, 1, 2, 3],
....: 6: [1, 2, 3, 4]})
- sage: g.is_perfect()
+ sage: g.is_perfect() # needs sage.modules
False
TESTS::
- sage: Graph(':Ab').is_perfect()
+ sage: Graph(':Ab').is_perfect() # needs sage.modules
Traceback (most recent call last):
...
ValueError: This method is only defined for simple graphs, and yours is not one of them !
@@ -2654,7 +2668,7 @@ def is_perfect(self, certificate=False):
sage: g.add_edge(0,0)
sage: g.edges(sort=True)
[(0, 0, None)]
- sage: g.is_perfect()
+ sage: g.is_perfect() # needs sage.modules
Traceback (most recent call last):
...
ValueError: This method is only defined for simple graphs, and yours is not one of them !
@@ -2701,16 +2715,16 @@ def is_edge_transitive(self):
EXAMPLES::
sage: P = graphs.PetersenGraph()
- sage: P.is_edge_transitive()
+ sage: P.is_edge_transitive() # needs sage.libs.gap
True
sage: C = graphs.CubeGraph(3)
- sage: C.is_edge_transitive()
+ sage: C.is_edge_transitive() # needs sage.libs.gap
True
- sage: G = graphs.GrayGraph()
- sage: G.is_edge_transitive()
+ sage: G = graphs.GrayGraph() # needs networkx
+ sage: G.is_edge_transitive() # needs networkx sage.libs.gap
True
sage: P = graphs.PathGraph(4)
- sage: P.is_edge_transitive()
+ sage: P.is_edge_transitive() # needs sage.libs.gap
False
"""
from sage.libs.gap.libgap import libgap
@@ -2747,10 +2761,10 @@ def is_arc_transitive(self):
EXAMPLES::
sage: P = graphs.PetersenGraph()
- sage: P.is_arc_transitive()
+ sage: P.is_arc_transitive() # needs sage.libs.gap
True
- sage: G = graphs.GrayGraph()
- sage: G.is_arc_transitive()
+ sage: G = graphs.GrayGraph() # needs networkx
+ sage: G.is_arc_transitive() # needs networkx sage.libs.gap
False
"""
from sage.libs.gap.libgap import libgap
@@ -2784,13 +2798,13 @@ def is_half_transitive(self):
The Petersen Graph is not half-transitive::
sage: P = graphs.PetersenGraph()
- sage: P.is_half_transitive()
+ sage: P.is_half_transitive() # needs sage.libs.gap
False
The smallest half-transitive graph is the Holt Graph::
sage: H = graphs.HoltGraph()
- sage: H.is_half_transitive()
+ sage: H.is_half_transitive() # needs sage.libs.gap
True
"""
# A half-transitive graph always has only vertices of even degree
@@ -2821,19 +2835,19 @@ def is_semi_symmetric(self):
The Petersen graph is not semi-symmetric::
sage: P = graphs.PetersenGraph()
- sage: P.is_semi_symmetric()
+ sage: P.is_semi_symmetric() # needs sage.libs.gap
False
The Gray graph is the smallest possible cubic semi-symmetric graph::
- sage: G = graphs.GrayGraph()
- sage: G.is_semi_symmetric()
+ sage: G = graphs.GrayGraph() # needs networkx
+ sage: G.is_semi_symmetric() # needs networkx sage.libs.gap
True
Another well known semi-symmetric graph is the Ljubljana graph::
- sage: L = graphs.LjubljanaGraph()
- sage: L.is_semi_symmetric()
+ sage: L = graphs.LjubljanaGraph() # needs networkx
+ sage: L.is_semi_symmetric() # needs networkx sage.libs.gap
True
"""
# A semi-symmetric graph is always bipartite
@@ -2955,8 +2969,8 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0,
sage: g = graphs.CycleGraph(6)
sage: bounds = lambda x: [1,1]
- sage: m = g.degree_constrained_subgraph(bounds=bounds)
- sage: m.size()
+ sage: m = g.degree_constrained_subgraph(bounds=bounds) # needs sage.numerical.mip
+ sage: m.size() # needs sage.numerical.mip
3
"""
self._scream_if_not_simple()
@@ -3161,8 +3175,8 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb
optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`::
sage: g = graphs.CompleteBipartiteGraph(3,4)
- sage: o = g.minimum_outdegree_orientation()
- sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4))
+ sage: o = g.minimum_outdegree_orientation() # needs sage.numerical.mip
+ sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) # needs sage.numerical.mip
True
"""
self._scream_if_not_simple()
@@ -3632,23 +3646,23 @@ def chromatic_index(self, solver=None, verbose=0, *, integrality_tolerance=1e-3)
The path `P_n` with `n \geq 2` has chromatic index 2::
- sage: graphs.PathGraph(5).chromatic_index()
+ sage: graphs.PathGraph(5).chromatic_index() # needs sage.numerical.mip
2
The windmill graph with parameters `k,n` has chromatic index `(k-1)n`::
sage: k,n = 3,4
sage: G = graphs.WindmillGraph(k,n)
- sage: G.chromatic_index() == (k-1)*n
+ sage: G.chromatic_index() == (k-1)*n # needs sage.numerical.mip
True
TESTS:
Graphs without vertices or edges::
- sage: Graph().chromatic_index()
+ sage: Graph().chromatic_index() # needs sage.numerical.mip
0
- sage: Graph(2).chromatic_index()
+ sage: Graph(2).chromatic_index() # needs sage.numerical.mip
0
"""
if not self.order() or not self.size():
@@ -3725,7 +3739,7 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0,
A bipartite graph has (by definition) chromatic number 2::
- sage: graphs.RandomBipartite(50,50,0.7).chromatic_number()
+ sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() # needs numpy
2
A complete multipartite graph with k parts has chromatic number `k`::
@@ -3855,14 +3869,15 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0,
True
sage: are_equal_colorings(P, Q)
True
- sage: G.plot(partition=P) # optional - sage.plot
+
+ sage: # needs sage.plot
+ sage: G.plot(partition=P)
Graphics object consisting of 16 graphics primitives
sage: G.coloring(hex_colors=True, algorithm="MILP")
{'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]}
- sage: H = G.coloring(hex_colors=True, algorithm="DLX")
- sage: H
+ sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H
{'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]}
- sage: G.plot(vertex_colors=H) # optional - sage.plot
+ sage: G.plot(vertex_colors=H)
Graphics object consisting of 16 graphics primitives
.. PLOT::
@@ -3911,25 +3926,26 @@ def chromatic_symmetric_function(self, R=None):
EXAMPLES::
- sage: s = SymmetricFunctions(ZZ).s()
+ sage: s = SymmetricFunctions(ZZ).s() # needs sage.combinat sage.modules
sage: G = graphs.CycleGraph(5)
- sage: XG = G.chromatic_symmetric_function(); XG
+ sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules
p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1]
+ 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5]
- sage: s(XG)
+ sage: s(XG) # needs sage.combinat sage.modules
30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1]
Not all graphs have a positive Schur expansion::
sage: G = graphs.ClawGraph()
- sage: XG = G.chromatic_symmetric_function(); XG
+ sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]
- sage: s(XG)
+ sage: s(XG) # needs sage.combinat sage.modules
8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1]
We show that given a triangle `\{e_1, e_2, e_3\}`, we have
`X_G = X_{G - e_1} + X_{G - e_2} - X_{G - e_1 - e_2}`::
+ sage: # needs sage.combinat sage.modules
sage: G = Graph([[1,2],[1,3],[2,3]])
sage: XG = G.chromatic_symmetric_function()
sage: G1 = copy(G)
@@ -3987,6 +4003,7 @@ def chromatic_quasisymmetric_function(self, t=None, R=None):
EXAMPLES::
+ sage: # needs sage.combinat sage.modules
sage: G = Graph([[1,2,3], [[1,3], [2,3]]])
sage: G.chromatic_quasisymmetric_function()
(2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1]
@@ -4005,27 +4022,27 @@ def chromatic_quasisymmetric_function(self, t=None, R=None):
Not all chromatic quasisymmetric functions are symmetric::
sage: G = Graph([[1,2], [1,5], [3,4], [3,5]])
- sage: G.chromatic_quasisymmetric_function().is_symmetric()
+ sage: G.chromatic_quasisymmetric_function().is_symmetric() # needs sage.combinat sage.modules
False
We check that at `t = 1`, we recover the usual chromatic symmetric
function::
- sage: p = SymmetricFunctions(QQ).p()
+ sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat sage.modules
sage: G = graphs.CycleGraph(5)
- sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
+ sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules
120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1]
+ 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1]
+ 10*M[2, 1, 2] + 10*M[2, 2, 1]
- sage: p(XG.to_symmetric_function())
+ sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules
p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1]
+ 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5]
sage: G = graphs.ClawGraph()
- sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
+ sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules
24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3]
+ 6*M[2, 1, 1] + M[3, 1]
- sage: p(XG.to_symmetric_function())
+ sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]
"""
from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions
@@ -4129,7 +4146,7 @@ def matching(self, value_only=False, algorithm="Edmonds",
Maximum matching in a Pappus Graph::
sage: g = graphs.PappusGraph()
- sage: g.matching(value_only=True)
+ sage: g.matching(value_only=True) # needs sage.networkx
9
Same test with the Linear Program formulation::
@@ -4149,7 +4166,7 @@ def matching(self, value_only=False, algorithm="Edmonds",
and LP formulation::
sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)])
- sage: sorted(g.matching())
+ sage: sorted(g.matching()) # needs sage.networkx
[(0, 1, 0), (2, 3, -5)]
sage: sorted(g.matching(algorithm="LP"))
[(0, 1, 0), (2, 3, -5)]
@@ -4158,7 +4175,7 @@ def matching(self, value_only=False, algorithm="Edmonds",
LP formulation::
sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)])
- sage: g.matching(use_edge_labels=True)
+ sage: g.matching(use_edge_labels=True) # needs sage.networkx
[(1, 2, 999)]
sage: g.matching(algorithm="LP", use_edge_labels=True)
[(1, 2, 999)]
@@ -4168,10 +4185,10 @@ def matching(self, value_only=False, algorithm="Edmonds",
sage: edge_list = [(0,0,5), (0,1,1), (0,2,2), (0,3,3), (1,2,6)
....: , (1,2,3), (1,3,3), (2,3,3)]
sage: g = Graph(edge_list, loops=True, multiedges=True)
- sage: m = g.matching(use_edge_labels=True)
- sage: type(m)
+ sage: m = g.matching(use_edge_labels=True) # needs sage.networkx
+ sage: type(m) # needs sage.networkx
- sage: sorted(m)
+ sage: sorted(m) # needs sage.networkx
[(0, 3, 3), (1, 2, 6)]
TESTS:
@@ -4306,9 +4323,9 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve
Odd length cycles and odd cliques of order at least 3 are
factor-critical graphs::
- sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)]
+ sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx
[True, True, True, True, True]
- sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)]
+ sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx
[True, True, True, True, True]
More generally, every Hamiltonian graph with an odd number of vertices
@@ -4319,18 +4336,18 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve
sage: G.add_edge(14, 0)
sage: G.is_hamiltonian()
True
- sage: G.is_factor_critical()
+ sage: G.is_factor_critical() # needs networkx
True
Friendship graphs are non-Hamiltonian factor-critical graphs::
- sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)]
+ sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] # needs networkx
[True, True, True, True]
Bipartite graphs are not factor-critical::
- sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5)
- sage: G.is_factor_critical()
+ sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) # needs numpy
+ sage: G.is_factor_critical() # needs numpy
False
Graphs with even order are not factor critical::
@@ -4342,10 +4359,10 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve
One can specify a matching::
sage: F = graphs.FriendshipGraph(4)
- sage: M = F.matching()
- sage: F.is_factor_critical(matching=M)
+ sage: M = F.matching() # needs networkx
+ sage: F.is_factor_critical(matching=M) # needs networkx
True
- sage: F.is_factor_critical(matching=Graph(M))
+ sage: F.is_factor_critical(matching=Graph(M)) # needs networkx
True
TESTS:
@@ -4355,8 +4372,8 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve
sage: G = graphs.RandomGNP(15, .3)
sage: while not G.is_biconnected():
....: G = graphs.RandomGNP(15, .3)
- sage: M = G.matching()
- sage: G.is_factor_critical(matching=M[:-1])
+ sage: M = G.matching() # needs networkx
+ sage: G.is_factor_critical(matching=M[:-1]) # needs networkx
Traceback (most recent call last):
...
ValueError: the input is not a near perfect matching of the graph
@@ -4498,8 +4515,8 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0,
with this method ::
sage: g = graphs.CycleGraph(10)
- sage: mapping = g.has_homomorphism_to(g, core = True)
- sage: print("The size of the core is {}".format(len(set(mapping.values()))))
+ sage: mapping = g.has_homomorphism_to(g, core=True) # needs sage.numerical.mip
+ sage: print("The size of the core is {}".format(len(set(mapping.values())))) # needs sage.numerical.mip
The size of the core is 2
OUTPUT:
@@ -4513,18 +4530,18 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0,
Is Petersen's graph 3-colorable::
sage: P = graphs.PetersenGraph()
- sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False
+ sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False # needs sage.numerical.mip
True
An odd cycle admits a homomorphism to a smaller odd cycle, but not to an
even cycle::
sage: g = graphs.CycleGraph(9)
- sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False
+ sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False # needs sage.numerical.mip
True
- sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False
+ sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False # needs sage.numerical.mip
True
- sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False
+ sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False # needs sage.numerical.mip
False
"""
self._scream_if_not_simple()
@@ -4616,7 +4633,7 @@ def fractional_clique_number(self, solver='PPL', verbose=0,
The fractional clique number of a `C_7` is `7/3`::
sage: g = graphs.CycleGraph(7)
- sage: g.fractional_clique_number()
+ sage: g.fractional_clique_number() # needs sage.numerical.mip
7/3
"""
return self.fractional_chromatic_number(solver=solver, verbose=verbose,
@@ -4660,37 +4677,38 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0):
In any graph, the `Mad` is always larger than the average degree::
sage: g = graphs.RandomGNP(20,.3)
- sage: mad_g = g.maximum_average_degree()
- sage: g.average_degree() <= mad_g
+ sage: mad_g = g.maximum_average_degree() # needs sage.numerical.mip
+ sage: g.average_degree() <= mad_g # needs sage.numerical.mip
True
Unlike the average degree, the `Mad` of the disjoint union of two graphs
is the maximum of the `Mad` of each graphs::
sage: h = graphs.RandomGNP(20,.3)
- sage: mad_h = h.maximum_average_degree()
- sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
+ sage: mad_h = h.maximum_average_degree() # needs sage.numerical.mip
+ sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) # needs sage.numerical.mip
True
The subgraph of a regular graph realizing the maximum average degree is
always the whole graph ::
sage: g = graphs.CompleteGraph(5)
- sage: mad_g = g.maximum_average_degree(value_only=False)
- sage: g.is_isomorphic(mad_g)
+ sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip
+ sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip
True
This also works for complete bipartite graphs ::
sage: g = graphs.CompleteBipartiteGraph(3,4)
- sage: mad_g = g.maximum_average_degree(value_only=False)
- sage: g.is_isomorphic(mad_g)
+ sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip
+ sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip
True
TESTS:
Check corner cases::
+ sage: # needs sage.numerical.mip
sage: Graph().maximum_average_degree(value_only=True)
0
sage: Graph().maximum_average_degree(value_only=False)
@@ -4794,7 +4812,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0,
sage: g = graphs.CompleteBipartiteGraph(3,3)
sage: g.delete_edge(1,4)
- sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]])
+ sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) # needs sage.numerical.mip
[1, 4]
The Petersen Graph is 3-colorable, which can be expressed as an
@@ -4803,6 +4821,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0,
partition of the set of vertices the family defined by the three copies
of each vertex. The ISR of such a family defines a 3-coloring::
+ sage: # needs sage.numerical.mip
sage: g = 3 * graphs.PetersenGraph()
sage: n = g.order() / 3
sage: f = [[i, i + n, i + 2*n] for i in range(n)]
@@ -4923,6 +4942,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3):
Trying to find a minor isomorphic to `K_4` in the `4\times 4` grid::
+ sage: # needs sage.numerical.mip
sage: g = graphs.GridGraph([4,4])
sage: h = graphs.CompleteGraph(4)
sage: L = g.minor(h)
@@ -4935,11 +4955,11 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3):
as it has a `K_5` minor::
sage: g = graphs.PetersenGraph()
- sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time
+ sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time # needs sage.numerical.mip
And even a `K_{3,3}` minor::
- sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time
+ sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time, needs sage.numerical.mip
(It is much faster to use the linear-time test of planarity in this
situation, though.)
@@ -4951,7 +4971,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3):
sage: g = g.subgraph(edges = g.min_spanning_tree())
sage: g.is_tree()
True
- sage: L = g.minor(graphs.CompleteGraph(3))
+ sage: L = g.minor(graphs.CompleteGraph(3)) # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: This graph has no minor isomorphic to H !
@@ -5234,7 +5254,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None,
[1, 1, 1]
sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython')
[1, 1, 1]
- sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX')
+ sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx
[2, 1, 2]
sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost')
[2, 1, 2]
@@ -5769,7 +5789,7 @@ def distance_graph(self, dist):
sage: G = graphs.CompleteGraph(3)
sage: H = G.cartesian_product(graphs.CompleteGraph(2))
sage: K = H.distance_graph(2)
- sage: K.am()
+ sage: K.am() # needs sage.modules
[0 0 0 1 0 1]
[0 0 1 0 1 0]
[0 1 0 0 0 1]
@@ -5797,8 +5817,8 @@ def distance_graph(self, dist):
that sum to the matrix of all ones::
sage: P = graphs.PathGraph(20)
- sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)])
- sage: all_ones == matrix(ZZ, 20, 20, [1]*400)
+ sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) # needs sage.modules
+ sage: all_ones == matrix(ZZ, 20, 20, [1]*400) # needs sage.modules
True
Four-bit strings differing in one bit is the same as
@@ -5812,11 +5832,12 @@ def distance_graph(self, dist):
The graph of eight-bit strings, adjacent if different in an odd number
of bits::
- sage: G = graphs.CubeGraph(8) # long time
- sage: H = G.distance_graph([1,3,5,7]) # long time
- sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) # long time
- sage: degrees.append(2^8) # long time
- sage: degrees == H.degree_histogram() # long time
+ sage: # long time
+ sage: G = graphs.CubeGraph(8)
+ sage: H = G.distance_graph([1,3,5,7])
+ sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]])
+ sage: degrees.append(2^8)
+ sage: degrees == H.degree_histogram()
True
An example of using ``Infinity`` as the distance in a graph that is not
@@ -5825,7 +5846,7 @@ def distance_graph(self, dist):
sage: G = graphs.CompleteGraph(3)
sage: H = G.disjoint_union(graphs.CompleteGraph(2))
sage: L = H.distance_graph(Infinity)
- sage: L.am()
+ sage: L.am() # needs sage.modules
[0 0 0 1 1]
[0 0 0 1 1]
[0 0 0 1 1]
@@ -5950,12 +5971,12 @@ def to_directed(self, data_structure=None, sparse=None):
:trac:`22424`::
sage: G1 = graphs.RandomGNP(5,0.5)
- sage: gp1 = G1.graphplot(save_pos=True) # optional - sage.plot
+ sage: gp1 = G1.graphplot(save_pos=True) # needs sage.plot
sage: G2 = G1.to_directed()
sage: G2.delete_vertex(0)
sage: G2.add_vertex(5)
- sage: gp2 = G2.graphplot() # optional - sage.plot
- sage: gp1 = G1.graphplot() # optional - sage.plot
+ sage: gp2 = G2.graphplot() # needs sage.plot
+ sage: gp1 = G1.graphplot() # needs sage.plot
Vertex labels will be retained (:trac:`14708`)::
@@ -6114,14 +6135,14 @@ def seidel_adjacency_matrix(self, vertices=None, *, base_ring=None, **kwds):
sage: G = graphs.CycleGraph(5)
sage: G = G.disjoint_union(graphs.CompleteGraph(1))
- sage: G.seidel_adjacency_matrix().minpoly()
+ sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules
x^2 - 5
Selecting the base ring::
- sage: G.seidel_adjacency_matrix()[0, 0].parent()
+ sage: G.seidel_adjacency_matrix()[0, 0].parent() # needs sage.modules
Integer Ring
- sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent()
+ sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules
Real Double Field
"""
set_immutable = kwds.pop('immutable', False)
@@ -6161,7 +6182,7 @@ def seidel_switching(self, s, inplace=True):
sage: G = graphs.CycleGraph(5)
sage: G = G.disjoint_union(graphs.CompleteGraph(1))
sage: G.seidel_switching([(0,1),(1,0),(0,0)])
- sage: G.seidel_adjacency_matrix().minpoly()
+ sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules
x^2 - 5
sage: G.is_connected()
True
@@ -6192,13 +6213,14 @@ def twograph(self):
EXAMPLES::
- sage: p=graphs.PetersenGraph()
- sage: p.twograph()
+ sage: p = graphs.PetersenGraph()
+ sage: p.twograph() # needs sage.modules
Incidence structure with 10 points and 60 blocks
sage: p=graphs.chang_graphs()
sage: T8 = graphs.CompleteGraph(8).line_graph()
- sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],inplace=False)
- sage: T8.twograph() == C.twograph()
+ sage: C = T8.seidel_switching([(0,1,None), (2,3,None), (4,5,None), (6,7,None)],
+ ....: inplace=False)
+ sage: T8.twograph() == C.twograph() # needs sage.modules
True
sage: T8.is_isomorphic(C)
False
@@ -6206,8 +6228,8 @@ def twograph(self):
TESTS::
sage: from sage.combinat.designs.twographs import TwoGraph
- sage: p=graphs.PetersenGraph().twograph()
- sage: TwoGraph(p, check=True)
+ sage: p = graphs.PetersenGraph().twograph() # needs sage.modules
+ sage: TwoGraph(p, check=True) # needs sage.modules
Incidence structure with 10 points and 60 blocks
.. SEEALSO::
@@ -6341,19 +6363,19 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose
Petersen's graph has a topological `K_4`-minor::
sage: g = graphs.PetersenGraph()
- sage: g.topological_minor(graphs.CompleteGraph(4))
+ sage: g.topological_minor(graphs.CompleteGraph(4)) # needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...
And a topological `K_{3,3}`-minor::
- sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
+ sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) # needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...
And of course, a tree has no topological `C_3`-minor::
sage: g = graphs.RandomGNP(15,.3)
- sage: g = g.subgraph(edges = g.min_spanning_tree())
- sage: g.topological_minor(graphs.CycleGraph(3))
+ sage: g = g.subgraph(edges=g.min_spanning_tree())
+ sage: g.topological_minor(graphs.CycleGraph(3)) # needs sage.numerical.mip
False
"""
self._scream_if_not_simple()
@@ -6545,7 +6567,7 @@ def cliques_maximal(self, algorithm="native"):
[2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],
[5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2, 2]) # optional - sage.plot
+ sage: G.show(figsize=[2, 2]) # needs sage.plot
sage: G.cliques_maximal()
[[0, 1, 2], [0, 1, 3]]
sage: C = graphs.PetersenGraph()
@@ -6559,9 +6581,9 @@ def cliques_maximal(self, algorithm="native"):
Comparing the two implementations::
sage: g = graphs.RandomGNP(20,.7)
- sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX")))
+ sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) # needs networkx
sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native")))
- sage: s1 == s2
+ sage: s1 == s2 # needs networkx
True
"""
if algorithm == "native":
@@ -6720,7 +6742,7 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose=
sage: C.clique_number()
4
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
+ sage: G.show(figsize=[2,2]) # needs sage.plot
sage: G.clique_number()
3
@@ -6744,9 +6766,9 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose=
TESTS::
sage: g = graphs.PetersenGraph()
- sage: g.clique_number(algorithm="MILP")
+ sage: g.clique_number(algorithm="MILP") # needs sage.numerical.mip
2
- sage: for i in range(10): # optional - mcqd
+ sage: for i in range(10): # optional - mcqd # needs sage.numerical.mip
....: g = graphs.RandomGNP(15,.5)
....: if g.clique_number() != g.clique_number(algorithm="mcqd"):
....: print("This is dead wrong !")
@@ -6789,23 +6811,23 @@ def cliques_number_of(self, vertices=None, cliques=None):
EXAMPLES::
sage: C = Graph('DJ{')
- sage: C.cliques_number_of()
+ sage: C.cliques_number_of() # needs networkx
{0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
sage: E = C.cliques_maximal()
sage: E
[[0, 4], [1, 2, 3, 4]]
- sage: C.cliques_number_of(cliques=E)
+ sage: C.cliques_number_of(cliques=E) # needs networkx
{0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
sage: F = graphs.Grid2dGraph(2,3)
- sage: F.cliques_number_of()
+ sage: F.cliques_number_of() # needs networkx
{(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2}
- sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)])
+ sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) # needs networkx
{(0, 1): 3, (1, 2): 2}
sage: F.cliques_number_of(vertices=(0, 1))
3
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
- sage: G.cliques_number_of()
+ sage: G.show(figsize=[2,2]) # needs sage.plot
+ sage: G.cliques_number_of() # needs networkx
{0: 2, 1: 2, 2: 1, 3: 1}
"""
if cliques is None:
@@ -6840,14 +6862,14 @@ def cliques_get_max_clique_graph(self):
EXAMPLES::
- sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG
+ sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG # needs networkx
Graph on 24 vertices
- sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot
+ sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
- sage: G.cliques_get_max_clique_graph()
+ sage: G.show(figsize=[2,2]) # needs sage.plot
+ sage: G.cliques_get_max_clique_graph() # needs networkx
Graph on 2 vertices
- sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # optional - sage.plot
+ sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # needs networkx sage.plot
"""
import networkx
return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph()),
@@ -6868,14 +6890,14 @@ def cliques_get_clique_bipartite(self, **kwds):
EXAMPLES::
- sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG
+ sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG # needs networkx
Bipartite graph on 36 vertices
- sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot
+ sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
- sage: G.cliques_get_clique_bipartite()
+ sage: G.show(figsize=[2,2]) # needs sage.plot
+ sage: G.cliques_get_clique_bipartite() # needs networkx
Bipartite graph on 6 vertices
- sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # optional - sage.plot
+ sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # needs networkx sage.plot
"""
from .bipartite_graph import BipartiteGraph
import networkx
@@ -6958,7 +6980,7 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules
As a linear program::
sage: C = graphs.PetersenGraph()
- sage: len(C.independent_set(algorithm="MILP"))
+ sage: len(C.independent_set(algorithm="MILP")) # needs sage.numerical.mip
4
.. PLOT::
@@ -7057,9 +7079,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False,
The two algorithms should return the same result::
sage: g = graphs.RandomGNP(10, .5)
- sage: vc1 = g.vertex_cover(algorithm="MILP")
+ sage: vc1 = g.vertex_cover(algorithm="MILP") # needs sage.numerical.mip
sage: vc2 = g.vertex_cover(algorithm="Cliquer")
- sage: len(vc1) == len(vc2)
+ sage: len(vc1) == len(vc2) # needs sage.numerical.mip
True
The cardinality of the vertex cover is unchanged when reduction rules
@@ -7110,9 +7132,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False,
Issue :trac:`24287` is fixed::
sage: G = Graph([(0,1)]*5 + [(1,2)]*2, multiedges=True)
- sage: G.vertex_cover(reduction_rules=True, algorithm='MILP')
+ sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') # needs sage.numerical.mip
[1]
- sage: G.vertex_cover(reduction_rules=False)
+ sage: G.vertex_cover(reduction_rules=False) # needs sage.numerical.mip
[1]
Issue :trac:`25988` is fixed::
@@ -7466,20 +7488,22 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None,
EXAMPLES::
sage: C = Graph('DJ{')
- sage: C.cliques_vertex_clique_number() # optional - sage.plot
+ sage: C.cliques_vertex_clique_number()
{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
sage: E = C.cliques_maximal(); E
[[0, 4], [1, 2, 3, 4]]
- sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # optional - sage.plot
+ sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx
{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
+
sage: F = graphs.Grid2dGraph(2,3)
- sage: F.cliques_vertex_clique_number(algorithm="networkx") # optional - sage.plot
+ sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx
{(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2}
- sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) # optional - sage.plot
+ sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)])
{(0, 1): 2, (1, 2): 2}
+
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
- sage: G.cliques_vertex_clique_number() # optional - sage.plot
+ sage: G.show(figsize=[2,2]) # needs sage.plot
+ sage: G.cliques_vertex_clique_number()
{0: 3, 1: 3, 2: 3, 3: 3}
"""
if algorithm == "cliquer":
@@ -7518,6 +7542,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None):
EXAMPLES::
+ sage: # needs networkx
sage: C = Graph('DJ{')
sage: C.cliques_containing_vertex()
{0: [[0, 4]],
@@ -7529,8 +7554,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None):
[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_containing_vertex([0, 1])
{0: [[0, 4]], 1: [[1, 2, 3, 4]]}
- sage: E = C.cliques_maximal()
- sage: E
+ sage: E = C.cliques_maximal(); E
[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_containing_vertex(cliques=E)
{0: [[0, 4]],
@@ -7540,8 +7564,8 @@ def cliques_containing_vertex(self, vertices=None, cliques=None):
4: [[0, 4], [1, 2, 3, 4]]}
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
- sage: G.show(figsize=[2,2]) # optional - sage.plot
- sage: G.cliques_containing_vertex()
+ sage: G.show(figsize=[2,2]) # needs sage.plot
+ sage: G.cliques_containing_vertex() # needs networkx
{0: [[0, 1, 2], [0, 1, 3]],
1: [[0, 1, 2], [0, 1, 3]],
2: [[0, 1, 2]],
@@ -7550,6 +7574,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None):
Since each clique of a 2 dimensional grid corresponds to an edge, the
number of cliques in which a vertex is involved equals its degree::
+ sage: # needs networkx
sage: F = graphs.Grid2dGraph(2,3)
sage: d = F.cliques_containing_vertex()
sage: all(F.degree(u) == len(cliques) for u,cliques in d.items())
@@ -7716,20 +7741,23 @@ def cores(self, k=None, with_labels=False):
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: (graphs.FruchtGraph()).cores(with_labels=True)
{0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
+
+ sage: # needs sage.modules
sage: set_random_seed(0)
sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1)
sage: b = Graph(20)
sage: b.add_edges(a.nonzero_positions(), loops=False)
sage: cores = b.cores(with_labels=True); cores
- {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
- sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core
+ {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3,
+ 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
+ sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core
[0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Checking the 2-core of a random lobster is indeed the empty set::
- sage: g = graphs.RandomLobster(20, .5, .5)
- sage: ordering, core = g.cores(2)
- sage: len(core) == 0
+ sage: g = graphs.RandomLobster(20, .5, .5) # needs networkx
+ sage: ordering, core = g.cores(2) # needs networkx
+ sage: len(core) == 0 # needs networkx
True
Checking the cores of a bull graph::
@@ -8127,22 +8155,22 @@ def is_circumscribable(self, solver="ppl", verbose=0):
EXAMPLES::
sage: C = graphs.CubeGraph(3)
- sage: C.is_circumscribable()
+ sage: C.is_circumscribable() # needs sage.numerical.mip
True
sage: O = graphs.OctahedralGraph()
- sage: O.is_circumscribable()
+ sage: O.is_circumscribable() # needs sage.numerical.mip
True
- sage: TT = polytopes.truncated_tetrahedron().graph()
- sage: TT.is_circumscribable()
+ sage: TT = polytopes.truncated_tetrahedron().graph() # needs sage.geometry.polyhedron
+ sage: TT.is_circumscribable() # needs sage.geometry.polyhedron sage.numerical.mip
False
Stellating in a face of the octahedral graph is not circumscribable::
sage: f = set(flatten(choice(O.faces())))
sage: O.add_edges([[6, i] for i in f])
- sage: O.is_circumscribable()
+ sage: O.is_circumscribable() # needs sage.numerical.mip
False
.. SEEALSO::
@@ -8249,7 +8277,7 @@ def is_inscribable(self, solver="ppl", verbose=0):
True
sage: C = graphs.CubeGraph(3)
- sage: C.is_inscribable()
+ sage: C.is_inscribable() # needs sage.numerical.mip
True
Cutting off a vertex from the cube yields an uninscribable graph::
@@ -8260,7 +8288,7 @@ def is_inscribable(self, solver="ppl", verbose=0):
sage: C.add_edges(Combinations(triangle, 2))
sage: C.add_edges(zip(triangle, C.neighbors(v)))
sage: C.delete_vertex(v)
- sage: C.is_inscribable()
+ sage: C.is_inscribable() # needs sage.numerical.mip
False
Breaking a face of the cube yields an uninscribable graph::
@@ -8268,7 +8296,7 @@ def is_inscribable(self, solver="ppl", verbose=0):
sage: C = graphs.CubeGraph(3)
sage: face = choice(C.faces())
sage: C.add_edge([face[0][0], face[2][0]])
- sage: C.is_inscribable()
+ sage: C.is_inscribable() # needs sage.numerical.mip
False
@@ -8554,22 +8582,24 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1
edge-partitionned into `2`-regular graphs::
sage: g = graphs.CompleteGraph(7)
- sage: classes = g.two_factor_petersen()
- sage: for c in classes:
+ sage: classes = g.two_factor_petersen() # needs sage.numerical.mip
+ sage: for c in classes: # needs sage.numerical.mip
....: gg = Graph()
....: gg.add_edges(c)
....: print(max(gg.degree())<=2)
True
True
True
- sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size()
+ sage: Set(set(classes[0]) # needs sage.numerical.mip
+ ....: | set(classes[1])
+ ....: | set(classes[2])).cardinality() == g.size()
True
::
sage: g = graphs.CirculantGraph(24, [7, 11])
- sage: cl = g.two_factor_petersen()
- sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # optional - sage.plot
+ sage: cl = g.two_factor_petersen() # needs sage.numerical.mip
+ sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # needs sage.numerical.mip sage.plot
Graphics object consisting of 73 graphics primitives
"""
@@ -8641,30 +8671,30 @@ def kirchhoff_symanzik_polynomial(self, name='t'):
For the cycle of length 5::
sage: G = graphs.CycleGraph(5)
- sage: G.kirchhoff_symanzik_polynomial()
+ sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules
t0 + t1 + t2 + t3 + t4
One can use another letter for variables::
- sage: G.kirchhoff_symanzik_polynomial(name='u')
+ sage: G.kirchhoff_symanzik_polynomial(name='u') # needs networkx sage.modules
u0 + u1 + u2 + u3 + u4
For the 'coffee bean' graph::
sage: G = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')], multiedges=True)
- sage: G.kirchhoff_symanzik_polynomial()
+ sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules
t0*t1 + t0*t2 + t1*t2
For the 'parachute' graph::
sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True)
- sage: G.kirchhoff_symanzik_polynomial()
+ sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules
t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3
For the complete graph with 4 vertices::
sage: G = graphs.CompleteGraph(4)
- sage: G.kirchhoff_symanzik_polynomial()
+ sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules
t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4
+ t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5
+ t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5
@@ -8714,44 +8744,44 @@ def magnitude_function(self):
EXAMPLES::
sage: g = Graph({1:[], 2:[]})
- sage: g.magnitude_function()
+ sage: g.magnitude_function() # needs sage.modules
2
sage: g = graphs.CycleGraph(4)
- sage: g.magnitude_function()
+ sage: g.magnitude_function() # needs sage.modules
4/(q^2 + 2*q + 1)
sage: g = graphs.CycleGraph(5)
- sage: m = g.magnitude_function(); m
+ sage: m = g.magnitude_function(); m # needs sage.modules
5/(2*q^2 + 2*q + 1)
One can expand the magnitude as a power series in `q` as follows::
sage: q = QQ[['q']].gen()
- sage: m(q)
+ sage: m(q) # needs sage.modules
5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ...
One can also use the substitution `q = exp(-t)` to obtain the magnitude
function as a function of `t`::
sage: g = graphs.CycleGraph(6)
- sage: m = g.magnitude_function()
- sage: t = var('t') # optional - sage.symbolic
- sage: m(exp(-t)) # optional - sage.symbolic
+ sage: m = g.magnitude_function() # needs sage.modules
+ sage: t = var('t') # needs sage.modules sage.symbolic
+ sage: m(exp(-t)) # needs sage.modules sage.symbolic
6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1)
TESTS::
sage: g = Graph()
- sage: g.magnitude_function()
+ sage: g.magnitude_function() # needs sage.modules
0
sage: g = Graph({1:[]})
- sage: g.magnitude_function()
+ sage: g.magnitude_function() # needs sage.modules
1
sage: g = graphs.PathGraph(4)
- sage: g.magnitude_function()
+ sage: g.magnitude_function() # needs sage.modules
(-2*q + 4)/(q + 1)
REFERENCES:
@@ -8805,20 +8835,20 @@ def ihara_zeta_function_inverse(self):
EXAMPLES::
sage: G = graphs.CompleteGraph(4)
- sage: factor(G.ihara_zeta_function_inverse())
+ sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules
(2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3
sage: G = graphs.CompleteGraph(5)
- sage: factor(G.ihara_zeta_function_inverse())
+ sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules
(-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4
sage: G = graphs.PetersenGraph()
- sage: factor(G.ihara_zeta_function_inverse())
+ sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules
(-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4
* (2*t^2 - t + 1)^5
sage: G = graphs.RandomTree(10)
- sage: G.ihara_zeta_function_inverse()
+ sage: G.ihara_zeta_function_inverse() # needs sage.libs.pari sage.modules
1
REFERENCES:
@@ -9001,11 +9031,11 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0,
EXAMPLES::
- sage: graphs.PetersenGraph().has_perfect_matching()
+ sage: graphs.PetersenGraph().has_perfect_matching() # needs networkx
True
- sage: graphs.WheelGraph(6).has_perfect_matching()
+ sage: graphs.WheelGraph(6).has_perfect_matching() # needs networkx
True
- sage: graphs.WheelGraph(5).has_perfect_matching()
+ sage: graphs.WheelGraph(5).has_perfect_matching() # needs networkx
False
sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
True
@@ -9023,14 +9053,16 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0,
TESTS::
sage: G = graphs.EmptyGraph()
- sage: all(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP'])
+ sage: all(G.has_perfect_matching(algorithm=algo) # needs networkx
+ ....: for algo in ['Edmonds', 'LP_matching', 'LP'])
True
Be careful with isolated vertices::
sage: G = graphs.PetersenGraph()
sage: G.add_vertex(11)
- sage: any(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP'])
+ sage: any(G.has_perfect_matching(algorithm=algo) # needs networkx
+ ....: for algo in ['Edmonds', 'LP_matching', 'LP'])
False
"""
if self.order() % 2:
@@ -9088,6 +9120,7 @@ def effective_resistance(self, i, j, *, base_ring=None):
Effective resistances in a straight linear 2-tree on 6 vertices ::
+ sage: # needs sage.modules
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.effective_resistance(0,1)
34/55
@@ -9100,6 +9133,7 @@ def effective_resistance(self, i, j, *, base_ring=None):
Effective resistances in a fan on 6 vertices ::
+ sage: # needs sage.modules
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.effective_resistance(1,5)
6/5
@@ -9110,9 +9144,9 @@ def effective_resistance(self, i, j, *, base_ring=None):
Using a different base ring::
- sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14
+ sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 # needs sage.modules
1.2000000000000000
- sage: H.effective_resistance(1, 1, base_ring=RDF)
+ sage: H.effective_resistance(1, 1, base_ring=RDF) # needs sage.modules
0.0
.. SEEALSO::
@@ -9128,8 +9162,10 @@ def effective_resistance(self, i, j, *, base_ring=None):
TESTS::
+ sage: # needs sage.modules
sage: G = graphs.CompleteGraph(4)
- sage: all(G.effective_resistance(u, v) == 1/2 for u,v in G.edge_iterator(labels=False))
+ sage: all(G.effective_resistance(u, v) == 1/2
+ ....: for u,v in G.edge_iterator(labels=False))
True
sage: Graph(1).effective_resistance(0,0)
0
@@ -9221,7 +9257,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
only non-adjacent vertex pairs ::
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
- sage: G.effective_resistance_matrix()
+ sage: G.effective_resistance_matrix() # needs sage.modules
[ 0 0 0 49/55 59/55 15/11]
[ 0 0 0 0 9/11 59/55]
[ 0 0 0 0 0 49/55]
@@ -9232,7 +9268,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
The same effective resistance matrix, this time including adjacent
vertices ::
- sage: G.effective_resistance_matrix(nonedgesonly=False)
+ sage: G.effective_resistance_matrix(nonedgesonly=False) # needs sage.modules
[ 0 34/55 34/55 49/55 59/55 15/11]
[34/55 0 26/55 31/55 9/11 59/55]
[34/55 26/55 0 5/11 31/55 49/55]
@@ -9244,7 +9280,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
vertices counting only non-adjacent vertex pairs ::
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
- sage: H.effective_resistance_matrix()
+ sage: H.effective_resistance_matrix() # needs sage.modules
[ 0 0 0 0 0 0 0]
[ 0 0 0 49/55 56/55 6/5 89/55]
[ 0 0 0 0 4/5 56/55 81/55]
@@ -9255,7 +9291,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
A different base ring::
- sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent()
+ sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules
Real Double Field
.. SEEALSO::
@@ -9270,7 +9306,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
TESTS::
- sage: graphs.CompleteGraph(4).effective_resistance_matrix()
+ sage: graphs.CompleteGraph(4).effective_resistance_matrix() # needs sage.modules
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
@@ -9278,7 +9314,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges([(0, 1)] * 3)
- sage: G.effective_resistance_matrix()
+ sage: G.effective_resistance_matrix() # needs sage.modules
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with
@@ -9286,6 +9322,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
in the meantime if you want to use it please disallow multiedges
using allow_multiple_edges().
+ sage: # needs sage.modules
sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False)
[ 0 1/2 1/2 1/2]
[1/2 0 1/2 1/2]
@@ -9305,11 +9342,12 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True,
[0 1 0 0]
sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)])
sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3]
- sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5)
+ sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari
True
Ask for an immutable matrix::
+ sage: # needs sage.modules
sage: G = Graph([(0, 1)])
sage: M = G.effective_resistance_matrix(immutable=False)
sage: M.is_immutable()
@@ -9375,20 +9413,20 @@ def least_effective_resistance(self, nonedgesonly=True):
straight linear 2-tree on 6 vertices::
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
- sage: G.least_effective_resistance()
+ sage: G.least_effective_resistance() # needs sage.modules
[(1, 4)]
Pairs of (adjacent or non-adjacent) nodes with least effective
resistance in a straight linear 2-tree on 6 vertices ::
- sage: G.least_effective_resistance(nonedgesonly = False)
+ sage: G.least_effective_resistance(nonedgesonly=False) # needs sage.modules
[(2, 3)]
Pairs of non-adjacent nodes with least effective resistance in a fan on
6 vertices counting only non-adjacent vertex pairs ::
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
- sage: H.least_effective_resistance()
+ sage: H.least_effective_resistance() # needs sage.modules
[(2, 4)]
.. SEEALSO::
@@ -9405,6 +9443,7 @@ def least_effective_resistance(self, nonedgesonly=True):
TESTS::
+ sage: # needs sage.modules
sage: graphs.CompleteGraph(4).least_effective_resistance()
[]
sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False)
@@ -9470,7 +9509,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
sage: G1 = Graph()
sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
- sage: G1.common_neighbors_matrix(nonedgesonly = True)
+ sage: G1.common_neighbors_matrix(nonedgesonly=True) # needs sage.modules
[0 0 0 2 1 0]
[0 0 0 0 2 1]
[0 0 0 0 0 2]
@@ -9481,7 +9520,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
We now show the common neighbors matrix which includes adjacent
vertices ::
- sage: G1.common_neighbors_matrix(nonedgesonly = False)
+ sage: G1.common_neighbors_matrix(nonedgesonly=False) # needs sage.modules
[0 1 1 2 1 0]
[1 0 2 1 2 1]
[1 2 0 2 1 2]
@@ -9493,7 +9532,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
non-adjacent vertex pairs ::
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
- sage: H.common_neighbors_matrix()
+ sage: H.common_neighbors_matrix() # needs sage.modules
[0 0 0 0 0 0 0]
[0 0 0 2 1 1 1]
[0 0 0 0 2 1 1]
@@ -9504,7 +9543,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
A different base ring::
- sage: H.common_neighbors_matrix(base_ring=RDF)
+ sage: H.common_neighbors_matrix(base_ring=RDF) # needs sage.modules
[0.0 0.0 0.0 0.0 0.0 0.0 0.0]
[0.0 0.0 0.0 2.0 1.0 1.0 1.0]
[0.0 0.0 0.0 0.0 2.0 1.0 1.0]
@@ -9515,8 +9554,8 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
It is an error to input anything other than a simple graph::
- sage: G = Graph([(0,0)],loops=True)
- sage: G.common_neighbors_matrix()
+ sage: G = Graph([(0,0)], loops=True)
+ sage: G.common_neighbors_matrix() # needs sage.modules
Traceback (most recent call last):
...
ValueError: This method is not known to work on graphs with loops.
@@ -9531,6 +9570,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
TESTS::
+ sage: # needs sage.modules
sage: G = graphs.CompleteGraph(4)
sage: M = G.common_neighbors_matrix()
sage: M.is_zero()
@@ -9548,6 +9588,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True,
Asking for an immutable matrix::
+ sage: # needs sage.modules
sage: G = Graph([(0, 1)])
sage: M = G.common_neighbors_matrix()
sage: M.is_immutable()
@@ -9593,19 +9634,19 @@ def most_common_neighbors(self, nonedgesonly=True):
linear 2-tree ::
sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
- sage: G1.most_common_neighbors()
+ sage: G1.most_common_neighbors() # needs sage.modules
[(0, 3), (1, 4), (2, 5)]
If we include non-adjacent pairs ::
- sage: G1.most_common_neighbors(nonedgesonly = False)
+ sage: G1.most_common_neighbors(nonedgesonly=False) # needs sage.modules
[(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)]
The common neighbors matrix for a fan on 6 vertices counting only
non-adjacent vertex pairs ::
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
- sage: H.most_common_neighbors()
+ sage: H.most_common_neighbors() # needs sage.modules
[(1, 3), (2, 4), (3, 5)]
.. SEEALSO::
@@ -9615,7 +9656,8 @@ def most_common_neighbors(self, nonedgesonly=True):
TESTS::
- sage: G=graphs.CompleteGraph(4)
+ sage: # needs sage.modules
+ sage: G = graphs.CompleteGraph(4)
sage: G.most_common_neighbors()
[]
sage: G.most_common_neighbors(nonedgesonly=False)
@@ -9682,18 +9724,18 @@ def arboricity(self, certificate=False):
EXAMPLES::
sage: G = graphs.PetersenGraph()
- sage: a,F = G.arboricity(True)
- sage: a
+ sage: a, F = G.arboricity(True) # needs sage.modules
+ sage: a # needs sage.modules
2
- sage: all([f.is_forest() for f in F])
+ sage: all([f.is_forest() for f in F]) # needs sage.modules
True
- sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size()
+ sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() # needs sage.modules
True
TESTS::
sage: g = Graph()
- sage: g.arboricity(True)
+ sage: g.arboricity(True) # needs sage.modules
(0, [])
"""
from sage.matroids.constructor import Matroid
diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx
index 60abd45d4d1..f11bc3c4a05 100644
--- a/src/sage/graphs/graph_coloring.pyx
+++ b/src/sage/graphs/graph_coloring.pyx
@@ -104,11 +104,12 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict=
3
sage: format_coloring(color_classes, value_only=False)
{0: ['a', 'b'], 1: ['c'], 2: ['d']}
- sage: format_coloring(color_classes, value_only=False, hex_colors=True)
+ sage: format_coloring(color_classes, value_only=False, hex_colors=True) # needs sage.plot
{'#0000ff': ['d'], '#00ff00': ['c'], '#ff0000': ['a', 'b']}
sage: format_coloring(color_classes, value_only=False, hex_colors=False, vertex_color_dict=True)
{'a': 0, 'b': 0, 'c': 1, 'd': 2}
- sage: format_coloring(color_classes, value_only=False, hex_colors=True, vertex_color_dict=True)
+ sage: format_coloring(color_classes, value_only=False, hex_colors=True, # needs sage.plot
+ ....: vertex_color_dict=True)
{'a': '#ff0000', 'b': '#ff0000', 'c': '#00ff00', 'd': '#0000ff'}
TESTS::
@@ -116,9 +117,10 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict=
sage: from sage.graphs.graph_coloring import format_coloring
sage: format_coloring([], value_only=True)
[]
- sage: format_coloring([], value_only=False, hex_colors=True)
+ sage: format_coloring([], value_only=False, hex_colors=True) # needs sage.plot
{}
- sage: format_coloring([], value_only=False, hex_colors=True, vertex_color_dict=True)
+ sage: format_coloring([], value_only=False, hex_colors=True, # needs sage.plot
+ ....: vertex_color_dict=True)
{}
sage: format_coloring([], value_only=False, hex_colors=False, vertex_color_dict=True)
{}
@@ -210,7 +212,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False,
sage: from sage.graphs.graph_coloring import all_graph_colorings
sage: G = Graph({0: [1, 2, 3], 1: [2]})
sage: n = 0
- sage: for C in all_graph_colorings(G, 3, hex_colors=True):
+ sage: for C in all_graph_colorings(G, 3, hex_colors=True): # needs sage.plot
....: parts = [C[k] for k in C]
....: for P in parts:
....: l = len(P)
@@ -218,8 +220,8 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False,
....: for j in range(i + 1, l):
....: if G.has_edge(P[i], P[j]):
....: raise RuntimeError("Coloring Failed.")
- ....: n+=1
- sage: print("G has %s 3-colorings." % n)
+ ....: n += 1
+ sage: print("G has %s 3-colorings." % n) # needs sage.plot
G has 12 3-colorings.
TESTS::
@@ -237,11 +239,12 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False,
....: print(c)
{0: 0, 2: 0, 1: 1}
{1: 0, 0: 1, 2: 1}
- sage: for c in all_graph_colorings(G, 2, hex_colors=True):
+ sage: for c in all_graph_colorings(G, 2, hex_colors=True): # needs sage.plot
....: print(sorted(c.items()))
[('#00ffff', [1]), ('#ff0000', [0, 2])]
[('#00ffff', [0, 2]), ('#ff0000', [1])]
- sage: for c in all_graph_colorings(G, 2, hex_colors=True, vertex_color_dict=True):
+ sage: for c in all_graph_colorings(G, 2, hex_colors=True, # needs sage.plot
+ ....: vertex_color_dict=True):
....: print(c)
{0: '#ff0000', 2: '#ff0000', 1: '#00ffff'}
{1: '#ff0000', 0: '#00ffff', 2: '#00ffff'}
@@ -513,7 +516,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None,
sage: from sage.graphs.graph_coloring import vertex_coloring
sage: g = graphs.PetersenGraph()
- sage: vertex_coloring(g, value_only=True)
+ sage: vertex_coloring(g, value_only=True) # needs sage.numerical.mip
3
TESTS:
@@ -532,7 +535,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None,
:trac:`33559` is fixed::
sage: G = Graph('MgCgS?_O@IeTHKG??')
- sage: len(G.coloring(algorithm='MILP'))
+ sage: len(G.coloring(algorithm='MILP')) # needs sage.numerical.mip
4
"""
g._scream_if_not_simple(allow_multiple_edges=True)
@@ -775,15 +778,15 @@ def fractional_chromatic_number(G, solver='PPL', verbose=0,
The fractional chromatic number of a `C_5` is `5/2`::
sage: g = graphs.CycleGraph(5)
- sage: g.fractional_chromatic_number()
+ sage: g.fractional_chromatic_number() # needs sage.numerical.mip
5/2
TESTS::
sage: G = graphs.RandomGNP(20, .2)
- sage: a = G.fractional_chromatic_number(check_components=True)
- sage: b = G.fractional_chromatic_number(check_components=False)
- sage: a == b
+ sage: a = G.fractional_chromatic_number(check_components=True) # needs sage.numerical.mip
+ sage: b = G.fractional_chromatic_number(check_components=False) # needs sage.numerical.mip
+ sage: a == b # needs sage.numerical.mip
True
"""
G._scream_if_not_simple()
@@ -884,7 +887,7 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo
The fractional chromatic index of a `C_5` is `5/2`::
sage: g = graphs.CycleGraph(5)
- sage: g.fractional_chromatic_index()
+ sage: g.fractional_chromatic_index() # needs sage.numerical.mip
5/2
TESTS:
@@ -893,9 +896,9 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo
solvers::
sage: g = graphs.PetersenGraph()
- sage: g.fractional_chromatic_index(solver='GLPK') # known bug (#23798)
+ sage: g.fractional_chromatic_index(solver='GLPK') # known bug # needs sage.numerical.mip
3.0
- sage: g.fractional_chromatic_index(solver='PPL')
+ sage: g.fractional_chromatic_index(solver='PPL') # needs sage.numerical.mip
3
"""
G._scream_if_not_simple()
@@ -1025,13 +1028,13 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0,
sage: from sage.graphs.graph_coloring import grundy_coloring
sage: g = graphs.PathGraph(4)
- sage: grundy_coloring(g, 4)
+ sage: grundy_coloring(g, 4) # needs sage.numerical.mip
3
The Grundy number of the PetersenGraph is equal to 4::
sage: g = graphs.PetersenGraph()
- sage: grundy_coloring(g, 5)
+ sage: grundy_coloring(g, 5) # needs sage.numerical.mip
4
It would have been sufficient to set the value of ``k`` to 4 in
@@ -1179,13 +1182,13 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0,
sage: from sage.graphs.graph_coloring import b_coloring
sage: g = graphs.PathGraph(5)
- sage: b_coloring(g, 5)
+ sage: b_coloring(g, 5) # needs sage.numerical.mip
3
The b-chromatic number of the Petersen Graph is equal to 3::
sage: g = graphs.PetersenGraph()
- sage: b_coloring(g, 5)
+ sage: b_coloring(g, 5) # needs sage.numerical.mip
3
It would have been sufficient to set the value of ``k`` to 4 in this case,
@@ -1378,47 +1381,49 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No
The Petersen graph has chromatic index 4::
- sage: from sage.graphs.graph_coloring import edge_coloring
- sage: g = graphs.PetersenGraph()
- sage: edge_coloring(g, value_only=True, solver='GLPK')
- 4
- sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK')
- sage: len(color_classes)
- 4
- sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size()
- True
- sage: all(g.has_edge(e) for C in color_classes for e in C)
- True
- sage: all(len(Graph(C).matching()) == len(C) for C in color_classes)
- True
- sage: color_classes = edge_coloring(g, value_only=False, hex_colors=True, solver='GLPK')
- sage: sorted(color_classes.keys())
- ['#00ffff', '#7f00ff', '#7fff00', '#ff0000']
+ sage: # needs sage.numerical.mip
+ sage: from sage.graphs.graph_coloring import edge_coloring
+ sage: g = graphs.PetersenGraph()
+ sage: edge_coloring(g, value_only=True, solver='GLPK')
+ 4
+ sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK')
+ sage: len(color_classes)
+ 4
+ sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size()
+ True
+ sage: all(g.has_edge(e) for C in color_classes for e in C)
+ True
+ sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx
+ True
+ sage: color_classes = edge_coloring(g, value_only=False,
+ ....: hex_colors=True, solver='GLPK')
+ sage: sorted(color_classes.keys())
+ ['#00ffff', '#7f00ff', '#7fff00', '#ff0000']
Complete graphs are colored using the linear-time round-robin coloring::
- sage: from sage.graphs.graph_coloring import edge_coloring
- sage: len(edge_coloring(graphs.CompleteGraph(20)))
- 19
+ sage: from sage.graphs.graph_coloring import edge_coloring
+ sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip
+ 19
The chromatic index of a non connected graph is the maximum over its
connected components::
- sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10)
- sage: edge_coloring(g, value_only=True)
- 9
+ sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10)
+ sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip
+ 9
TESTS:
Graph without edge::
- sage: g = Graph(2)
- sage: edge_coloring(g)
- []
- sage: edge_coloring(g, value_only=True)
- 0
- sage: edge_coloring(g, hex_colors=True)
- {}
+ sage: g = Graph(2)
+ sage: edge_coloring(g) # needs sage.numerical.mip
+ []
+ sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip
+ 0
+ sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip
+ {}
"""
g._scream_if_not_simple()
@@ -1564,7 +1569,7 @@ def _vizing_edge_coloring(g):
True
sage: all(g.has_edge(e) for C in color_classes for e in C)
True
- sage: all(len(Graph(C).matching()) == len(C) for C in color_classes)
+ sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx
True
Coloring the edges of the Star Graph::
@@ -1832,22 +1837,23 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False,
horizontal lines and the set of vertical lines are an admissible partition::
sage: from sage.graphs.graph_coloring import linear_arboricity
- sage: g = graphs.Grid2dGraph(4, 4)
- sage: g1,g2 = linear_arboricity(g)
+ sage: g = graphs.Grid2dGraph(4, 4) # needs sage.numerical.mip
+ sage: g1,g2 = linear_arboricity(g) # needs sage.numerical.mip
Each graph is of course a forest::
- sage: g1.is_forest() and g2.is_forest()
+ sage: g1.is_forest() and g2.is_forest() # needs sage.numerical.mip
True
Of maximum degree 2::
- sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2
+ sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 # needs sage.numerical.mip
True
Which constitutes a partition of the whole edge set::
- sage: all((g1.has_edge(e) or g2.has_edge(e)) for e in g.edge_iterator(labels=None))
+ sage: all((g1.has_edge(e) or g2.has_edge(e)) # needs sage.numerical.mip
+ ....: for e in g.edge_iterator(labels=None))
True
TESTS:
@@ -1855,15 +1861,15 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False,
Asking for the value of the linear arboricity only (:trac:`24991`)::
sage: from sage.graphs.graph_coloring import linear_arboricity
- sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4))
+ sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip
[0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
Test parameter ``hex_color`` (:trac:`26228`)::
sage: from sage.graphs.graph_coloring import linear_arboricity
sage: g = graphs.Grid2dGraph(4, 4)
- sage: d = linear_arboricity(g, hex_colors=True)
- sage: sorted(d)
+ sage: d = linear_arboricity(g, hex_colors=True) # needs sage.numerical.mip
+ sage: sorted(d) # needs sage.numerical.mip
['#00ffff', '#ff0000']
"""
g._scream_if_not_simple()
@@ -2036,21 +2042,22 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0,
sage: from sage.graphs.graph_coloring import acyclic_edge_coloring
sage: g = graphs.CompleteGraph(8)
- sage: colors = acyclic_edge_coloring(g)
+ sage: colors = acyclic_edge_coloring(g) # needs sage.numerical.mip
Each color class is of course a matching ::
- sage: all(max(gg.degree()) <= 1 for gg in colors)
+ sage: all(max(gg.degree()) <= 1 for gg in colors) # needs sage.numerical.mip
True
These matchings being a partition of the edge set::
- sage: all(any(gg.has_edge(e) for gg in colors) for e in g.edge_iterator(labels=False))
+ sage: all(any(gg.has_edge(e) for gg in colors) # needs sage.numerical.mip
+ ....: for e in g.edge_iterator(labels=False))
True
Besides, the union of any two of them is a forest ::
- sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors)
+ sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) # needs sage.numerical.mip
True
If one wants to acyclically color a cycle on `4` vertices, at least 3 colors
@@ -2058,15 +2065,15 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0,
with only 2::
sage: g = graphs.CycleGraph(4)
- sage: acyclic_edge_coloring(g, k=2)
+ sage: acyclic_edge_coloring(g, k=2) # needs sage.numerical.mip
Traceback (most recent call last):
...
ValueError: this graph cannot be colored with the given number of colors
The optimal coloring give us `3` classes::
- sage: colors = acyclic_edge_coloring(g, k=None)
- sage: len(colors)
+ sage: colors = acyclic_edge_coloring(g, k=None) # needs sage.numerical.mip
+ sage: len(colors) # needs sage.numerical.mip
3
TESTS:
@@ -2074,32 +2081,32 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0,
Issue :trac:`24991` is fixed::
sage: from sage.graphs.graph_coloring import acyclic_edge_coloring
- sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4))
+ sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip
[2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5]
Test parameter ``hex_color`` (:trac:`26228`)::
sage: from sage.graphs.graph_coloring import acyclic_edge_coloring
sage: g = graphs.CompleteGraph(4)
- sage: d = acyclic_edge_coloring(g, hex_colors=True)
- sage: sorted(d)
+ sage: d = acyclic_edge_coloring(g, hex_colors=True) # needs sage.numerical.mip
+ sage: sorted(d) # needs sage.numerical.mip
['#0066ff', '#00ff66', '#cbff00', '#cc00ff', '#ff0000']
The acyclic chromatic index of a graph without edge is 0 (:trac:`27079`)::
sage: from sage.graphs.graph_coloring import acyclic_edge_coloring
sage: g = Graph(3)
- sage: acyclic_edge_coloring(g, k=None, value_only=True)
+ sage: acyclic_edge_coloring(g, k=None, value_only=True) # needs sage.numerical.mip
0
- sage: acyclic_edge_coloring(g, k=None, hex_colors=True)
+ sage: acyclic_edge_coloring(g, k=None, hex_colors=True) # needs sage.numerical.mip
{}
- sage: acyclic_edge_coloring(g, k=None, hex_colors=False)
+ sage: acyclic_edge_coloring(g, k=None, hex_colors=False) # needs sage.numerical.mip
[]
Empty graph (:trac:`27079`)::
sage: from sage.graphs.graph_coloring import acyclic_edge_coloring
- sage: acyclic_edge_coloring(Graph(), k=None, value_only=True)
+ sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) # needs sage.numerical.mip
0
"""
g._scream_if_not_simple(allow_multiple_edges=True)
diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py
index 9274ca13452..b8e9226bc2c 100644
--- a/src/sage/graphs/graph_database.py
+++ b/src/sage/graphs/graph_database.py
@@ -120,7 +120,7 @@ def graph6_to_plot(graph6):
EXAMPLES::
sage: from sage.graphs.graph_database import graph6_to_plot
- sage: type(graph6_to_plot('D??')) # optional - sage.plot
+ sage: type(graph6_to_plot('D??')) # needs sage.plot
"""
g = Graph(str(graph6))
diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx
index d72c6e5ff80..bbd3916ac2b 100644
--- a/src/sage/graphs/graph_decompositions/bandwidth.pyx
+++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx
@@ -160,7 +160,7 @@ def bandwidth(G, k=None):
False
sage: bandwidth(G)
(5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2])
- sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # optional - sage.modules
+ sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # needs sage.modules
[0 1 1 0 1 0 0 0 0 0]
[1 0 0 0 0 1 1 0 0 0]
[1 0 0 1 0 0 0 1 0 0]
@@ -174,7 +174,7 @@ def bandwidth(G, k=None):
sage: G = graphs.ChvatalGraph()
sage: bandwidth(G)
(6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])
- sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # optional - sage.modules
+ sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # needs sage.modules
[0 0 1 1 0 1 1 0 0 0 0 0]
[0 0 0 1 1 1 0 1 0 0 0 0]
[1 0 0 0 1 0 0 1 1 0 0 0]
diff --git a/src/sage/graphs/graph_decompositions/cutwidth.pyx b/src/sage/graphs/graph_decompositions/cutwidth.pyx
index 440d80ee2f6..208bd69dea4 100644
--- a/src/sage/graphs/graph_decompositions/cutwidth.pyx
+++ b/src/sage/graphs/graph_decompositions/cutwidth.pyx
@@ -372,7 +372,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False,
sage: G = Graph([(0, 1)])
sage: cutwidth(G, algorithm="exponential")
(1, [0, 1])
- sage: cutwidth(G, algorithm="MILP", solver='GLPK')
+ sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip
(1, [0, 1])
Cutwidth of a disconnected graph::
@@ -382,7 +382,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False,
sage: G.add_edge(2, 3)
sage: cutwidth(G, algorithm="exponential")
(1, [2, 3, 0, 1, 4])
- sage: cutwidth(G, algorithm="MILP", solver='GLPK')
+ sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip
(1, [2, 3, 0, 1, 4])
"""
from sage.graphs.graph import Graph
@@ -643,9 +643,9 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0,
sage: from sage.graphs.graph_decompositions import cutwidth
sage: G = graphs.CycleGraph(5)
- sage: cw, L = cutwidth.cutwidth_MILP(G); cw
+ sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip
2
- sage: cw == cutwidth.width_of_cut_decomposition(G, L)
+ sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip
True
sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe
2
@@ -654,18 +654,18 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0,
sage: from sage.graphs.graph_decompositions import cutwidth
sage: G = graphs.CompleteGraph(4)
- sage: cw, L = cutwidth.cutwidth_MILP(G); cw
+ sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip
4
- sage: cw == cutwidth.width_of_cut_decomposition(G, L)
+ sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip
True
Cutwidth of a Path graph::
sage: from sage.graphs.graph_decompositions import cutwidth
sage: G = graphs.PathGraph(3)
- sage: cw, L = cutwidth.cutwidth_MILP(G); cw
+ sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip
1
- sage: cw == cutwidth.width_of_cut_decomposition(G, L)
+ sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip
True
TESTS:
@@ -673,7 +673,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0,
Comparison with exponential algorithm::
sage: from sage.graphs.graph_decompositions import cutwidth
- sage: for i in range(2): # long time
+ sage: for i in range(2): # long time # needs sage.numerical.mip
....: G = graphs.RandomGNP(7, 0.3)
....: ve, le = cutwidth.cutwidth_dyn(G)
....: vm, lm = cutwidth.cutwidth_MILP(G, solver='GLPK')
@@ -684,7 +684,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0,
sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth_MILP
sage: G = graphs.CycleGraph(3)
- sage: cutwidth_MILP(G, lower_bound=G.size()+1)
+ sage: cutwidth_MILP(G, lower_bound=G.size()+1) # needs sage.numerical.mip
Traceback (most recent call last):
...
MIPSolverException: ...
diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pyx b/src/sage/graphs/graph_decompositions/fast_digraph.pyx
index fd75e5e63c3..3d7c4b2fea7 100644
--- a/src/sage/graphs/graph_decompositions/fast_digraph.pyx
+++ b/src/sage/graphs/graph_decompositions/fast_digraph.pyx
@@ -41,7 +41,7 @@ cdef class FastDigraph:
....: 'cdef FastDigraph F = FastDigraph(G)',
....: 'cdef int i',
....: 'print([F.degree[i] for i in range(F.n)])']
- sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
[1, 2, 1]
"""
if D.order() > 8*sizeof(int):
@@ -98,7 +98,7 @@ cdef class FastDigraph:
....: 'from sage.graphs.graph import Graph',
....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph',
....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()']
- sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
010
101
010
@@ -128,7 +128,7 @@ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S):
....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))',
....: 'cdef int i',
....: 'print([compute_out_neighborhood_cardinality(F, 1<> 1) & 0x55555555)
@@ -198,7 +198,7 @@ cdef inline int slow_popcount32(int i):
....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32',
....: 'cdef int i',
....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))']
- sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython
+ sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython
True
"""
# Slow popcount for 32bits integers
diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx
index 7042eabbfaf..31f49206586 100644
--- a/src/sage/graphs/graph_decompositions/graph_products.pyx
+++ b/src/sage/graphs/graph_decompositions/graph_products.pyx
@@ -206,8 +206,8 @@ def is_cartesian_product(g, certificate=False, relabeling=False):
Wagner's Graph (:trac:`13599`)::
- sage: g = graphs.WagnerGraph() # optional - networkx
- sage: g.is_cartesian_product() # optional - networkx
+ sage: g = graphs.WagnerGraph() # needs networkx
+ sage: g.is_cartesian_product() # needs networkx
False
Empty and one-element graph (:trac:`19546`)::
diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.py
index 230525e00e1..7a0c71c2fb1 100644
--- a/src/sage/graphs/graph_decompositions/modular_decomposition.py
+++ b/src/sage/graphs/graph_decompositions/modular_decomposition.py
@@ -610,7 +610,7 @@ def habib_maurer_algorithm(graph, g_classes=None):
decompositions. ::
sage: from sage.graphs.graph_decompositions.modular_decomposition import permute_decomposition
- sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # optional - sage.groups
+ sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # needs sage.groups
"""
if graph.is_directed():
raise ValueError("Graph must be undirected")
diff --git a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
index ad1e3fb1f03..3644edf6ac7 100644
--- a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
+++ b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
@@ -1,3 +1,5 @@
+// sage.setup: distribution = sagemath-tdlib
+
#include
#include