From bc5f5c1db7bde95c5480024d906da46a38cbdca9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 20 Jun 2023 21:48:56 -0700 Subject: [PATCH 001/262] build/pkgs/{cmr,googletest}: New --- build/pkgs/cmr/SPKG.rst | 32 +++++++++++++++++++++++ build/pkgs/cmr/checksums.ini | 5 ++++ build/pkgs/cmr/dependencies | 1 + build/pkgs/cmr/dependencies_order_only | 1 + build/pkgs/cmr/package-version.txt | 1 + build/pkgs/cmr/spkg-install.in | 9 +++++++ build/pkgs/cmr/type | 1 + build/pkgs/googletest/SPKG.rst | 19 ++++++++++++++ build/pkgs/googletest/checksums.ini | 5 ++++ build/pkgs/googletest/package-version.txt | 1 + build/pkgs/googletest/spkg-install.in | 9 +++++++ build/pkgs/googletest/type | 1 + 12 files changed, 85 insertions(+) create mode 100644 build/pkgs/cmr/SPKG.rst create mode 100644 build/pkgs/cmr/checksums.ini create mode 100644 build/pkgs/cmr/dependencies create mode 100644 build/pkgs/cmr/dependencies_order_only create mode 100644 build/pkgs/cmr/package-version.txt create mode 100644 build/pkgs/cmr/spkg-install.in create mode 100644 build/pkgs/cmr/type create mode 100644 build/pkgs/googletest/SPKG.rst create mode 100644 build/pkgs/googletest/checksums.ini create mode 100644 build/pkgs/googletest/package-version.txt create mode 100644 build/pkgs/googletest/spkg-install.in create mode 100644 build/pkgs/googletest/type diff --git a/build/pkgs/cmr/SPKG.rst b/build/pkgs/cmr/SPKG.rst new file mode 100644 index 00000000000..a8d73dd0f79 --- /dev/null +++ b/build/pkgs/cmr/SPKG.rst @@ -0,0 +1,32 @@ +cmr: Combinatorial matrix recognition +===================================== + +Description +----------- + +The following matrix classes can be recognized: + +- Totally Unimodular Matrices +- Network Matrices +- Complement Totally Unimodular Matrices +- (Strongly) k-Modular and Unimodular Matrices + +Moreover, representation matrices for the following matroid classes can be recognized: + +- Regular Matroids +- Graphic / Cographic / Planar Matrices +- Series-Parallel Matroids + + +License +------- + +MIT license + + +Upstream Contact +---------------- + +https://discopt.github.io/cmr/ + +https://github.com/discopt/cmr diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini new file mode 100644 index 00000000000..ba00c11472a --- /dev/null +++ b/build/pkgs/cmr/checksums.ini @@ -0,0 +1,5 @@ +tarball=cmr-0+VERSION.tar.gz +sha1=128ace88629d11c3b407a2957d3f8e4276aa9c19 +md5=362cc83e039262c25f9ecdb7e219a2da +cksum=511125891 +upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/dependencies b/build/pkgs/cmr/dependencies new file mode 100644 index 00000000000..8e2118051ff --- /dev/null +++ b/build/pkgs/cmr/dependencies @@ -0,0 +1 @@ +googletest diff --git a/build/pkgs/cmr/dependencies_order_only b/build/pkgs/cmr/dependencies_order_only new file mode 100644 index 00000000000..a3ea3e4380f --- /dev/null +++ b/build/pkgs/cmr/dependencies_order_only @@ -0,0 +1 @@ +cmake diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt new file mode 100644 index 00000000000..a7fe28c60e1 --- /dev/null +++ b/build/pkgs/cmr/package-version.txt @@ -0,0 +1 @@ +5887831f71679dcf4801a0079733d666ac06404f diff --git a/build/pkgs/cmr/spkg-install.in b/build/pkgs/cmr/spkg-install.in new file mode 100644 index 00000000000..f60a8c8825e --- /dev/null +++ b/build/pkgs/cmr/spkg-install.in @@ -0,0 +1,9 @@ +# -*- shell-script -*- +cd src +# Need C++14, so remove our flags that force C++11 +export CXX="$(echo "$CXX" | sed 's/-std=[a-z0-9+]*//g') -std=gnu++14" +mkdir build +cd build +sdh_cmake .. +sdh_make +sdh_make_install diff --git a/build/pkgs/cmr/type b/build/pkgs/cmr/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/cmr/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/googletest/SPKG.rst b/build/pkgs/googletest/SPKG.rst new file mode 100644 index 00000000000..fde8c4ed840 --- /dev/null +++ b/build/pkgs/googletest/SPKG.rst @@ -0,0 +1,19 @@ +googletest: Google testing and mocking framework +================================================ + +Description +----------- + +C++ test framework + + +License +------- + +BSD-3-Clause license + + +Upstream Contact +---------------- + +https://github.com/google/googletest diff --git a/build/pkgs/googletest/checksums.ini b/build/pkgs/googletest/checksums.ini new file mode 100644 index 00000000000..91398fb19fb --- /dev/null +++ b/build/pkgs/googletest/checksums.ini @@ -0,0 +1,5 @@ +tarball=googletest-VERSION.tar.gz +sha1=bfa4b5131b6eaac06962c251742c96aab3f7aa78 +md5=95b29f0038ec84a611df951d74d99897 +cksum=719315074 +upstream_url=https://github.com/google/googletest/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/googletest/package-version.txt b/build/pkgs/googletest/package-version.txt new file mode 100644 index 00000000000..feaae22bac7 --- /dev/null +++ b/build/pkgs/googletest/package-version.txt @@ -0,0 +1 @@ +1.13.0 diff --git a/build/pkgs/googletest/spkg-install.in b/build/pkgs/googletest/spkg-install.in new file mode 100644 index 00000000000..f60a8c8825e --- /dev/null +++ b/build/pkgs/googletest/spkg-install.in @@ -0,0 +1,9 @@ +# -*- shell-script -*- +cd src +# Need C++14, so remove our flags that force C++11 +export CXX="$(echo "$CXX" | sed 's/-std=[a-z0-9+]*//g') -std=gnu++14" +mkdir build +cd build +sdh_cmake .. +sdh_make +sdh_make_install diff --git a/build/pkgs/googletest/type b/build/pkgs/googletest/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/googletest/type @@ -0,0 +1 @@ +optional From 13176b765fcd52bdee4ce6c88a1d2b9d388e53de Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jun 2023 07:47:53 -0700 Subject: [PATCH 002/262] build/pkgs/googletest: Add distros --- build/pkgs/googletest/distros/alpine.txt | 1 + build/pkgs/googletest/distros/arch.txt | 1 + build/pkgs/googletest/distros/debian.txt | 1 + build/pkgs/googletest/distros/fedora.txt | 1 + build/pkgs/googletest/distros/freebsd.txt | 1 + build/pkgs/googletest/distros/gentoo.txt | 1 + build/pkgs/googletest/distros/homebrew.txt | 1 + build/pkgs/googletest/distros/nix.txt | 1 + build/pkgs/googletest/distros/opensuse.txt | 1 + build/pkgs/googletest/distros/repology.txt | 1 + build/pkgs/googletest/distros/void.txt | 1 + 11 files changed, 11 insertions(+) create mode 100644 build/pkgs/googletest/distros/alpine.txt create mode 100644 build/pkgs/googletest/distros/arch.txt create mode 100644 build/pkgs/googletest/distros/debian.txt create mode 100644 build/pkgs/googletest/distros/fedora.txt create mode 100644 build/pkgs/googletest/distros/freebsd.txt create mode 100644 build/pkgs/googletest/distros/gentoo.txt create mode 100644 build/pkgs/googletest/distros/homebrew.txt create mode 100644 build/pkgs/googletest/distros/nix.txt create mode 100644 build/pkgs/googletest/distros/opensuse.txt create mode 100644 build/pkgs/googletest/distros/repology.txt create mode 100644 build/pkgs/googletest/distros/void.txt diff --git a/build/pkgs/googletest/distros/alpine.txt b/build/pkgs/googletest/distros/alpine.txt new file mode 100644 index 00000000000..2b5013430e6 --- /dev/null +++ b/build/pkgs/googletest/distros/alpine.txt @@ -0,0 +1 @@ +gtest-dev diff --git a/build/pkgs/googletest/distros/arch.txt b/build/pkgs/googletest/distros/arch.txt new file mode 100644 index 00000000000..5e17e6e11c8 --- /dev/null +++ b/build/pkgs/googletest/distros/arch.txt @@ -0,0 +1 @@ +gtest diff --git a/build/pkgs/googletest/distros/debian.txt b/build/pkgs/googletest/distros/debian.txt new file mode 100644 index 00000000000..8e2118051ff --- /dev/null +++ b/build/pkgs/googletest/distros/debian.txt @@ -0,0 +1 @@ +googletest diff --git a/build/pkgs/googletest/distros/fedora.txt b/build/pkgs/googletest/distros/fedora.txt new file mode 100644 index 00000000000..5e17e6e11c8 --- /dev/null +++ b/build/pkgs/googletest/distros/fedora.txt @@ -0,0 +1 @@ +gtest diff --git a/build/pkgs/googletest/distros/freebsd.txt b/build/pkgs/googletest/distros/freebsd.txt new file mode 100644 index 00000000000..b5572b17648 --- /dev/null +++ b/build/pkgs/googletest/distros/freebsd.txt @@ -0,0 +1 @@ +devel/googletest diff --git a/build/pkgs/googletest/distros/gentoo.txt b/build/pkgs/googletest/distros/gentoo.txt new file mode 100644 index 00000000000..160c470c7aa --- /dev/null +++ b/build/pkgs/googletest/distros/gentoo.txt @@ -0,0 +1 @@ +dev-cpp/gtest diff --git a/build/pkgs/googletest/distros/homebrew.txt b/build/pkgs/googletest/distros/homebrew.txt new file mode 100644 index 00000000000..8e2118051ff --- /dev/null +++ b/build/pkgs/googletest/distros/homebrew.txt @@ -0,0 +1 @@ +googletest diff --git a/build/pkgs/googletest/distros/nix.txt b/build/pkgs/googletest/distros/nix.txt new file mode 100644 index 00000000000..5e17e6e11c8 --- /dev/null +++ b/build/pkgs/googletest/distros/nix.txt @@ -0,0 +1 @@ +gtest diff --git a/build/pkgs/googletest/distros/opensuse.txt b/build/pkgs/googletest/distros/opensuse.txt new file mode 100644 index 00000000000..8e2118051ff --- /dev/null +++ b/build/pkgs/googletest/distros/opensuse.txt @@ -0,0 +1 @@ +googletest diff --git a/build/pkgs/googletest/distros/repology.txt b/build/pkgs/googletest/distros/repology.txt new file mode 100644 index 00000000000..5e17e6e11c8 --- /dev/null +++ b/build/pkgs/googletest/distros/repology.txt @@ -0,0 +1 @@ +gtest diff --git a/build/pkgs/googletest/distros/void.txt b/build/pkgs/googletest/distros/void.txt new file mode 100644 index 00000000000..721753a34cd --- /dev/null +++ b/build/pkgs/googletest/distros/void.txt @@ -0,0 +1 @@ +gtest-devel From a29c56f339f3fbb10db0e2a7cfd52bd7f973d068 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jun 2023 12:24:24 -0700 Subject: [PATCH 003/262] build/pkgs/cmr: Add gtest linking patch, build shared lib, add spkg-check.in --- build/pkgs/cmr/patches/link_gtest.patch | 19 +++++++++++++++++++ build/pkgs/cmr/spkg-check.in | 3 +++ build/pkgs/cmr/spkg-install.in | 4 ++-- build/pkgs/googletest/dependencies_order_only | 1 + build/pkgs/googletest/spkg-install.in | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 build/pkgs/cmr/patches/link_gtest.patch create mode 100644 build/pkgs/cmr/spkg-check.in create mode 100644 build/pkgs/googletest/dependencies_order_only diff --git a/build/pkgs/cmr/patches/link_gtest.patch b/build/pkgs/cmr/patches/link_gtest.patch new file mode 100644 index 00000000000..45160e1d4d2 --- /dev/null +++ b/build/pkgs/cmr/patches/link_gtest.patch @@ -0,0 +1,19 @@ +commit 23b0cf4402573babb7c3292a9f9d191cda1ee56b +Author: Matthias Koeppe +Date: Wed Jun 21 12:04:53 2023 -0700 + + test/CMakeLists.txt (cmr_gtest): Explicitly link against gtest + +diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt +index 0bde995..7027ce5 100644 +--- a/test/CMakeLists.txt ++++ b/test/CMakeLists.txt +@@ -37,7 +37,7 @@ endif() + + # Configure cmr_gtest target. + target_compile_features(cmr_gtest PRIVATE cxx_auto_type) +-target_link_libraries(cmr_gtest gtest_main CMR::cmr) ++target_link_libraries(cmr_gtest gtest_main gtest CMR::cmr) + + include(GoogleTest) + gtest_discover_tests(cmr_gtest) diff --git a/build/pkgs/cmr/spkg-check.in b/build/pkgs/cmr/spkg-check.in new file mode 100644 index 00000000000..35f1999505d --- /dev/null +++ b/build/pkgs/cmr/spkg-check.in @@ -0,0 +1,3 @@ +cd src +cd build +ctest diff --git a/build/pkgs/cmr/spkg-install.in b/build/pkgs/cmr/spkg-install.in index f60a8c8825e..22ebcf53c9c 100644 --- a/build/pkgs/cmr/spkg-install.in +++ b/build/pkgs/cmr/spkg-install.in @@ -4,6 +4,6 @@ cd src export CXX="$(echo "$CXX" | sed 's/-std=[a-z0-9+]*//g') -std=gnu++14" mkdir build cd build -sdh_cmake .. -sdh_make +sdh_cmake -DGENERATORS=on -DCMAKE_SYSTEM_PREFIX_PATH="$SAGE_LOCAL" -DHAVE_FLAG_SEARCH_PATHS_FIRST=0 -DSHARED=on .. +sdh_make VERBOSE=1 sdh_make_install diff --git a/build/pkgs/googletest/dependencies_order_only b/build/pkgs/googletest/dependencies_order_only new file mode 100644 index 00000000000..a3ea3e4380f --- /dev/null +++ b/build/pkgs/googletest/dependencies_order_only @@ -0,0 +1 @@ +cmake diff --git a/build/pkgs/googletest/spkg-install.in b/build/pkgs/googletest/spkg-install.in index f60a8c8825e..8573ba26d7b 100644 --- a/build/pkgs/googletest/spkg-install.in +++ b/build/pkgs/googletest/spkg-install.in @@ -4,6 +4,6 @@ cd src export CXX="$(echo "$CXX" | sed 's/-std=[a-z0-9+]*//g') -std=gnu++14" mkdir build cd build -sdh_cmake .. +sdh_cmake -DBUILD_SHARED_LIBS=ON .. sdh_make sdh_make_install From bdd93a99fd8ecedb7eb8357beb603573a9ae1fce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 22 Jun 2023 10:27:10 -0700 Subject: [PATCH 004/262] build/pkgs/cmr: Update to https://github.com/discopt/cmr/commit/9c309df92a0645872b44996e5fe20d1bd9002a2d --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- build/pkgs/cmr/patches/link_gtest.patch | 19 ------------------- 3 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 build/pkgs/cmr/patches/link_gtest.patch diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index ba00c11472a..435bb6e595e 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=128ace88629d11c3b407a2957d3f8e4276aa9c19 -md5=362cc83e039262c25f9ecdb7e219a2da -cksum=511125891 +sha1=43754f5e995b85c09cd8121a875a13ac6dda86ba +md5=e33f4469436ec9cd0a1f9bae9abf543b +cksum=3818534900 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index a7fe28c60e1..d3e2e6cd825 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -5887831f71679dcf4801a0079733d666ac06404f +9c309df92a0645872b44996e5fe20d1bd9002a2d diff --git a/build/pkgs/cmr/patches/link_gtest.patch b/build/pkgs/cmr/patches/link_gtest.patch deleted file mode 100644 index 45160e1d4d2..00000000000 --- a/build/pkgs/cmr/patches/link_gtest.patch +++ /dev/null @@ -1,19 +0,0 @@ -commit 23b0cf4402573babb7c3292a9f9d191cda1ee56b -Author: Matthias Koeppe -Date: Wed Jun 21 12:04:53 2023 -0700 - - test/CMakeLists.txt (cmr_gtest): Explicitly link against gtest - -diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt -index 0bde995..7027ce5 100644 ---- a/test/CMakeLists.txt -+++ b/test/CMakeLists.txt -@@ -37,7 +37,7 @@ endif() - - # Configure cmr_gtest target. - target_compile_features(cmr_gtest PRIVATE cxx_auto_type) --target_link_libraries(cmr_gtest gtest_main CMR::cmr) -+target_link_libraries(cmr_gtest gtest_main gtest CMR::cmr) - - include(GoogleTest) - gtest_discover_tests(cmr_gtest) From 6e96d70c14d20897d1eafd781c05ca580600f7ab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 22 Jun 2023 10:41:29 -0700 Subject: [PATCH 005/262] build/pkgs/cmr/dependencies: Add boost_cropped --- build/pkgs/cmr/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cmr/dependencies b/build/pkgs/cmr/dependencies index 8e2118051ff..2443b003eb1 100644 --- a/build/pkgs/cmr/dependencies +++ b/build/pkgs/cmr/dependencies @@ -1 +1 @@ -googletest +googletest boost_cropped From 1acd20eaf6aef965ac9aec2c4749487b5e73edf4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jul 2023 18:21:12 -0700 Subject: [PATCH 006/262] sage.libs.cmr, sage.matrix.matrix_cmr_sparse: New --- src/sage/libs/cmr/cmr.pxd | 36 +++++++ src/sage/matrix/matrix_cmr_sparse.pxd | 18 ++++ src/sage/matrix/matrix_cmr_sparse.pyx | 136 ++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 src/sage/libs/cmr/cmr.pxd create mode 100644 src/sage/matrix/matrix_cmr_sparse.pxd create mode 100644 src/sage/matrix/matrix_cmr_sparse.pyx diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd new file mode 100644 index 00000000000..792ee98daac --- /dev/null +++ b/src/sage/libs/cmr/cmr.pxd @@ -0,0 +1,36 @@ +# distutils: libraries = cmr + +cdef extern from "cmr/env.h": + int CMR_OKAY + int CMR_ERROR_INPUT + int CMR_ERROR_OUTPUT + int CMR_ERROR_MEMORY + int CMR_ERROR_INVALID + int CMR_ERROR_OVERFLOW + int CMR_ERROR_TIMEOUT + + ctypedef int CMR_ERROR + + ctypedef struct CMR + + int CMRcreateEnvironment(CMR** pcmr) + int CMRfreeEnvironment(CMR** pcmr) + + char* CMRgetErrorMessage(CMR* cmr) + void CMRclearErrorMessage(CMR* cmr) + +cdef extern from "cmr/matrix.h": + + ctypedef struct CMR_CHRMAT: + size_t numRows + size_t numColumns + size_t numNonzeros + size_t* rowSlice + size_t* entryColumns + char* entryValues + + CMR_ERROR CMRchrmatCreate(CMR* cmr, CMR_CHRMAT** presult, int numRows, int numColumns, int numNonzeros) + CMR_ERROR CMRchrmatSortNonzeros(CMR* cmr, CMR_CHRMAT* matrix) + # CMR_ERROR CMRchrmatPrintDense(CMR* cmr, CMR_CHRMAT* matrix, FILE* stream, char zeroChar, bint header) + CMR_ERROR CMRchrmatFindEntry(CMR_CHRMAT* matrix, size_t row, size_t column, size_t* pentry) + CMR_ERROR CMRchrmatFree(CMR* cmr, CMR_CHRMAT** pmatrix) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd new file mode 100644 index 00000000000..ae656c67c33 --- /dev/null +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -0,0 +1,18 @@ +from sage.libs.cmr.cmr cimport * + +from .matrix_sparse cimport Matrix_sparse + +cdef class Matrix_cmr_sparse(Matrix_sparse): + pass + +# cdef class Matrix_cmr_double_sparse(Matrix_cmr_sparse): +# pass + +# cdef class Matrix_cmr_int_sparse(Matrix_cmr_sparse): +# pass + +cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): + + cdef CMR_CHRMAT *_mat + + cdef _init_from_dict(self, dict d, int nrows, int ncols) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx new file mode 100644 index 00000000000..c3991858c8e --- /dev/null +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -0,0 +1,136 @@ +r""" +Sparse Matrices with CMR +""" + +from libc.stdint cimport SIZE_MAX + +from sage.rings.integer cimport Integer + +from .args cimport MatrixArgs_init + + +cdef class Matrix_cmr_sparse(Matrix_sparse): + pass + + +cdef CMR *cmr = NULL + + +cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]); M + [1 2 3] + [4 0 6] + sage: M.dict() + {(0, 0): 1, (0, 1): 2, (0, 2): 3, (1, 0): 4, (1, 2): 6} + + Matrices of this class are always immutable:: + + sage: M.is_immutable() + True + sage: copy(M) is M + True + sage: deepcopy(M) is M + True + + This matrix class can only store very small integers:: + + sage: Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 1, 3, sparse=True), [-128, 0, 127]) + [-128 0 127] + sage: Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 1, 3, sparse=True), [126, 127, 128]) + Traceback (most recent call last): + ... + OverflowError: value too large to convert to char + + Arithmetic does not preserve the implementation class (even if the numbers would fit):: + + sage: M2 = M + M; M2 + [ 2 4 6] + [ 8 0 12] + sage: type(M2) + + sage: M * 100 + [100 200 300] + [400 0 600] + """ + def __init__(self, parent, entries=None, copy=None, bint coerce=True): + r""" + TESTS:: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]); M + sage: TestSuite(M).run() + """ + cdef dict d + ma = MatrixArgs_init(parent, entries) + d = ma.dict(coerce) + self._init_from_dict(d, ma.nrows, ma.ncols) + + cdef _init_from_dict(self, dict d, int nrows, int ncols): + if cmr == NULL: + CMRcreateEnvironment(&cmr) + if CMRchrmatCreate(cmr, &self._mat, nrows, ncols, len(d)) != CMR_OKAY: + raise RuntimeError + for row in range(nrows): + self._mat.rowSlice[row] = 0 + for (row, col), coeff in d.items(): + if coeff: + self._mat.rowSlice[row + 1] += 1 + for row in range(nrows): + self._mat.rowSlice[row + 1] += self._mat.rowSlice[row] + for (row, col), coeff in d.items(): + if coeff: + index = self._mat.rowSlice[row] + self._mat.entryColumns[index] = col + self._mat.entryValues[index] = coeff + self._mat.rowSlice[row] = index + 1 + for row in reversed(range(nrows)): + self._mat.rowSlice[row + 1] = self._mat.rowSlice[row] + self._mat.rowSlice[0] = 0 + if CMRchrmatSortNonzeros(cmr, self._mat) != CMR_OKAY: + raise RuntimeError + self.set_immutable() + + cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): + cdef size_t index + if CMRchrmatFindEntry(self._mat, i, j, &index) != CMR_OKAY: + raise RuntimeError + if index == SIZE_MAX: + return Integer(0) + return Integer(self._mat.entryValues[index]) + + def _dict(self): + """ + Return the underlying dictionary of ``self``. + """ + cdef dict d + d = {} + for row in range(self._mat.numRows): + for index in range(self._mat.rowSlice[row], self._mat.rowSlice[row + 1]): + d[(row, self._mat.entryColumns[index])] = Integer(self._mat.entryValues[index]) + return d + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + def __dealloc__(self): + CMRchrmatFree(cmr, &self._mat) + + def _test_change_ring(self, **options): + return + + def _pickle(self): + version = 0 + return self._dict(), version + + def _unpickle(self, data, int version): + if version != 0: + raise RuntimeError("unknown matrix version (=%s)"%version) + self._init_from_dict(data, self._nrows, self._ncols) From ff6aa4099a0bff1e044b1b764c0a66c0c339b544 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jul 2023 19:30:41 -0700 Subject: [PATCH 007/262] sage.libs.cmr, sage.matrix.matrix_cmr_sparse: Add more --- src/sage/libs/cmr/cmr.pxd | 43 +++++++++++++++++++ src/sage/matrix/matrix_cmr_sparse.pyx | 61 +++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 792ee98daac..ebcbca99632 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -1,5 +1,8 @@ +# -*- python -*- # distutils: libraries = cmr +# (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "") (replace-regexp "[;{}]" "") (replace-regexp "CMR_EXPORT *" "") (replace-regexp "bool" "bint")) + cdef extern from "cmr/env.h": int CMR_OKAY int CMR_ERROR_INPUT @@ -21,6 +24,16 @@ cdef extern from "cmr/env.h": cdef extern from "cmr/matrix.h": + ctypedef struct CMR_SUBMAT: + size_t numRows + size_t* rows + size_t numColumns + size_t* columns + + CMR_ERROR CMRsubmatCreate(CMR* cmr, size_t numRows, size_t numColumns, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRsubmatCreate1x1(CMR* cmr, size_t row, size_t column, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRsubmatFree(CMR* cmr, CMR_SUBMAT** psubmatrix) + ctypedef struct CMR_CHRMAT: size_t numRows size_t numColumns @@ -33,4 +46,34 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRchrmatSortNonzeros(CMR* cmr, CMR_CHRMAT* matrix) # CMR_ERROR CMRchrmatPrintDense(CMR* cmr, CMR_CHRMAT* matrix, FILE* stream, char zeroChar, bint header) CMR_ERROR CMRchrmatFindEntry(CMR_CHRMAT* matrix, size_t row, size_t column, size_t* pentry) + CMR_ERROR CMRchrmatZoomSubmat(CMR* cmr, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, CMR_CHRMAT** presult) CMR_ERROR CMRchrmatFree(CMR* cmr, CMR_CHRMAT** pmatrix) + +cdef extern from "cmr/k_modular.h": + + CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisUnimodular) + CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisStronglyUnimodular) + CMR_ERROR CMRtestKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisKmodular, size_t* pk) + CMR_ERROR CMRtestStrongKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisStronglyKmodular, size_t* pk) + +cdef extern from "cmr/camion.h": + + ctypedef struct CMR_CAMION_STATISTICS: + size_t totalCount + double totalTime + + CMR_ERROR CMRstatsCamionInit(CMR_CAMION_STATISTICS* stats) + # CMR_ERROR CMRstatsCamionPrint(FILE* stream, CMR_CAMION_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRtestCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bint* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcomputeCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bint* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + +cdef extern from "cmr/matroid.h": + + ctypedef struct CMR_MINOR: + size_t numPivots + size_t* pivotRows + size_t* pivotColumns + CMR_SUBMAT* remainingSubmatrix + + CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix) + CMR_ERROR CMRminorFree(CMR* cmr, CMR_MINOR** pminor) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index c3991858c8e..bdc8d04363b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -61,8 +61,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" TESTS:: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 2, 3], [4, 0, 6]]); M + [1 2 3] + [4 0 6] sage: TestSuite(M).run() """ cdef dict d @@ -134,3 +137,61 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if version != 0: raise RuntimeError("unknown matrix version (=%s)"%version) self._init_from_dict(data, self._nrows, self._ncols) + + # CMR-specific methods. Other classes that want to provide these methods should create + # a copy of themselves as an instance of this class and delegate to it. + + def is_unimodular(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 0, 0], [0, 1, 0]]); M + [1 0 0] + [0 1 0] + sage: M.is_unimodular() + True + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 1, 0], [-1, 1, 1]]); M + [ 1 1 0] + [-1 1 1] + sage: M.is_unimodular() + False + """ + cdef bint result + if CMRtestUnimodularity(cmr, self._mat, &result) != CMR_OKAY: + raise RuntimeError + return result + + def is_strongly_unimodular(self): + cdef bint result + if CMRtestStrongUnimodularity(cmr, self._mat, &result) != CMR_OKAY: + raise RuntimeError + return result + + def modulus(self): + cdef bint result + cdef size_t k + if CMRtestKmodularity(cmr, self._mat, &result, &k) != CMR_OKAY: + raise RuntimeError + if result: + return Integer(k) + else: + return None + + def strong_modulus(self): + cdef bint result + cdef size_t k + if CMRtestStrongKmodularity(cmr, self._mat, &result, &k) != CMR_OKAY: + raise RuntimeError + if result: + return Integer(k) + else: + return None + + def is_k_modular(self, k): + return self.modulus() <= k + + def is_strongly_k_modular(self, k): + return self.strong_modulus() <= k From c9c89496a705b893fc4ea35473930508f11c1813 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jul 2023 20:48:48 -0700 Subject: [PATCH 008/262] sage.libs.cmr: Add more --- src/sage/libs/cmr/cmr.pxd | 97 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index ebcbca99632..8bb6ca0f138 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -1,7 +1,7 @@ # -*- python -*- # distutils: libraries = cmr -# (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "") (replace-regexp "[;{}]" "") (replace-regexp "CMR_EXPORT *" "") (replace-regexp "bool" "bint")) +# (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "" nil (point) (point-max)) (replace-regexp "[;{}]" "" nil (point) (point-max)) (replace-regexp "CMR_EXPORT *" "" nil (point) (point-max)) (replace-regexp "bool" "bint" nil (point) (point-max))) cdef extern from "cmr/env.h": int CMR_OKAY @@ -77,3 +77,98 @@ cdef extern from "cmr/matroid.h": CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix) CMR_ERROR CMRminorFree(CMR* cmr, CMR_MINOR** pminor) + +cdef extern from "cmr/element.h": + + ctypedef int CMR_ELEMENT + + const char* CMRelementString(CMR_ELEMENT element, char* buffer) + bint CMRelementIsValid(CMR_ELEMENT element) + CMR_ELEMENT CMRrowToElement(size_t row) + CMR_ELEMENT CMRcolumnToElement(size_t column) + bint CMRelementIsRow(CMR_ELEMENT element) + size_t CMRelementToRowIndex(CMR_ELEMENT element) + bint CMRelementIsColumn(CMR_ELEMENT element) + size_t CMRelementToColumnIndex(CMR_ELEMENT element) + CMR_ELEMENT CMRelementTranspose(CMR_ELEMENT element) + +cdef extern from "cmr/separation.h": + + ctypedef struct CMR_SEPA: + unsigned char* rowsToPart + unsigned char* columnsToPart + size_t numRows[2] + size_t numColumns[2] + size_t* rows[2] + size_t* columns[2] + size_t extraRows[2][2] + size_t extraColumns[2][2] + unsigned char* indicatorMemory + size_t* elementMemory + + CMR_ERROR CMRsepaCreate(CMR* cmr, size_t numRows, size_t numColumns, CMR_SEPA** psepa) + CMR_ERROR CMRsepaInitialize(CMR* cmr, CMR_SEPA* separation, size_t firstExtraRow0, size_t firstExtraColumn1, size_t firstExtraRow1, size_t firstExtraColumn0, size_t secondExtraRow0, size_t secondExtraColumn1, size_t secondExtraRow1, size_t secondExtraColumn0) + CMR_ERROR CMRsepaInitializeMatrix(CMR* cmr, CMR_SEPA* separation, CMR_CHRMAT* matrix, unsigned char totalRank) + CMR_ERROR CMRsepaFree(CMR* cmr, CMR_SEPA** psepa) + unsigned char CMRsepaRankBottomLeft(CMR_SEPA* sepa) + unsigned char CMRsepaRankTopRight(CMR_SEPA* sepa) + unsigned char CMRsepaRank(CMR_SEPA* sepa) + CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bint* pisTernary, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRoneSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_CHRMAT** presult) + CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, CMR_CHRMAT** presult) + CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, CMR_CHRMAT** presult) + +cdef extern from "cmr/graph.h": + ctypedef int CMR_GRAPH_NODE + ctypedef int CMR_GRAPH_EDGE + ctypedef int CMR_GRAPH_ITER + + ctypedef struct CMR_GRAPH_NODE_DATA: + int prev + int next + int firstOut + + ctypedef struct CMR_GRAPH_ARC_DATA: + int target + int prev + int next + + ctypedef struct CMR_GRAPH: + size_t numNodes + size_t memNodes + CMR_GRAPH_NODE_DATA* nodes + int firstNode + int freeNode + size_t numEdges + size_t memEdges + CMR_GRAPH_ARC_DATA* arcs + int freeEdge + + size_t CMRgraphMemNodes(CMR_GRAPH* graph) + size_t CMRgraphNumNodes(CMR_GRAPH* graph) + size_t CMRgraphMemEdges(CMR_GRAPH* graph) + size_t CMRgraphNumEdges(CMR_GRAPH* graph) + CMR_GRAPH_NODE CMRgraphEdgeU(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_GRAPH_NODE CMRgraphEdgeV(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_ERROR CMRgraphCreateEmpty(CMR* cmr, CMR_GRAPH** pgraph, int memNodes, int memEdges) + CMR_ERROR CMRgraphFree(CMR* cmr, CMR_GRAPH** pgraph) + CMR_ERROR CMRgraphClear(CMR* cmr, CMR_GRAPH* graph) + CMR_ERROR CMRgraphAddNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE* pnode) + CMR_ERROR CMRgraphAddEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v, CMR_GRAPH_EDGE* pedge) + CMR_ERROR CMRgraphDeleteNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_ERROR CMRgraphDeleteEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_GRAPH_NODE CMRgraphNodesFirst(CMR_GRAPH* graph) + bint CMRgraphNodesValid(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_GRAPH_NODE CMRgraphNodesNext(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_GRAPH_ITER CMRgraphIncFirst(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + bint CMRgraphIncValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_ITER CMRgraphIncNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_EDGE CMRgraphIncEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_NODE CMRgraphIncSource(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_NODE CMRgraphIncTarget(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_ITER CMRgraphEdgesNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + bint CMRgraphEdgesValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_EDGE CMRgraphEdgesEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + # CMR_ERROR CMRgraphPrint(FILE* stream, CMR_GRAPH* graph) + CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) + # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) From b4a90b7d67806dad080cb897af563c8cf4c53042 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 00:01:17 -0700 Subject: [PATCH 009/262] sage.libs.cmr, sage.matrix.matrix_cmr_sparse: Add is_graphic --- src/sage/libs/cmr/cmr.pxd | 26 ++++++++ src/sage/matrix/matrix_cmr_sparse.pyx | 88 +++++++++++++++++++++------ 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 8bb6ca0f138..2666ab23304 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -119,6 +119,7 @@ cdef extern from "cmr/separation.h": CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, CMR_CHRMAT** presult) cdef extern from "cmr/graph.h": + ctypedef int CMR_GRAPH_NODE ctypedef int CMR_GRAPH_EDGE ctypedef int CMR_GRAPH_ITER @@ -172,3 +173,28 @@ cdef extern from "cmr/graph.h": # CMR_ERROR CMRgraphPrint(FILE* stream, CMR_GRAPH* graph) CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) + +cdef extern from "cmr/graphic.h": + + ctypedef struct CMR_GRAPHIC_STATISTICS: + size_t totalCount + double totalTime + size_t checkCount + double checkTime + size_t applyCount + double applyTime + size_t transposeCount + double transposeTime + + CMR_ERROR CMRstatsGraphicInit(CMR_GRAPHIC_STATISTICS* stats) + # CMR_ERROR CMRstatsGraphicPrint(FILE* stream, CMR_GRAPHIC_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRcomputeGraphicMatrix(CMR* cmr, CMR_GRAPH* graph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, int numForestEdges, CMR_GRAPH_EDGE* forestEdges, int numCoforestEdges, CMR_GRAPH_EDGE* coforestEdges, bint* pisCorrectForest) + CMR_ERROR CMRtestGraphicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisGraphic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestCographicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestGraphicColumnSubmatrixGreedy(CMR* cmr, CMR_CHRMAT* transpose, size_t* orderedColumns, CMR_SUBMAT** psubmatrix) + + +# Our global CMR environment +cdef CMR *cmr + +cdef CMR_CALL(CMR_ERROR _cmr_error) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index bdc8d04363b..fa0930a8e50 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -4,6 +4,8 @@ Sparse Matrices with CMR from libc.stdint cimport SIZE_MAX +from cysignals.signals cimport sig_on, sig_off + from sage.rings.integer cimport Integer from .args cimport MatrixArgs_init @@ -13,9 +15,6 @@ cdef class Matrix_cmr_sparse(Matrix_sparse): pass -cdef CMR *cmr = NULL - - cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" EXAMPLES:: @@ -76,8 +75,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _init_from_dict(self, dict d, int nrows, int ncols): if cmr == NULL: CMRcreateEnvironment(&cmr) - if CMRchrmatCreate(cmr, &self._mat, nrows, ncols, len(d)) != CMR_OKAY: - raise RuntimeError + CMR_CALL(CMRchrmatCreate(cmr, &self._mat, nrows, ncols, len(d))) for row in range(nrows): self._mat.rowSlice[row] = 0 for (row, col), coeff in d.items(): @@ -94,14 +92,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): for row in reversed(range(nrows)): self._mat.rowSlice[row + 1] = self._mat.rowSlice[row] self._mat.rowSlice[0] = 0 - if CMRchrmatSortNonzeros(cmr, self._mat) != CMR_OKAY: - raise RuntimeError + CMR_CALL(CMRchrmatSortNonzeros(cmr, self._mat)) self.set_immutable() cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): cdef size_t index - if CMRchrmatFindEntry(self._mat, i, j, &index) != CMR_OKAY: - raise RuntimeError + CMR_CALL(CMRchrmatFindEntry(self._mat, i, j, &index)) if index == SIZE_MAX: return Integer(0) return Integer(self._mat.entryValues[index]) @@ -160,21 +156,30 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): False """ cdef bint result - if CMRtestUnimodularity(cmr, self._mat, &result) != CMR_OKAY: - raise RuntimeError + + sig_on() + CMR_CALL(CMRtestUnimodularity(cmr, self._mat, &result)) + sig_off() + return result def is_strongly_unimodular(self): cdef bint result - if CMRtestStrongUnimodularity(cmr, self._mat, &result) != CMR_OKAY: - raise RuntimeError + + sig_on() + CMR_CALL(CMRtestStrongUnimodularity(cmr, self._mat, &result)) + sig_off() + return result def modulus(self): cdef bint result cdef size_t k - if CMRtestKmodularity(cmr, self._mat, &result, &k) != CMR_OKAY: - raise RuntimeError + + sig_on() + CMR_CALL(CMRtestKmodularity(cmr, self._mat, &result, &k)) + sig_off() + if result: return Integer(k) else: @@ -183,8 +188,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def strong_modulus(self): cdef bint result cdef size_t k - if CMRtestStrongKmodularity(cmr, self._mat, &result, &k) != CMR_OKAY: - raise RuntimeError + + sig_on() + CMR_CALL(CMRtestStrongKmodularity(cmr, self._mat, &result, &k)) + sig_off() + if result: return Integer(k) else: @@ -195,3 +203,49 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_strongly_k_modular(self, k): return self.strong_modulus() <= k + + def is_graphic(self, *, time_limit=60.0, certificate=False): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, -1]]); M + [ 1 0] + [-1 1] + [ 0 -1] + sage: M.is_graphic() + True + + TESTS:: + + sage: M.is_graphic(time_limit=0.0) + Traceback (most recent call last): + ... + RuntimeError: Time limit exceeded + """ + cdef bint result + cdef CMR_GRAPH *graph + cdef CMR_GRAPH_EDGE* forest_edges + cdef CMR_GRAPH_EDGE* coforest_edges + cdef CMR_SUBMAT* submatrix + cdef CMR_GRAPHIC_STATISTICS stats + + if certificate: + sig_on() + CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, &graph, &forest_edges, + &coforest_edges, &submatrix, &stats, time_limit)) + sig_off() + # FIXME: this segfaults despite the sig_on/sig_off + else: + sig_on() + CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, NULL, NULL, + NULL, NULL, &stats, time_limit)) + sig_off() + + if certificate: + raise NotImplementedError + return result + + def is_cographic(self, certificate=False): + raise NotImplementedError From 26f30b53692d69274caf958e1b6213b91396ffa7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 10:24:20 -0700 Subject: [PATCH 010/262] src/sage/matrix/matrix_cmr_sparse.pyx: Fixups --- src/sage/matrix/matrix_cmr_sparse.pyx | 53 +++++++++++++++++---------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index fa0930a8e50..79ed7d2da91 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -158,8 +158,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bint result sig_on() - CMR_CALL(CMRtestUnimodularity(cmr, self._mat, &result)) - sig_off() + try: + CMR_CALL(CMRtestUnimodularity(cmr, self._mat, &result)) + finally: + sig_off() return result @@ -167,8 +169,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bint result sig_on() - CMR_CALL(CMRtestStrongUnimodularity(cmr, self._mat, &result)) - sig_off() + try: + CMR_CALL(CMRtestStrongUnimodularity(cmr, self._mat, &result)) + finally: + sig_off() return result @@ -177,8 +181,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef size_t k sig_on() - CMR_CALL(CMRtestKmodularity(cmr, self._mat, &result, &k)) - sig_off() + try: + CMR_CALL(CMRtestKmodularity(cmr, self._mat, &result, &k)) + finally: + sig_off() if result: return Integer(k) @@ -190,8 +196,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef size_t k sig_on() - CMR_CALL(CMRtestStrongKmodularity(cmr, self._mat, &result, &k)) - sig_off() + try: + CMR_CALL(CMRtestStrongKmodularity(cmr, self._mat, &result, &k)) + finally: + sig_off() if result: return Integer(k) @@ -216,6 +224,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 -1] sage: M.is_graphic() True + sage: M.is_graphic(certificate=True) + Traceback (most recent call last): + ... + NotImplementedError TESTS:: @@ -225,23 +237,26 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): RuntimeError: Time limit exceeded """ cdef bint result - cdef CMR_GRAPH *graph - cdef CMR_GRAPH_EDGE* forest_edges - cdef CMR_GRAPH_EDGE* coforest_edges - cdef CMR_SUBMAT* submatrix + cdef CMR_GRAPH *graph = NULL + cdef CMR_GRAPH_EDGE* forest_edges = NULL + cdef CMR_GRAPH_EDGE* coforest_edges = NULL + cdef CMR_SUBMAT* submatrix = NULL cdef CMR_GRAPHIC_STATISTICS stats if certificate: sig_on() - CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, &graph, &forest_edges, - &coforest_edges, &submatrix, &stats, time_limit)) - sig_off() - # FIXME: this segfaults despite the sig_on/sig_off + try: + CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, &graph, &forest_edges, + &coforest_edges, &submatrix, &stats, time_limit)) + finally: + sig_off() else: sig_on() - CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, NULL, NULL, - NULL, NULL, &stats, time_limit)) - sig_off() + try: + CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, NULL, NULL, + NULL, NULL, &stats, time_limit)) + finally: + sig_off() if certificate: raise NotImplementedError From ecd66c354708e73891c72852ae3c25d44e7a1bc0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 11:39:36 -0700 Subject: [PATCH 011/262] src/sage/matrix/matrix_cmr_sparse.pyx: is_graphic certificates --- src/sage/matrix/matrix_cmr_sparse.pyx | 67 ++++++++++++++++++++------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 79ed7d2da91..1c9de63b28d 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -222,12 +222,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 1 0] [-1 1] [ 0 -1] - sage: M.is_graphic() + sage: M.is_graphic() # ?? should it not check 0/1-ness? True - sage: M.is_graphic(certificate=True) - Traceback (most recent call last): - ... - NotImplementedError + sage: result, certificate = M.is_graphic(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: graph.vertices(sort=True) # what is the meaning of the numbers? + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] + sage: forest_edges # indexed by rows of M + ((1, 2), (7, 1), (12, 7)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (1, 12)) TESTS:: @@ -243,24 +249,49 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef CMR_SUBMAT* submatrix = NULL cdef CMR_GRAPHIC_STATISTICS stats - if certificate: - sig_on() - try: + sig_on() + try: + if certificate: CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, &graph, &forest_edges, &coforest_edges, &submatrix, &stats, time_limit)) - finally: - sig_off() - else: - sig_on() - try: + else: CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, NULL, NULL, NULL, NULL, &stats, time_limit)) - finally: - sig_off() + finally: + sig_off() + + if not certificate: + return result + + # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend + from sage.graphs.graph import Graph + + def vertices(): + i = CMRgraphNodesFirst(graph) + while CMRgraphNodesValid(graph, i): + yield i + i = CMRgraphNodesNext(graph, i) + + def edge(e): + return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) + + def edges(): + i = CMRgraphEdgesFirst(graph) + while CMRgraphEdgesValid(graph, i): + e = CMRgraphEdgesEdge(graph, i) + yield edge(e) + i = CMRgraphEdgesNext(graph, i) + + if result: + sage_graph = Graph([list(vertices()), list(edges())]) + sage_forest_edges = tuple(edge(forest_edges[row]) + for row in range(self.nrows())) + sage_coforest_edges = tuple(edge(coforest_edges[column]) + for column in range(self.ncols())) + return True, (sage_graph, sage_forest_edges, sage_coforest_edges) + + return False, None # submatrix TBD - if certificate: - raise NotImplementedError - return result def is_cographic(self, certificate=False): raise NotImplementedError From dae3db408d485ac50bc8b17b2b334c31cf0a2507 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 12:24:01 -0700 Subject: [PATCH 012/262] sage.libs.cmr: Add more --- src/sage/libs/cmr/cmr.pxd | 199 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 8 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 2666ab23304..d29e258a1a4 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -167,6 +167,7 @@ cdef extern from "cmr/graph.h": CMR_GRAPH_EDGE CMRgraphIncEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) CMR_GRAPH_NODE CMRgraphIncSource(CMR_GRAPH* graph, CMR_GRAPH_ITER i) CMR_GRAPH_NODE CMRgraphIncTarget(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_ITER CMRgraphEdgesFirst(CMR_GRAPH* graph) CMR_GRAPH_ITER CMRgraphEdgesNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) bint CMRgraphEdgesValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) CMR_GRAPH_EDGE CMRgraphEdgesEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) @@ -177,14 +178,14 @@ cdef extern from "cmr/graph.h": cdef extern from "cmr/graphic.h": ctypedef struct CMR_GRAPHIC_STATISTICS: - size_t totalCount - double totalTime - size_t checkCount - double checkTime - size_t applyCount - double applyTime - size_t transposeCount - double transposeTime + size_t totalCount + double totalTime + size_t checkCount + double checkTime + size_t applyCount + double applyTime + size_t transposeCount + double transposeTime CMR_ERROR CMRstatsGraphicInit(CMR_GRAPHIC_STATISTICS* stats) # CMR_ERROR CMRstatsGraphicPrint(FILE* stream, CMR_GRAPHIC_STATISTICS* stats, const char* prefix) @@ -193,6 +194,188 @@ cdef extern from "cmr/graphic.h": CMR_ERROR CMRtestCographicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) CMR_ERROR CMRtestGraphicColumnSubmatrixGreedy(CMR* cmr, CMR_CHRMAT* transpose, size_t* orderedColumns, CMR_SUBMAT** psubmatrix) +cdef extern from "cmr/series_parallel.h": + + ctypedef struct CMR_SP_STATISTICS: + size_t totalCount + double totalTime + size_t reduceCount + double reduceTime + size_t wheelCount + double wheelTime + size_t nonbinaryCount + double nonbinaryTime + + CMR_ERROR CMRstatsSeriesParallelInit(CMR_SP_STATISTICS* stats) + + # CMR_ERROR CMRstatsSeriesParallelPrint(FILE* stream, CMR_SP_STATISTICS* stats, const char* prefix) + + ctypedef struct CMR_SP_REDUCTION: + CMR_ELEMENT element + CMR_ELEMENT mate + + char* CMRspReductionString(CMR_SP_REDUCTION reduction, char* buffer) + + bint CMRspIsRow(CMR_SP_REDUCTION reduction) + bint CMRspIsColumn(CMR_SP_REDUCTION reduction) + bint CMRspIsZero(CMR_SP_REDUCTION reduction) + bint CMRspIsUnit(CMR_SP_REDUCTION reduction) + bint CMRspIsCopy(CMR_SP_REDUCTION reduction) + bint CMRspIsValid(CMR_SP_REDUCTION reduction) + + CMR_ERROR CMRtestBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRdecomposeBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRdecomposeTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + +cdef extern from "cmr/network.h": + + ctypedef struct CMR_NETWORK_STATISTICS: + size_t totalCount + double totalTime + CMR_CAMION_STATISTICS camion + CMR_GRAPHIC_STATISTICS graphic + + CMR_ERROR CMRstatsNetworkInit(CMR_NETWORK_STATISTICS* stats) + # CMR_ERROR CMRstatsNetworkPrint(FILE* stream, CMR_NETWORK_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRcomputeNetworkMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bint* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bint* pisCorrectForest) + CMR_ERROR CMRtestNetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bint** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestConetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bint** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + +cdef extern from "cmr/dec.h": + + ctypedef struct CMR_DEC + + ctypedef int CMR_DEC_TYPE + + int CMR_DEC_IRREGULAR + int CMR_DEC_UNKNOWN + int CMR_DEC_ONE_SUM + int CMR_DEC_TWO_SUM + int CMR_DEC_THREE_SUM + int CMR_DEC_GRAPHIC + int CMR_DEC_COGRAPHIC + int CMR_DEC_PLANAR + int CMR_DEC_SERIES_PARALLEL + int CMR_DEC_SPECIAL_R10 + int CMR_DEC_SPECIAL_FANO + int CMR_DEC_SPECIAL_FANO_DUAL + int CMR_DEC_SPECIAL_K_5 + int CMR_DEC_SPECIAL_K_5_DUAL + int CMR_DEC_SPECIAL_K_3_3 + int CMR_DEC_SPECIAL_K_3_3_DUAL + + ctypedef int CMR_DEC_FLAGS + + int CMR_DEC_MASK_REPRESENTATION + int CMR_DEC_IS_GRAPHIC + int CMR_DEC_IS_COGRAPHIC + int CMR_DEC_IS_REGULAR + int CMR_DEC_HAS_LOWER_LEFT_NONZEROS + int CMR_DEC_HAS_UPPER_RIGHT_NONZEROS + + CMR_ERROR CMRdecFree(CMR* cmr, CMR_DEC** pdec) + bint CMRdecHasMatrix(CMR_DEC* dec) + bint CMRdecHasTranspose(CMR_DEC* dec) + CMR_CHRMAT* CMRdecGetMatrix(CMR_DEC* dec) + CMR_CHRMAT* CMRdecGetTranspose(CMR_DEC* dec) + size_t CMRdecNumChildren(CMR_DEC* dec) + CMR_DEC* CMRdecChild(CMR_DEC* dec, size_t childIndex) + int CMRdecIsSum(CMR_DEC* dec, bint* plowerLeftNonzeros, bint* pupperRightNonzeros) + CMR_DEC_TYPE CMRdecIsSpecialLeaf(CMR_DEC* dec, int* prepresentationMatrix) + bint CMRdecIsGraphicLeaf(CMR_DEC* dec) + bint CMRdecIsCographicLeaf(CMR_DEC* dec) + bint CMRdecIsGraphic(CMR_DEC* dec) + bint CMRdecIsCographic(CMR_DEC* dec) + bint CMRdecIsRegular(CMR_DEC* dec) + bint CMRdecNumRows(CMR_DEC* dec) + CMR_ELEMENT* CMRdecRowElements(CMR_DEC* dec) + size_t* CMRdecRowsParent(CMR_DEC* dec) + bint CMRdecNumColumns(CMR_DEC* dec) + CMR_ELEMENT* CMRdecColumnElements(CMR_DEC* dec) + size_t* CMRdecColumnsParent(CMR_DEC* dec) + # CMR_ERROR CMRdecPrint(CMR* cmr, CMR_DEC* dec, FILE* stream, size_t indent, bint printMatrices, bint printGraphs, bint printReductions) + char* CMRdecConsistency(CMR_DEC* dec, bint recurse) + CMR_GRAPH* CMRdecGraph(CMR_DEC* dec) + CMR_GRAPH_EDGE* CMRdecGraphForest(CMR_DEC* dec) + size_t CMRdecGraphSizeForest(CMR_DEC* dec) + CMR_GRAPH_EDGE* CMRdecGraphCoforest(CMR_DEC* dec) + size_t CMRdecGraphSizeCoforest(CMR_DEC* dec) + bint* CMRdecGraphArcsReversed(CMR_DEC* dec) + CMR_GRAPH* CMRdecCograph(CMR_DEC* dec) + CMR_GRAPH_EDGE* CMRdecCographForest(CMR_DEC* dec) + CMR_GRAPH_EDGE* CMRdecCographCoforest(CMR_DEC* dec) + bint* CMRdecCographArcsReversed(CMR_DEC* dec) + + +cdef extern from "cmr/regular.h": + + ctypedef int CMR_DEC_CONSTRUCT + + int CMR_DEC_CONSTRUCT_NONE + int CMR_DEC_CONSTRUCT_LEAVES + int CMR_DEC_CONSTRUCT_ALL + + ctypedef struct CMR_REGULAR_PARAMETERS: + bint directGraphicness + bint seriesParallel + bint planarityCheck + bint completeTree + CMR_DEC_CONSTRUCT matrices + CMR_DEC_CONSTRUCT transposes + CMR_DEC_CONSTRUCT graphs + + CMR_ERROR CMRparamsRegularInit(CMR_REGULAR_PARAMETERS* params) + + ctypedef struct CMR_REGULAR_STATISTICS: + size_t totalCount + double totalTime + CMR_SP_STATISTICS seriesParallel + CMR_GRAPHIC_STATISTICS graphic + CMR_NETWORK_STATISTICS network + size_t sequenceExtensionCount + double sequenceExtensionTime + size_t sequenceGraphicCount + double sequenceGraphicTime + size_t enumerationCount + double enumerationTime + size_t enumerationCandidatesCount + + CMR_ERROR CMRstatsRegularInit(CMR_REGULAR_STATISTICS* stats) + # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRtestBinaryRegular(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMETERS* params, CMR_REGULAR_STATISTICS* stats, double timeLimit) + + +cdef extern from "cmr/tu.h": + + ctypedef struct CMR_TU_PARAMETERS: + CMR_REGULAR_PARAMETERS regular + + CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMETERS* params) + + ctypedef struct CMR_TU_STATISTICS: + size_t totalCount + double totalTime + CMR_CAMION_STATISTICS camion + CMR_REGULAR_STATISTICS regular + + CMR_ERROR CMRstatsTotalUnimodularityInit(CMR_TU_STATISTICS* stats) + # CMR_ERROR CMRstatsTotalUnimodularityPrint(FILE* stream, CMR_TU_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMETERS* params, CMR_TU_STATISTICS* stats, double timeLimit) + + +cdef extern from "cmr/ctu.h": + + ctypedef struct CMR_CTU_STATISTICS: + size_t totalCount + double totalTime + CMR_TU_STATISTICS tu + + CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATISTICS* stats) + # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRcomplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) + CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats) + # Our global CMR environment cdef CMR *cmr From 9901da90772070c42d871f3f61b7d0675545d762 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 18:13:00 -0700 Subject: [PATCH 013/262] src/sage/matrix/matrix_cmr_sparse.pyx: _is_binary_linear_matroid_regular (first version) --- src/sage/matrix/matrix_cmr_sparse.pyx | 85 ++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1c9de63b28d..79f4de7de1f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -292,6 +292,87 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, None # submatrix TBD - - def is_cographic(self, certificate=False): + def is_cographic(self, *, time_limit=60.0, certificate=False): raise NotImplementedError + + def is_network_matrix(self, *, time_limit=60.0, certificate=False): + raise NotImplementedError + + def is_dual_network_matrix(self, *, time_limit=60.0, certificate=False): + raise NotImplementedError + + def _is_binary_linear_matroid_regular(self, *, time_limit=60.0, certificate=False, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='if_regular', + construct_matrices=False, + construct_transposes=False, + construct_graphs=False): + r""" + This is an internal method because it should really be exposed + as a method of :class:`Matroid`. + + INPUT: + + - ``certificate``: One of ``False``, ``True``, ``'if_regular'``, ``'if_not_regular'`` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [1, 1], [0, 1]]); M + [1 0] + [1 1] + [0 1] + sage: M._is_binary_linear_matroid_regular() + True + """ + cdef bint result + cdef CMR_REGULAR_PARAMETERS params + cdef CMR_REGULAR_STATISTICS stats + cdef CMR_DEC *dec = NULL + cdef CMR_MINOR *minor = NULL + + cdef CMR_DEC **pdec = &dec + cdef CMR_MINOR **pminor = &minor + + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + series_parallel_ok=series_parallel_ok, + check_graphic_minors_planar=check_graphic_minors_planar, + complete_tree=complete_tree, + construct_matrices=construct_matrices, + construct_transposes=construct_transposes, + construct_graphs=construct_graphs) + + _set_cmr_regular_parameters(¶ms, kwds) + sig_on() + try: + CMR_CALL(CMRtestBinaryRegular(cmr, self._mat, &result, pdec, pminor, + ¶ms, &stats, time_limit)) + finally: + sig_off() + + if not certificate: + return result + + raise NotImplementedError + + +cdef _cmr_dec_construct(param): + if not param: + return CMR_DEC_CONSTRUCT_NONE + if param == 'leaves': + return CMR_DEC_CONSTRUCT_LEAVES + return CMR_DEC_CONSTRUCT_ALL + + +cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMETERS *params, dict kwds): + CMR_CALL(CMRparamsRegularInit(params)) + params.directGraphicness = kwds['use_direct_graphicness_test'] + params.seriesParallel = kwds['series_parallel_ok'] + params.planarityCheck = kwds['check_graphic_minors_planar'] + params.completeTree = kwds['complete_tree'] is True + params.matrices = _cmr_dec_construct(kwds['construct_matrices']) + params.transposes = _cmr_dec_construct(kwds['construct_transposes']) + params.graphs = _cmr_dec_construct(kwds['construct_graphs']) From 3774045af6c18cde3572b4d503e2600def1ba027 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jul 2023 19:45:59 -0700 Subject: [PATCH 014/262] src/sage/matrix/matrix_cmr_sparse.pyx: Add is_totally_unimodular (first version) --- src/sage/matrix/matrix_cmr_sparse.pyx | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 79f4de7de1f..50f5b5e5d7a 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -358,6 +358,57 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): raise NotImplementedError + def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='if_regular', + construct_matrices=False, + construct_transposes=False, + construct_graphs=False): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: M.is_totally_unimodular() + True + + """ + cdef bint result + cdef CMR_TU_PARAMETERS params + cdef CMR_TU_STATISTICS stats + cdef CMR_DEC *dec = NULL + cdef CMR_SUBMAT *submat = NULL + + cdef CMR_DEC **pdec = &dec + cdef CMR_SUBMAT **psubmat = &submat + + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + series_parallel_ok=series_parallel_ok, + check_graphic_minors_planar=check_graphic_minors_planar, + complete_tree=complete_tree, + construct_matrices=construct_matrices, + construct_transposes=construct_transposes, + construct_graphs=construct_graphs) + + _set_cmr_regular_parameters(¶ms.regular, kwds) + sig_on() + try: + CMR_CALL(CMRtestTotalUnimodularity(cmr, self._mat, &result, pdec, psubmat, + ¶ms, &stats, time_limit)) + finally: + sig_off() + + if not certificate: + return result + + raise NotImplementedError + cdef _cmr_dec_construct(param): if not param: From 3e7271c80df52110ed438be6f8439ef605599a91 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 19 Jul 2023 11:34:37 -0700 Subject: [PATCH 015/262] sage.libs.cmr: Add missing files --- src/sage/libs/cmr/__init__.py | 0 src/sage/libs/cmr/cmr.pyx | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/sage/libs/cmr/__init__.py create mode 100644 src/sage/libs/cmr/cmr.pyx diff --git a/src/sage/libs/cmr/__init__.py b/src/sage/libs/cmr/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/libs/cmr/cmr.pyx b/src/sage/libs/cmr/cmr.pyx new file mode 100644 index 00000000000..295746a46ac --- /dev/null +++ b/src/sage/libs/cmr/cmr.pyx @@ -0,0 +1,17 @@ +# -*- python -*- + +cdef CMR *cmr = NULL + + +cdef CMR_CALL(CMR_ERROR _cmr_error): + if _cmr_error == CMR_OKAY: + return + if _cmr_error == CMR_ERROR_INPUT: + raise RuntimeError("User input error") + if _cmr_error == CMR_ERROR_MEMORY: + raise RuntimeError("Memory (re)allocation failed") + if _cmr_error == CMR_ERROR_INVALID: + raise RuntimeError("Invalid input") + if _cmr_error == CMR_ERROR_TIMEOUT: + raise RuntimeError("Time limit exceeded") + raise RuntimeError("Unknown error") From 613c5666c7ead39f083a2b95ff4dafb4f41bd6b7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Feb 2024 09:42:18 -0800 Subject: [PATCH 016/262] build/pkgs/sagelib/dependencies: TEMP: Add cmr --- build/pkgs/sagelib/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagelib/dependencies b/build/pkgs/sagelib/dependencies index b1ebfd0825e..c468418099f 100644 --- a/build/pkgs/sagelib/dependencies +++ b/build/pkgs/sagelib/dependencies @@ -1,4 +1,4 @@ -FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran +FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cmr cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran ---------- All lines of this file are ignored except the first. From 5078766c18f2174d74b79b3f9232aac8721f259a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 20 Jul 2023 11:27:35 -0700 Subject: [PATCH 017/262] sage.libs.cmr, sage.matrix.matrix_cmr_sparse: Fix handling of bool for Linux ABI --- src/sage/libs/cmr/cmr.pxd | 48 +++++++++++++++------------ src/sage/matrix/matrix_cmr_sparse.pxd | 2 +- src/sage/matrix/matrix_cmr_sparse.pyx | 27 +++++++-------- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d29e258a1a4..82e6c2c93b7 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -3,6 +3,10 @@ # (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "" nil (point) (point-max)) (replace-regexp "[;{}]" "" nil (point) (point-max)) (replace-regexp "CMR_EXPORT *" "" nil (point) (point-max)) (replace-regexp "bool" "bint" nil (point) (point-max))) +cdef extern from "stdbool.h": + + ctypedef int bool + cdef extern from "cmr/env.h": int CMR_OKAY int CMR_ERROR_INPUT @@ -51,10 +55,10 @@ cdef extern from "cmr/matrix.h": cdef extern from "cmr/k_modular.h": - CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisUnimodular) - CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisStronglyUnimodular) - CMR_ERROR CMRtestKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisKmodular, size_t* pk) - CMR_ERROR CMRtestStrongKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisStronglyKmodular, size_t* pk) + CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, int* pisUnimodular) + CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisStronglyUnimodular) + CMR_ERROR CMRtestKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisKmodular, size_t* pk) + CMR_ERROR CMRtestStrongKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisStronglyKmodular, size_t* pk) cdef extern from "cmr/camion.h": @@ -64,8 +68,8 @@ cdef extern from "cmr/camion.h": CMR_ERROR CMRstatsCamionInit(CMR_CAMION_STATISTICS* stats) # CMR_ERROR CMRstatsCamionPrint(FILE* stream, CMR_CAMION_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRtestCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bint* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRcomputeCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bint* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcomputeCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bool* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) cdef extern from "cmr/matroid.h": @@ -113,7 +117,7 @@ cdef extern from "cmr/separation.h": unsigned char CMRsepaRankBottomLeft(CMR_SEPA* sepa) unsigned char CMRsepaRankTopRight(CMR_SEPA* sepa) unsigned char CMRsepaRank(CMR_SEPA* sepa) - CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bint* pisTernary, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bool* pisTernary, CMR_SUBMAT** psubmatrix) CMR_ERROR CMRoneSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_CHRMAT** presult) CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, CMR_CHRMAT** presult) CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, CMR_CHRMAT** presult) @@ -189,9 +193,9 @@ cdef extern from "cmr/graphic.h": CMR_ERROR CMRstatsGraphicInit(CMR_GRAPHIC_STATISTICS* stats) # CMR_ERROR CMRstatsGraphicPrint(FILE* stream, CMR_GRAPHIC_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRcomputeGraphicMatrix(CMR* cmr, CMR_GRAPH* graph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, int numForestEdges, CMR_GRAPH_EDGE* forestEdges, int numCoforestEdges, CMR_GRAPH_EDGE* coforestEdges, bint* pisCorrectForest) - CMR_ERROR CMRtestGraphicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisGraphic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestCographicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcomputeGraphicMatrix(CMR* cmr, CMR_GRAPH* graph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, int numForestEdges, CMR_GRAPH_EDGE* forestEdges, int numCoforestEdges, CMR_GRAPH_EDGE* coforestEdges, bool* pisCorrectForest) + CMR_ERROR CMRtestGraphicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisGraphic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestCographicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) CMR_ERROR CMRtestGraphicColumnSubmatrixGreedy(CMR* cmr, CMR_CHRMAT* transpose, size_t* orderedColumns, CMR_SUBMAT** psubmatrix) cdef extern from "cmr/series_parallel.h": @@ -223,10 +227,10 @@ cdef extern from "cmr/series_parallel.h": bint CMRspIsCopy(CMR_SP_REDUCTION reduction) bint CMRspIsValid(CMR_SP_REDUCTION reduction) - CMR_ERROR CMRtestBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRdecomposeBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRdecomposeTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bint* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRdecomposeBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRdecomposeTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) cdef extern from "cmr/network.h": @@ -238,9 +242,9 @@ cdef extern from "cmr/network.h": CMR_ERROR CMRstatsNetworkInit(CMR_NETWORK_STATISTICS* stats) # CMR_ERROR CMRstatsNetworkPrint(FILE* stream, CMR_NETWORK_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRcomputeNetworkMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bint* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bint* pisCorrectForest) - CMR_ERROR CMRtestNetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bint** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestConetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bint* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bint** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcomputeNetworkMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bool* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bool* pisCorrectForest) + CMR_ERROR CMRtestNetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestConetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) cdef extern from "cmr/dec.h": @@ -281,7 +285,7 @@ cdef extern from "cmr/dec.h": CMR_CHRMAT* CMRdecGetTranspose(CMR_DEC* dec) size_t CMRdecNumChildren(CMR_DEC* dec) CMR_DEC* CMRdecChild(CMR_DEC* dec, size_t childIndex) - int CMRdecIsSum(CMR_DEC* dec, bint* plowerLeftNonzeros, bint* pupperRightNonzeros) + int CMRdecIsSum(CMR_DEC* dec, bool* plowerLeftNonzeros, bool* pupperRightNonzeros) CMR_DEC_TYPE CMRdecIsSpecialLeaf(CMR_DEC* dec, int* prepresentationMatrix) bint CMRdecIsGraphicLeaf(CMR_DEC* dec) bint CMRdecIsCographicLeaf(CMR_DEC* dec) @@ -301,11 +305,11 @@ cdef extern from "cmr/dec.h": size_t CMRdecGraphSizeForest(CMR_DEC* dec) CMR_GRAPH_EDGE* CMRdecGraphCoforest(CMR_DEC* dec) size_t CMRdecGraphSizeCoforest(CMR_DEC* dec) - bint* CMRdecGraphArcsReversed(CMR_DEC* dec) + bool* CMRdecGraphArcsReversed(CMR_DEC* dec) CMR_GRAPH* CMRdecCograph(CMR_DEC* dec) CMR_GRAPH_EDGE* CMRdecCographForest(CMR_DEC* dec) CMR_GRAPH_EDGE* CMRdecCographCoforest(CMR_DEC* dec) - bint* CMRdecCographArcsReversed(CMR_DEC* dec) + bool* CMRdecCographArcsReversed(CMR_DEC* dec) cdef extern from "cmr/regular.h": @@ -361,7 +365,7 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRstatsTotalUnimodularityInit(CMR_TU_STATISTICS* stats) # CMR_ERROR CMRstatsTotalUnimodularityPrint(FILE* stream, CMR_TU_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMETERS* params, CMR_TU_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMETERS* params, CMR_TU_STATISTICS* stats, double timeLimit) cdef extern from "cmr/ctu.h": @@ -374,7 +378,7 @@ cdef extern from "cmr/ctu.h": CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATISTICS* stats) # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATISTICS* stats, const char* prefix) CMR_ERROR CMRcomplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) - CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bint* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats) + CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats) # Our global CMR environment diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index ae656c67c33..ee4c7f1197d 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,4 +1,4 @@ -from sage.libs.cmr.cmr cimport * +from sage.libs.cmr.cmr cimport CMR_CHRMAT from .matrix_sparse cimport Matrix_sparse diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 50f5b5e5d7a..4cbcd7ababf 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -6,6 +6,7 @@ from libc.stdint cimport SIZE_MAX from cysignals.signals cimport sig_on, sig_off +from sage.libs.cmr.cmr cimport * from sage.rings.integer cimport Integer from .args cimport MatrixArgs_init @@ -155,7 +156,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_unimodular() False """ - cdef bint result + cdef bool result sig_on() try: @@ -163,10 +164,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): finally: sig_off() - return result + return result def is_strongly_unimodular(self): - cdef bint result + cdef bool result sig_on() try: @@ -174,10 +175,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): finally: sig_off() - return result + return result def modulus(self): - cdef bint result + cdef bool result cdef size_t k sig_on() @@ -192,7 +193,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return None def strong_modulus(self): - cdef bint result + cdef bool result cdef size_t k sig_on() @@ -242,7 +243,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ... RuntimeError: Time limit exceeded """ - cdef bint result + cdef bool result cdef CMR_GRAPH *graph = NULL cdef CMR_GRAPH_EDGE* forest_edges = NULL cdef CMR_GRAPH_EDGE* coforest_edges = NULL @@ -261,7 +262,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() if not certificate: - return result + return result # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend from sage.graphs.graph import Graph @@ -282,7 +283,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): yield edge(e) i = CMRgraphEdgesNext(graph, i) - if result: + if result: sage_graph = Graph([list(vertices()), list(edges())]) sage_forest_edges = tuple(edge(forest_edges[row]) for row in range(self.nrows())) @@ -328,7 +329,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M._is_binary_linear_matroid_regular() True """ - cdef bint result + cdef bool result cdef CMR_REGULAR_PARAMETERS params cdef CMR_REGULAR_STATISTICS stats cdef CMR_DEC *dec = NULL @@ -354,7 +355,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() if not certificate: - return result + return result raise NotImplementedError @@ -379,7 +380,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): True """ - cdef bint result + cdef bool result cdef CMR_TU_PARAMETERS params cdef CMR_TU_STATISTICS stats cdef CMR_DEC *dec = NULL @@ -405,7 +406,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() if not certificate: - return result + return result raise NotImplementedError From 9424d4504df2f439800660dab8e1b6ad369435c7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 20 Jul 2023 11:28:41 -0700 Subject: [PATCH 018/262] src/sage/matrix/seymour_decomposition.pyx: New (draft) --- src/sage/matrix/seymour_decomposition.pyx | 68 +++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/sage/matrix/seymour_decomposition.pyx diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx new file mode 100644 index 00000000000..b0ee217ad62 --- /dev/null +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -0,0 +1,68 @@ +r""" +Seymour's decomposition of totally unimodular matrices and regular matroids +""" + +from sage.structure.sage_object cimport SageObject + + +cdef class DecompositionNode(SageObject): + + def matrix(self): + raise NotImplementedError + + def plot(self): + raise NotImplementedError + + def _repr_(self): + # print it + raise NotImplementedError + + +cdef class SumNode(DecompositionNode): + + def permuted_block_matrix(self): + r"Return (Prow, BlockMatrix, Pcolumn) so that self.matrix() == Prow * BlockMatrix * Pcolumn ????" + raise NotImplementedError + + def summands(self): + raise NotImplementedError + + +cdef class OneSumNode(SumNode): + + pass + + +cdef class BaseGraphicNode(DecompositionNode): + + pass + + +cdef class GraphicNode(BaseGraphicNode): + + def graph(self): + raise NotImplementedError + + +cdef class CographicNode(BaseGraphicNode): + + pass + + +cdef class PlanarNode(BaseGraphicNode): + + pass + + +cdef class LeafNode(DecompositionNode): + + + pass + + +cdef class K33Node(LeafNode): + + def graph(self): + raise NotImplementedError + + pass From c8c95f41cca4fd0af76be7cb43c5ccc5428d8361 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 20 Jul 2023 14:07:55 -0700 Subject: [PATCH 019/262] sage.matrix.seymour_decomposition: a bit more work --- src/sage/libs/cmr/cmr.pxd | 64 +++++++++++------------ src/sage/matrix/matrix_cmr_sparse.pyx | 9 +++- src/sage/matrix/seymour_decomposition.pxd | 13 +++++ src/sage/matrix/seymour_decomposition.pyx | 44 +++++++++++++++- 4 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 src/sage/matrix/seymour_decomposition.pxd diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 82e6c2c93b7..913096badbd 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -8,13 +8,13 @@ cdef extern from "stdbool.h": ctypedef int bool cdef extern from "cmr/env.h": - int CMR_OKAY - int CMR_ERROR_INPUT - int CMR_ERROR_OUTPUT - int CMR_ERROR_MEMORY - int CMR_ERROR_INVALID - int CMR_ERROR_OVERFLOW - int CMR_ERROR_TIMEOUT + const int CMR_OKAY + const int CMR_ERROR_INPUT + const int CMR_ERROR_OUTPUT + const int CMR_ERROR_MEMORY + const int CMR_ERROR_INVALID + const int CMR_ERROR_OVERFLOW + const int CMR_ERROR_TIMEOUT ctypedef int CMR_ERROR @@ -252,31 +252,31 @@ cdef extern from "cmr/dec.h": ctypedef int CMR_DEC_TYPE - int CMR_DEC_IRREGULAR - int CMR_DEC_UNKNOWN - int CMR_DEC_ONE_SUM - int CMR_DEC_TWO_SUM - int CMR_DEC_THREE_SUM - int CMR_DEC_GRAPHIC - int CMR_DEC_COGRAPHIC - int CMR_DEC_PLANAR - int CMR_DEC_SERIES_PARALLEL - int CMR_DEC_SPECIAL_R10 - int CMR_DEC_SPECIAL_FANO - int CMR_DEC_SPECIAL_FANO_DUAL - int CMR_DEC_SPECIAL_K_5 - int CMR_DEC_SPECIAL_K_5_DUAL - int CMR_DEC_SPECIAL_K_3_3 - int CMR_DEC_SPECIAL_K_3_3_DUAL + const int CMR_DEC_IRREGULAR + const int CMR_DEC_UNKNOWN + const int CMR_DEC_ONE_SUM + const int CMR_DEC_TWO_SUM + const int CMR_DEC_THREE_SUM + const int CMR_DEC_GRAPHIC + const int CMR_DEC_COGRAPHIC + const int CMR_DEC_PLANAR + const int CMR_DEC_SERIES_PARALLEL + const int CMR_DEC_SPECIAL_R10 + const int CMR_DEC_SPECIAL_FANO + const int CMR_DEC_SPECIAL_FANO_DUAL + const int CMR_DEC_SPECIAL_K_5 + const int CMR_DEC_SPECIAL_K_5_DUAL + const int CMR_DEC_SPECIAL_K_3_3 + const int CMR_DEC_SPECIAL_K_3_3_DUAL ctypedef int CMR_DEC_FLAGS - int CMR_DEC_MASK_REPRESENTATION - int CMR_DEC_IS_GRAPHIC - int CMR_DEC_IS_COGRAPHIC - int CMR_DEC_IS_REGULAR - int CMR_DEC_HAS_LOWER_LEFT_NONZEROS - int CMR_DEC_HAS_UPPER_RIGHT_NONZEROS + const int CMR_DEC_MASK_REPRESENTATION + const int CMR_DEC_IS_GRAPHIC + const int CMR_DEC_IS_COGRAPHIC + const int CMR_DEC_IS_REGULAR + const int CMR_DEC_HAS_LOWER_LEFT_NONZEROS + const int CMR_DEC_HAS_UPPER_RIGHT_NONZEROS CMR_ERROR CMRdecFree(CMR* cmr, CMR_DEC** pdec) bint CMRdecHasMatrix(CMR_DEC* dec) @@ -316,9 +316,9 @@ cdef extern from "cmr/regular.h": ctypedef int CMR_DEC_CONSTRUCT - int CMR_DEC_CONSTRUCT_NONE - int CMR_DEC_CONSTRUCT_LEAVES - int CMR_DEC_CONSTRUCT_ALL + const int CMR_DEC_CONSTRUCT_NONE + const int CMR_DEC_CONSTRUCT_LEAVES + const int CMR_DEC_CONSTRUCT_ALL ctypedef struct CMR_REGULAR_PARAMETERS: bint directGraphicness diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4cbcd7ababf..a6ae7ca7999 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -7,6 +7,7 @@ from libc.stdint cimport SIZE_MAX from cysignals.signals cimport sig_on, sig_off from sage.libs.cmr.cmr cimport * +from sage.matrix.seymour_decomposition cimport create_DecompositionNode from sage.rings.integer cimport Integer from .args cimport MatrixArgs_init @@ -378,7 +379,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 1] sage: M.is_totally_unimodular() True - + sage: M.is_totally_unimodular(certificate=True) + (True, DecompositionNode with 0 children) """ cdef bool result cdef CMR_TU_PARAMETERS params @@ -408,7 +410,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result - raise NotImplementedError + if result: + return True, create_DecompositionNode(dec) + + return False, NotImplemented cdef _cmr_dec_construct(param): diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd new file mode 100644 index 00000000000..68220eab566 --- /dev/null +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -0,0 +1,13 @@ +from sage.libs.cmr.cmr cimport CMR_DEC +from sage.structure.sage_object cimport SageObject + + +cdef class DecompositionNode(SageObject): + + cdef CMR_DEC *_dec + cdef DecompositionNode _root # my CMR_DEC is owned by this + + cdef _set_dec(self, CMR_DEC *dec, root) + + +cdef create_DecompositionNode(CMR_DEC *dec, root=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b0ee217ad62..43d8a92b6b4 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -2,20 +2,36 @@ r""" Seymour's decomposition of totally unimodular matrices and regular matroids """ +from sage.libs.cmr.cmr cimport * +from sage.misc.cachefunc import cached_method from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): + cdef _set_dec(self, CMR_DEC *dec, root): + if self._root is None: + CMR_CALL(CMRdecFree(cmr, &self._dec)) + self._dec = dec + self._root = root + + def __dealloc__(self): + self._set_dec(NULL, None) + def matrix(self): raise NotImplementedError def plot(self): raise NotImplementedError + @cached_method + def _children(self): + return tuple(create_DecompositionNode(CMRdecChild(self._dec, index), + self._root or self) + for index in range(CMRdecNumChildren(self._dec))) + def _repr_(self): - # print it - raise NotImplementedError + return f'{self.__class__.__name__} with {len(self._children())} children' cdef class SumNode(DecompositionNode): @@ -66,3 +82,27 @@ cdef class K33Node(LeafNode): raise NotImplementedError pass + + +cdef _class(CMR_DEC *dec): + k = CMRdecIsSum(dec, NULL, NULL) + if k == 1: + return OneSumNode + # More TBD + return DecompositionNode + + +cdef create_DecompositionNode(CMR_DEC *dec, root=None): + r""" + Create an instance of a subclass of :class:`DecompositionNode`. + + INPUT: + + - ``dec`` -- a ``CMR_DEC`` + - ``root`` -- a :class:`DecompositionNode` or ``None``. + If ``None``, ``dec`` will be owned by the returned instance. + If non-``None``, ``dec`` is owned by that instance. + """ + cdef DecompositionNode result = _class(dec)() + result._set_dec(dec, root) + return result From c74952560650dd4a25fc6250d6941c768c37b330 Mon Sep 17 00:00:00 2001 From: xuluze <113661384+xuluze@users.noreply.github.com> Date: Fri, 21 Jul 2023 09:05:35 -0700 Subject: [PATCH 020/262] Add example for `is_strongly_unimodular` (#5) add_examples_is_strongly_unimodular --- src/sage/matrix/matrix_cmr_sparse.pyx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index a6ae7ca7999..9ba6d1b5a05 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -168,6 +168,28 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result def is_strongly_unimodular(self): + r""" + A matrix is strongly unimodular if ``self`` and ``self.transpose()`` are both unimodular. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M + [1 0 1] + [0 1 1] + [1 2 3] + sage: M.is_unimodular() + True + sage: M.is_strongly_unimodular() + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 0, 0], [0, 1, 0]]); M + [1 0 0] + [0 1 0] + sage: M.is_strongly_unimodular() + True + """ cdef bool result sig_on() @@ -295,7 +317,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, None # submatrix TBD def is_cographic(self, *, time_limit=60.0, certificate=False): - raise NotImplementedError + raise NotImplementedError def is_network_matrix(self, *, time_limit=60.0, certificate=False): raise NotImplementedError From b16437eab77c1d671025619dcdb83c30af7b42ff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 22 Jul 2023 13:52:24 -0700 Subject: [PATCH 021/262] sage.matrix.seymour_decomposition: Add methods matrix, parent_rows_and_columns --- src/sage/matrix/seymour_decomposition.pyx | 72 ++++++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 43d8a92b6b4..ddd0fcd09a0 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -4,8 +4,12 @@ Seymour's decomposition of totally unimodular matrices and regular matroids from sage.libs.cmr.cmr cimport * from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse +from .matrix_space import MatrixSpace + cdef class DecompositionNode(SageObject): @@ -18,8 +22,69 @@ cdef class DecompositionNode(SageObject): def __dealloc__(self): self._set_dec(NULL, None) + @cached_method def matrix(self): - raise NotImplementedError + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, DecompositionNode with 0 children) + sage: certificate.matrix() is None + True + + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: construct_matrices=True) + sage: result, certificate + (True, DecompositionNode with 0 children) + sage: certificate.matrix() + [ 1 0] + [-1 1] + [ 0 1] + """ + cdef Matrix_cmr_chr_sparse result + cdef CMR_CHRMAT *mat = CMRdecGetMatrix(self._dec) + if mat == NULL: + return None + ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) + result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms) + result._mat = mat + result._root = self._root + return result + + def parent_rows_and_columns(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: certificate.parent_rows_and_columns() + (None, None) + """ + + cdef size_t *parent_rows = CMRdecRowsParent(self._dec) + cdef size_t *parent_columns = CMRdecColumnsParent(self._dec) + if parent_rows == NULL: + parent_rows_tuple = None + else: + parent_rows_tuple = tuple(parent_rows[i] for i in range(CMRdecNumRows(self._dec))) + if parent_columns == NULL: + parent_columns_tuple = None + else: + parent_columns_tuple = tuple(parent_columns[i] for i in range(CMRdecNumColumns(self._dec))) + + return parent_rows_tuple, parent_columns_tuple def plot(self): raise NotImplementedError @@ -40,8 +105,7 @@ cdef class SumNode(DecompositionNode): r"Return (Prow, BlockMatrix, Pcolumn) so that self.matrix() == Prow * BlockMatrix * Pcolumn ????" raise NotImplementedError - def summands(self): - raise NotImplementedError + summands = DecompositionNode._children cdef class OneSumNode(SumNode): @@ -103,6 +167,8 @@ cdef create_DecompositionNode(CMR_DEC *dec, root=None): If ``None``, ``dec`` will be owned by the returned instance. If non-``None``, ``dec`` is owned by that instance. """ + if dec == NULL: + return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) return result From 8e73911101342ede64efc94b3c87bfb5d59c9206 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 22 Jul 2023 13:53:12 -0700 Subject: [PATCH 022/262] sage.matrix.matrix_cmr_sparse: Certificate for non-TU --- src/sage/matrix/matrix_cmr_sparse.pxd | 1 + src/sage/matrix/matrix_cmr_sparse.pyx | 46 +++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index ee4c7f1197d..4c37669d7a8 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -14,5 +14,6 @@ cdef class Matrix_cmr_sparse(Matrix_sparse): cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef CMR_CHRMAT *_mat + cdef object _root cdef _init_from_dict(self, dict d, int nrows, int ncols) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 9ba6d1b5a05..5c4e1f09aba 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -11,6 +11,7 @@ from sage.matrix.seymour_decomposition cimport create_DecompositionNode from sage.rings.integer cimport Integer from .args cimport MatrixArgs_init +from .seymour_decomposition cimport create_DecompositionNode cdef class Matrix_cmr_sparse(Matrix_sparse): @@ -122,7 +123,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return self def __dealloc__(self): - CMRchrmatFree(cmr, &self._mat) + if self._root is not None: + # We own it, so we have to free it. + CMRchrmatFree(cmr, &self._mat) def _test_change_ring(self, **options): return @@ -403,6 +406,38 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): True sage: M.is_totally_unimodular(certificate=True) (True, DecompositionNode with 0 children) + + sage: MF = matroids.named_matroids.Fano(); MF + Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) + sage: MFR = MF.representation().change_ring(ZZ); MFR + [1 0 0 0 1 1 1] + [0 1 0 1 0 1 1] + [0 0 1 1 1 0 1] + sage: MFR2 = block_diagonal_matrix(MFR, MFR, sparse=True); MFR2 + [1 0 0 0 1 1 1|0 0 0 0 0 0 0] + [0 1 0 1 0 1 1|0 0 0 0 0 0 0] + [0 0 1 1 1 0 1|0 0 0 0 0 0 0] + [-------------+-------------] + [0 0 0 0 0 0 0|1 0 0 0 1 1 1] + [0 0 0 0 0 0 0|0 1 0 1 0 1 1] + [0 0 0 0 0 0 0|0 0 1 1 1 0 1] + sage: MS2 = MFR2.parent(); MS2 + Full MatrixSpace of 6 by 14 sparse matrices over Integer Ring + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: MFR2cmr = Matrix_cmr_chr_sparse(MS2, MFR2) + sage: MFR2cmr.is_totally_unimodular(certificate=True, construct_matrices=True) + (False, (None, ((0, 1, 2), (3, 4, 5)))) + sage: result, certificate = MFR2cmr.is_totally_unimodular(certificate=True, + ....: complete_tree=True, + ....: construct_matrices=True) + sage: result, certificate + (False, (None, ((0, 1, 2), (3, 4, 5)))) + sage: submatrix = MFR2.matrix_from_rows_and_columns(*certificate[1]); submatrix + [0 1 1] + [1 0 1] + [1 1 0] + sage: submatrix.determinant() + 2 """ cdef bool result cdef CMR_TU_PARAMETERS params @@ -435,7 +470,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: return True, create_DecompositionNode(dec) - return False, NotImplemented + if submat == NULL: + submat_tuple = None + else: + submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), + tuple(submat.columns[i] for i in range(submat.numColumns))) + + return False, (create_DecompositionNode(dec), + submat_tuple) cdef _cmr_dec_construct(param): From 2da94c603cfeb6fa4a85d5a24e435ede72868801 Mon Sep 17 00:00:00 2001 From: xuluze <113661384+xuluze@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:00:57 -0700 Subject: [PATCH 023/262] Add examples for is_k_modular, is_strongly_k_modular (#7) --- src/sage/matrix/matrix_cmr_sparse.pyx | 110 +++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 5c4e1f09aba..bb3b34b658c 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -204,6 +204,32 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result def modulus(self): + r""" + A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. + + OUTPUT: + + - ``k``: ``self`` is `k`-modular + - ``None``: ``self`` is not `k`-modular for any `k` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M + [1 0 1] + [0 1 1] + [1 2 3] + sage: M.modulus() + 1 + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 1, 1], [0, 1, 3]]); M + [1 1 1] + [0 1 3] + sage: M.modulus() + """ cdef bool result cdef size_t k @@ -219,6 +245,32 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return None def strong_modulus(self): + r""" + A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. + + OUTPUT: + + - ``k``: ``self`` is `k`-modular + - ``None``: ``self`` is not `k`-modular for any `k` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M + [1 0 1] + [0 1 1] + [1 2 3] + sage: M.strong_modulus() + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 0, 0], [0, 1, 0]]); M + [1 0 0] + [0 1 0] + sage: M.strong_modulus() + 1 + """ cdef bool result cdef size_t k @@ -234,10 +286,64 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return None def is_k_modular(self, k): - return self.modulus() <= k + r""" + A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. + If the matrix has full row rank, it is `k`-modular if all the full rank minor of the matrix has determinant `0,\pm k`. + The matrix is also called strictly `k`-modular. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M + [1 0 1] + [0 1 1] + [1 2 3] + sage: M.is_k_modular(1) + True + sage: M.is_k_modular(2) + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 1, 1], [0, 1, 3]]); M + [1 1 1] + [0 1 3] + sage: M.is_k_modular(1) + False + """ + result = self.modulus() + if not result: + return False + else: + return result == k def is_strongly_k_modular(self, k): - return self.strong_modulus() <= k + r""" + A matrix is strongly k-modular if ``self`` and ``self.transpose()`` are both k-modular. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M + [1 0 1] + [0 1 1] + [1 2 3] + sage: M.is_strongly_k_modular(1) + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 0, 0], [0, 1, 0]]); M + [1 0 0] + [0 1 0] + sage: M.is_strongly_k_modular(1) + True + """ + result = self.strong_modulus() + if not result: + return False + else: + return result == k def is_graphic(self, *, time_limit=60.0, certificate=False): r""" From 1c1baea6d4a8654e6be41bf417724f75b48fdb76 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 22 Jul 2023 15:01:10 -0700 Subject: [PATCH 024/262] Matrix_integer_dense.is_unimodular: New --- src/sage/matrix/matrix_integer_dense.pyx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index b6a832c38d9..7bd43b89a6b 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -3297,6 +3297,28 @@ cdef class Matrix_integer_dense(Matrix_dense): else: return R + def is_unimodular(self): + r""" + EXAMPLES:: + + sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]]); M + [1 0 0] + [0 1 0] + sage: M.is_unimodular() + True + sage: M = matrix(ZZ, [[1, 1, 0], [-1, 1, 1]]); M + [ 1 1 0] + [-1 1 1] + sage: M.is_unimodular() + False + """ + from .matrix_cmr_sparse import Matrix_cmr_chr_sparse + from .matrix_space import MatrixSpace + + MS = MatrixSpace(ZZ, self.nrows(), self.ncols(), sparse=True) + M = Matrix_cmr_chr_sparse(MS, self) + return M.is_unimodular() + def is_LLL_reduced(self, delta=None, eta=None): r""" Return ``True`` if this lattice is `(\delta, \eta)`-LLL reduced. From 12f1f02c2ddc87aef211c144e578e3768fa166ee Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 00:52:05 -0700 Subject: [PATCH 025/262] sage.matrix.seymour_decomposition: Add BaseGraphicNode.graph --- src/sage/matrix/matrix_cmr_sparse.pxd | 4 +- src/sage/matrix/matrix_cmr_sparse.pyx | 58 ++++++++++++++--------- src/sage/matrix/seymour_decomposition.pyx | 54 ++++++++++++++++++--- 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index 4c37669d7a8..b8fabcf131c 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,4 +1,4 @@ -from sage.libs.cmr.cmr cimport CMR_CHRMAT +from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH from .matrix_sparse cimport Matrix_sparse @@ -17,3 +17,5 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef object _root cdef _init_from_dict(self, dict d, int nrows, int ncols) + +cdef _sage_graph(CMR_GRAPH *graph) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index bb3b34b658c..390df67a6d4 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -396,30 +396,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result - # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend - from sage.graphs.graph import Graph - - def vertices(): - i = CMRgraphNodesFirst(graph) - while CMRgraphNodesValid(graph, i): - yield i - i = CMRgraphNodesNext(graph, i) - - def edge(e): - return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) - - def edges(): - i = CMRgraphEdgesFirst(graph) - while CMRgraphEdgesValid(graph, i): - e = CMRgraphEdgesEdge(graph, i) - yield edge(e) - i = CMRgraphEdgesNext(graph, i) - if result: - sage_graph = Graph([list(vertices()), list(edges())]) - sage_forest_edges = tuple(edge(forest_edges[row]) + sage_graph = _sage_graph(graph) + sage_forest_edges = tuple(edge(graph, forest_edges[row]) for row in range(self.nrows())) - sage_coforest_edges = tuple(edge(coforest_edges[column]) + sage_coforest_edges = tuple(edge(graph, coforest_edges[column]) for column in range(self.ncols())) return True, (sage_graph, sage_forest_edges, sage_coforest_edges) @@ -585,6 +566,16 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, (create_DecompositionNode(dec), submat_tuple) + def is_complement_totally_unimodular(self, *, time_limit=60.0, certificate=False, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='if_regular', + construct_matrices=False, + construct_transposes=False, + construct_graphs=False): + raise NotImplementedError + cdef _cmr_dec_construct(param): if not param: @@ -603,3 +594,26 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMETERS *params, dict kwds): params.matrices = _cmr_dec_construct(kwds['construct_matrices']) params.transposes = _cmr_dec_construct(kwds['construct_transposes']) params.graphs = _cmr_dec_construct(kwds['construct_graphs']) + + +cdef edge(CMR_GRAPH *graph, e): + return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) + +cdef _sage_graph(CMR_GRAPH *graph): + # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend + from sage.graphs.graph import Graph + + def vertices(): + i = CMRgraphNodesFirst(graph) + while CMRgraphNodesValid(graph, i): + yield i + i = CMRgraphNodesNext(graph, i) + + def edges(): + i = CMRgraphEdgesFirst(graph) + while CMRgraphEdgesValid(graph, i): + e = CMRgraphEdgesEdge(graph, i) + yield edge(graph, e) + i = CMRgraphEdgesNext(graph, i) + + return Graph([list(vertices()), list(edges())]) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ddd0fcd09a0..900df6e2aa4 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -7,7 +7,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject -from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_graph from .matrix_space import MatrixSpace @@ -35,14 +35,14 @@ cdef class DecompositionNode(SageObject): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, DecompositionNode with 0 children) + (True, GraphicNode with 0 children) sage: certificate.matrix() is None True sage: result, certificate = M.is_totally_unimodular(certificate=True, ....: construct_matrices=True) sage: result, certificate - (True, DecompositionNode with 0 children) + (True, GraphicNode with 0 children) sage: certificate.matrix() [ 1 0] [-1 1] @@ -113,15 +113,45 @@ cdef class OneSumNode(SumNode): pass -cdef class BaseGraphicNode(DecompositionNode): +cdef class TwoSumNode(SumNode): pass -cdef class GraphicNode(BaseGraphicNode): +cdef class ThreeSumNode(SumNode): + + pass + + +cdef class BaseGraphicNode(DecompositionNode): + @cached_method def graph(self): - raise NotImplementedError + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode with 0 children) + sage: G = certificate.graph(); G + Graph on 4 vertices + sage: G.vertices(sort=True) + [1, 2, 7, 12] + sage: G.edges(sort=True) + [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] + """ + return _sage_graph(CMRdecGraph(self._dec)) + + +cdef class GraphicNode(BaseGraphicNode): + + pass cdef class CographicNode(BaseGraphicNode): @@ -134,7 +164,7 @@ cdef class PlanarNode(BaseGraphicNode): pass -cdef class LeafNode(DecompositionNode): +cdef class SpecialLeafNode(DecompositionNode): pass @@ -152,6 +182,16 @@ cdef _class(CMR_DEC *dec): k = CMRdecIsSum(dec, NULL, NULL) if k == 1: return OneSumNode + if k == 2: + return TwoSumNode + if k == 3: + return ThreeSumNode + if CMRdecIsGraphicLeaf(dec): + if CMRdecIsCographicLeaf(dec): + return PlanarNode + return GraphicNode + if CMRdecIsCographicLeaf(dec): + return CographicNode # More TBD return DecompositionNode From e3c2e0ae8792cc82722197c96112271a59637036 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 01:23:09 -0700 Subject: [PATCH 026/262] sage.matrix.seymour_decomposition: Add BaseGraphicNode.forest_edges --- src/sage/matrix/matrix_cmr_sparse.pxd | 3 ++- src/sage/matrix/matrix_cmr_sparse.pyx | 9 ++++--- src/sage/matrix/seymour_decomposition.pyx | 33 +++++++++++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index b8fabcf131c..e34dad546f9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,4 +1,4 @@ -from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH +from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH, CMR_GRAPH_EDGE from .matrix_sparse cimport Matrix_sparse @@ -18,4 +18,5 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _init_from_dict(self, dict d, int nrows, int ncols) +cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_graph(CMR_GRAPH *graph) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 390df67a6d4..7b4ca2a8b88 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -398,9 +398,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_graph = _sage_graph(graph) - sage_forest_edges = tuple(edge(graph, forest_edges[row]) + sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) for row in range(self.nrows())) - sage_coforest_edges = tuple(edge(graph, coforest_edges[column]) + sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) for column in range(self.ncols())) return True, (sage_graph, sage_forest_edges, sage_coforest_edges) @@ -596,9 +596,10 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMETERS *params, dict kwds): params.graphs = _cmr_dec_construct(kwds['construct_graphs']) -cdef edge(CMR_GRAPH *graph, e): +cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e): return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) + cdef _sage_graph(CMR_GRAPH *graph): # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend from sage.graphs.graph import Graph @@ -613,7 +614,7 @@ cdef _sage_graph(CMR_GRAPH *graph): i = CMRgraphEdgesFirst(graph) while CMRgraphEdgesValid(graph, i): e = CMRgraphEdgesEdge(graph, i) - yield edge(graph, e) + yield _sage_edge(graph, e) i = CMRgraphEdgesNext(graph, i) return Graph([list(vertices()), list(edges())]) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 900df6e2aa4..7c8597024f8 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -7,7 +7,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject -from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_graph +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edge, _sage_graph from .matrix_space import MatrixSpace @@ -148,6 +148,35 @@ cdef class BaseGraphicNode(DecompositionNode): """ return _sage_graph(CMRdecGraph(self._dec)) + @cached_method + def forest_edges(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode with 0 children) + sage: certificate.forest_edges() + ((1, 2), (7, 1)) + """ + cdef CMR_GRAPH *graph = CMRdecGraph(self._dec) + cdef size_t num_edges = CMRdecGraphSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRdecGraphForest(self._dec) + return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + + @cached_method + def coforest_edges(self): + cdef CMR_GRAPH *graph = CMRdecGraph(self._dec) + cdef size_t num_edges = CMRdecGraphSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRdecGraphCoforest(self._dec) + return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + cdef class GraphicNode(BaseGraphicNode): @@ -164,7 +193,7 @@ cdef class PlanarNode(BaseGraphicNode): pass -cdef class SpecialLeafNode(DecompositionNode): +cdef class LeafNode(DecompositionNode): pass From 3bf35c923166a362696a98d8d2561ffbe3bb0bf5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 11:18:44 -0700 Subject: [PATCH 027/262] sage.matrix.seymour_decomposition: Add as_ordered_tree, _ascii_art_, _unicode_art_, plot --- src/sage/matrix/seymour_decomposition.pyx | 67 ++++++++++++++++++++--- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 7c8597024f8..84760a3af8b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -22,6 +22,9 @@ cdef class DecompositionNode(SageObject): def __dealloc__(self): self._set_dec(NULL, None) + def __hash__(self): + return self._dec + @cached_method def matrix(self): r""" @@ -35,14 +38,14 @@ cdef class DecompositionNode(SageObject): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode with 0 children) + (True, GraphicNode) sage: certificate.matrix() is None True sage: result, certificate = M.is_totally_unimodular(certificate=True, ....: construct_matrices=True) sage: result, certificate - (True, GraphicNode with 0 children) + (True, GraphicNode) sage: certificate.matrix() [ 1 0] [-1 1] @@ -86,8 +89,48 @@ cdef class DecompositionNode(SageObject): return parent_rows_tuple, parent_columns_tuple - def plot(self): - raise NotImplementedError + def as_ordered_tree(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) + sage: M2 = block_diagonal_matrix([M, M], sparse=True) + sage: M2cmr = Matrix_cmr_chr_sparse(M2.parent(), M2); M2cmr + [ 1 0 0 0] + [-1 1 0 0] + [ 0 1 0 0] + [ 0 0 1 0] + [ 0 0 -1 1] + [ 0 0 0 1] + sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, + ....: construct_matrices=True) + sage: T = certificate.as_ordered_tree(); T + OneSumNode with 2 children[GraphicNode[], GraphicNode[]] + sage: unicode_art(T) + ╭─────OneSumNode with 2 children + │ │ + GraphicNode GraphicNode + """ + from sage.combinat.ordered_tree import LabelledOrderedTree + return LabelledOrderedTree([child.as_ordered_tree() for child in self._children()], + label=self) + + def plot(self, **kwds): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) + sage: M2MT = block_diagonal_matrix([M, M, M.T], sparse=True) + sage: M2MTcmr = Matrix_cmr_chr_sparse(M2MT.parent(), M2MT) + sage: result, certificate = M2MTcmr.is_totally_unimodular(certificate=True, + ....: construct_matrices=True) + sage: T = certificate.as_ordered_tree() + sage: T.plot() # needs sage.plot + Graphics object consisting of 8 graphics primitives + """ + return self.as_ordered_tree().plot(**kwds) @cached_method def _children(self): @@ -96,7 +139,17 @@ cdef class DecompositionNode(SageObject): for index in range(CMRdecNumChildren(self._dec))) def _repr_(self): - return f'{self.__class__.__name__} with {len(self._children())} children' + result = f'{self.__class__.__name__}' + children = self._children() + if children: + result += f' with {len(children)} children' + return result + + def _unicode_art_(self): + return self.as_ordered_tree()._unicode_art_() + + def _ascii_art_(self): + return self.as_ordered_tree()._ascii_art_() cdef class SumNode(DecompositionNode): @@ -138,7 +191,7 @@ cdef class BaseGraphicNode(DecompositionNode): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode with 0 children) + (True, GraphicNode) sage: G = certificate.graph(); G Graph on 4 vertices sage: G.vertices(sort=True) @@ -161,7 +214,7 @@ cdef class BaseGraphicNode(DecompositionNode): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode with 0 children) + (True, GraphicNode) sage: certificate.forest_edges() ((1, 2), (7, 1)) """ From ab75441e87fff0da90c270f80b2a3c9e28f01da0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 12:37:05 -0700 Subject: [PATCH 028/262] Matrix_cmr_chr_sparse._is_binary_linear_matroid_regular: Handle certificate=True --- src/sage/matrix/matrix_cmr_sparse.pyx | 47 +++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 7b4ca2a8b88..43140b952e9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -441,6 +441,45 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 1] sage: M._is_binary_linear_matroid_regular() True + + sage: MF = matroids.named_matroids.Fano(); MF + Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) + sage: MFR = MF.representation().change_ring(ZZ); MFR + [1 0 0 0 1 1 1] + [0 1 0 1 0 1 1] + [0 0 1 1 1 0 1] + sage: MFR2 = block_diagonal_matrix(MFR, MFR, sparse=True); MFR2 + [1 0 0 0 1 1 1|0 0 0 0 0 0 0] + [0 1 0 1 0 1 1|0 0 0 0 0 0 0] + [0 0 1 1 1 0 1|0 0 0 0 0 0 0] + [-------------+-------------] + [0 0 0 0 0 0 0|1 0 0 0 1 1 1] + [0 0 0 0 0 0 0|0 1 0 1 0 1 1] + [0 0 0 0 0 0 0|0 0 1 1 1 0 1] + sage: MS2 = MFR2.parent(); MS2 + Full MatrixSpace of 6 by 14 sparse matrices over Integer Ring + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: MFR2cmr = Matrix_cmr_chr_sparse(MS2, MFR2) + sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( + ....: certificate=True) + sage: result, certificate + (False, (OneSumNode with 2 children, NotImplemented)) + sage: unicode_art(certificate[0]) + ╭────────────────OneSumNode with 2 children + │ │ + SeriesParallelNode DecompositionNode + │ + DecompositionNode + sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=True) + sage: result, certificate + (False, (OneSumNode with 2 children, NotImplemented)) + sage: unicode_art(certificate[0]) + ╭────────────────OneSumNode with 2 children + │ │ + SeriesParallelNode SeriesParallelNode + │ │ + DecompositionNode DecompositionNode """ cdef bool result cdef CMR_REGULAR_PARAMETERS params @@ -470,7 +509,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result - raise NotImplementedError + if result: + return True, create_DecompositionNode(dec) + + return False, (create_DecompositionNode(dec), + NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, @@ -492,7 +535,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_totally_unimodular() True sage: M.is_totally_unimodular(certificate=True) - (True, DecompositionNode with 0 children) + (True, GraphicNode) sage: MF = matroids.named_matroids.Fano(); MF Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) From daad900589aa2c77014145bcc7bbe130cd63b3f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 12:38:05 -0700 Subject: [PATCH 029/262] sage.matrix.seymour_decomposition: Add more classes, SpecialLeafNode.matroid() --- src/sage/matrix/seymour_decomposition.pyx | 56 ++++++++++++++++++----- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 84760a3af8b..231a46a078e 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -139,11 +139,7 @@ cdef class DecompositionNode(SageObject): for index in range(CMRdecNumChildren(self._dec))) def _repr_(self): - result = f'{self.__class__.__name__}' - children = self._children() - if children: - result += f' with {len(children)} children' - return result + return f'{self.__class__.__name__}' def _unicode_art_(self): return self.as_ordered_tree()._unicode_art_() @@ -154,6 +150,12 @@ cdef class DecompositionNode(SageObject): cdef class SumNode(DecompositionNode): + def _repr_(self): + result = super()._repr_() + children = self._children() + result += f' with {len(children)} children' + return result + def permuted_block_matrix(self): r"Return (Prow, BlockMatrix, Pcolumn) so that self.matrix() == Prow * BlockMatrix * Pcolumn ????" raise NotImplementedError @@ -246,18 +248,44 @@ cdef class PlanarNode(BaseGraphicNode): pass -cdef class LeafNode(DecompositionNode): - +cdef class SeriesParallelNode(DecompositionNode): pass -cdef class K33Node(LeafNode): +cdef class SpecialLeafNode(DecompositionNode): - def graph(self): - raise NotImplementedError + @cached_method + def matroid(self): + r""" - pass + """ + cdef int representation_matrix + cdef CMR_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + import sage.matroids.matroids_catalog as matroids + from sage.graphs.graph_generators import graphs + from sage.matroids.matroid import Matroid + + if typ == CMR_DEC_SPECIAL_R10: + return matroids.named_matroids.R10() + if typ == CMR_DEC_SPECIAL_FANO: + return matroids.named_matroids.Fano() + if typ == CMR_DEC_SPECIAL_FANO_DUAL: + return matroids.named_matroids.Fano().dual() + if typ == CMR_DEC_SPECIAL_K_5: + return matroids.CompleteGraphic(5) + if typ == CMR_DEC_SPECIAL_K_5_DUAL: + return matroids.CompleteGraphic(5).dual() + if typ == CMR_DEC_SPECIAL_K_3_3: + E = 'abcdefghi' + G = graphs.CompleteBipartiteGraph(3, 3) + return Matroid(groundset=E, graph=G, regular=True) + if typ == CMR_DEC_SPECIAL_K_3_3_DUAL: + return matroids.named_matroids.K33dual() + assert False, 'special leaf node with unknown type' + + def _repr_(self): + return f'Minor isomorphic to {self._matroid()}' cdef _class(CMR_DEC *dec): @@ -274,7 +302,11 @@ cdef _class(CMR_DEC *dec): return GraphicNode if CMRdecIsCographicLeaf(dec): return CographicNode - # More TBD + if CMRdecIsSpecialLeaf(dec, NULL): + return SpecialLeafNode + if CMRdecNumChildren(dec) == 1: + return SeriesParallelNode + assert CMRdecNumChildren(dec) == 0 return DecompositionNode From faf617266bd23fc624addab333d538e5991a40fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 16:51:26 -0700 Subject: [PATCH 030/262] sage.matrix.matrix_cmr_sparse: Add example --- src/sage/matrix/matrix_cmr_sparse.pyx | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 43140b952e9..1a9d12c628f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -480,6 +480,40 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): SeriesParallelNode SeriesParallelNode │ │ DecompositionNode DecompositionNode + + TESTS: + + This is test ``NestedMinorPivotsTwoSeparation`` in CMR's ``test_regular.cpp``:: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 11, 11, sparse=True), + ....: [[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], + ....: [0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + ....: [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + ....: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=True) + sage: result, certificate + (True, GraphicNode) + sage: unicode_art(certificate) + GraphicNode + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=True, + ....: use_direct_graphicness_test=False) + sage: result, certificate + (True, TwoSumNode with 2 children) + sage: unicode_art(certificate) + ╭─────TwoSumNode with 2 children + │ │ + GraphicNode SeriesParallelNode + │ + GraphicNode """ cdef bool result cdef CMR_REGULAR_PARAMETERS params From d47103eafa34419cab8883ada31e9d76249061d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 19:26:51 -0700 Subject: [PATCH 031/262] sage.matrix.matrix_cmr_sparse: Add one_sum --- src/sage/matrix/matrix_cmr_sparse.pxd | 5 +- src/sage/matrix/matrix_cmr_sparse.pyx | 73 +++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index e34dad546f9..6f4ce1fe2ab 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -16,7 +16,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef CMR_CHRMAT *_mat cdef object _root - cdef _init_from_dict(self, dict d, int nrows, int ncols) + cdef _init_from_dict(self, dict d, int nrows, int ncols, bint immutable=?) + + @staticmethod + cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?) cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_graph(CMR_GRAPH *graph) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1a9d12c628f..7d600900833 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -7,10 +7,13 @@ from libc.stdint cimport SIZE_MAX from cysignals.signals cimport sig_on, sig_off from sage.libs.cmr.cmr cimport * -from sage.matrix.seymour_decomposition cimport create_DecompositionNode from sage.rings.integer cimport Integer +from sage.rings.integer_ring import ZZ +from sage.structure.element cimport Matrix from .args cimport MatrixArgs_init +from .constructor import matrix +from .matrix_space import MatrixSpace from .seymour_decomposition cimport create_DecompositionNode @@ -59,7 +62,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [100 200 300] [400 0 600] """ - def __init__(self, parent, entries=None, copy=None, bint coerce=True): + def __init__(self, parent, entries=None, copy=None, bint coerce=True, immutable=True): r""" TESTS:: @@ -73,9 +76,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef dict d ma = MatrixArgs_init(parent, entries) d = ma.dict(coerce) - self._init_from_dict(d, ma.nrows, ma.ncols) + self._init_from_dict(d, ma.nrows, ma.ncols, immutable=True) - cdef _init_from_dict(self, dict d, int nrows, int ncols): + cdef _init_from_dict(self, dict d, int nrows, int ncols, bint immutable=True): if cmr == NULL: CMRcreateEnvironment(&cmr) CMR_CALL(CMRchrmatCreate(cmr, &self._mat, nrows, ncols, len(d))) @@ -96,7 +99,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): self._mat.rowSlice[row + 1] = self._mat.rowSlice[row] self._mat.rowSlice[0] = 0 CMR_CALL(CMRchrmatSortNonzeros(cmr, self._mat)) - self.set_immutable() + if immutable: + self.set_immutable() cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): cdef size_t index @@ -142,6 +146,65 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): # CMR-specific methods. Other classes that want to provide these methods should create # a copy of themselves as an instance of this class and delegate to it. + @staticmethod + def _from_data(data, immutable=True): + if not isinstance(data, Matrix): + data = matrix(ZZ, data, sparse=True) + if not isinstance(data, Matrix_cmr_chr_sparse): + data = Matrix_cmr_chr_sparse(data.parent(), data, immutable=immutable) + return data + + @staticmethod + cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=False): + cdef Matrix_cmr_chr_sparse result + ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) + result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms, immutable=immutable) + result._mat = mat + result._root = None + return result + + @staticmethod + def one_sum(*summands): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1, 1], [-1, 0]]) + sage: unicode_art(M) + ⎛ 1 0│ 0 0⎞ + ⎜-1 1│ 0 0⎟ + ⎜─────┼─────⎟ + ⎜ 0 0│ 1 1⎟ + ⎝ 0 0│-1 0⎠ + """ + cdef Matrix_cmr_chr_sparse sum, summand + cdef CMR_CHRMAT *sum_mat + summands = iter(summands) + try: + first = next(summands) + except StopIteration: + return Matrix_cmr_chr_sparse._from_data({}) + sum = Matrix_cmr_chr_sparse._from_data(first, immutable=False) + sum_mat = sum._mat + row_subdivision = [] + column_subdivision = [] + for s in summands: + row_subdivision.append(sum_mat.numRows) + column_subdivision.append(sum_mat.numColumns) + summand = Matrix_cmr_chr_sparse._from_data(s) + CMR_CALL(CMRoneSum(cmr, sum_mat, summand._mat, &sum_mat)) + if sum_mat != sum._mat: + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) + sum.subdivide(row_subdivision, column_subdivision) + sum.set_immutable() + return sum + + def two_sum(self, other): + raise NotImplementedError + + def three_sum(self, other): + raise NotImplementedError + def is_unimodular(self): r""" EXAMPLES:: From 324c60a5e87e0efb1399d7b082ec00047c69b95d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 23 Jul 2023 21:30:36 -0700 Subject: [PATCH 032/262] sage.matrix.matrix_cmr_sparse: Fixup, more tests for one_sum --- src/sage/matrix/matrix_cmr_sparse.pyx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 7d600900833..b4cf8f78ff0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -176,6 +176,19 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ⎜─────┼─────⎟ ⎜ 0 0│ 1 1⎟ ⎝ 0 0│-1 0⎠ + + TESTS:: + + sage: M = Matrix_cmr_chr_sparse.one_sum(); M + [] + sage: M.parent() + Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring + + sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]]); unicode_art(M) + ⎛ 1 0⎞ + ⎝-1 1⎠ + sage: M.parent() + Full MatrixSpace of 2 by 2 sparse matrices over Integer Ring """ cdef Matrix_cmr_chr_sparse sum, summand cdef CMR_CHRMAT *sum_mat @@ -195,14 +208,15 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRoneSum(cmr, sum_mat, summand._mat, &sum_mat)) if sum_mat != sum._mat: sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) - sum.subdivide(row_subdivision, column_subdivision) + if row_subdivision or column_subdivision: + sum.subdivide(row_subdivision, column_subdivision) sum.set_immutable() return sum - def two_sum(self, other): + def two_sum(self, other, *args): raise NotImplementedError - def three_sum(self, other): + def three_sum(self, other, *args): raise NotImplementedError def is_unimodular(self): From 733a20d162cbde4ed550ada9c4854161af4726a0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 24 Jul 2023 06:27:30 -0700 Subject: [PATCH 033/262] src/doc/en/reference/references/index.rst: Add Sch1986 --- src/doc/en/reference/references/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 6bc9946a442..626b954538a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -5829,6 +5829,9 @@ REFERENCES: subsequences*, Canadian Journal of Mathematics, Vol 13 (1961), pp. 179--191. +.. [Sch1986] Alexander Schrijver, *Theory of Linear and Integer Programming*, + John Wiley and Sons, 1986. + .. [Sch1990] Schnyder, Walter. *Embedding Planar Graphs on the Grid*. Proc. 1st Annual ACM-SIAM Symposium on Discrete Algorithms, San Francisco (1994), pp. 138-147. From f6fd9f60bdbe69488eb3e272786a6ea5e655f620 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 24 Jul 2023 06:27:57 -0700 Subject: [PATCH 034/262] sage.matrix.matrix_cmr_sparse: Add some documentation and tests --- src/sage/matrix/matrix_cmr_sparse.pyx | 44 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b4cf8f78ff0..1461964a012 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -18,11 +18,16 @@ from .seymour_decomposition cimport create_DecompositionNode cdef class Matrix_cmr_sparse(Matrix_sparse): + r""" + Base class for sparse matrices implemented in CMR + """ pass cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" + Sparse matrices with 8-bit integer entries implemented in CMR + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -166,6 +171,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): @staticmethod def one_sum(*summands): r""" + Return a block-diagonal matrix constructed from the given matrices (summands). + + INPUT: + + - ``summands`` -- integer matrices or data from which integer matrices can be + constructed + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -176,6 +188,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ⎜─────┼─────⎟ ⎜ 0 0│ 1 1⎟ ⎝ 0 0│-1 0⎠ + sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1]], [[-1]]) + sage: unicode_art(M) + ⎛ 1 0│ 0│ 0⎞ + ⎜-1 1│ 0│ 0⎟ + ⎜─────┼──┼──⎟ + ⎜ 0 0│ 1│ 0⎟ + ⎜─────┼──┼──⎟ + ⎝ 0 0│ 0│-1⎠ TESTS:: @@ -221,6 +241,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_unimodular(self): r""" + Return whether ``self`` is a unimodular matrix. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -249,6 +271,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_strongly_unimodular(self): r""" + Return whether ``self`` is a strongly unimodular matrix. + A matrix is strongly unimodular if ``self`` and ``self.transpose()`` are both unimodular. EXAMPLES:: @@ -282,7 +306,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def modulus(self): r""" - A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: + Return the integer `k` such that ``self`` is `k`-modular. + + A matrix `M` of rank `r` is `k`-modular if the following two conditions are satisfied: - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. @@ -323,6 +349,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def strong_modulus(self): r""" + Return the integer `k` such that ``self`` is strongly `k`-modular. + A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. @@ -364,6 +392,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_k_modular(self, k): r""" + Return whether ``self`` is `k`-modular. + A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. @@ -397,7 +427,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_strongly_k_modular(self, k): r""" - A matrix is strongly k-modular if ``self`` and ``self.transpose()`` are both k-modular. + Return whether ``self`` is strongly `k`-modular. + + A matrix is strongly `k`-modular if ``self`` and ``self.transpose()`` are both `k`-modular. EXAMPLES:: @@ -501,6 +533,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): construct_transposes=False, construct_graphs=False): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is regular. + This is an internal method because it should really be exposed as a method of :class:`Matroid`. @@ -635,6 +669,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): construct_transposes=False, construct_graphs=False): r""" + Return whether ``self`` is a totally unimodular matrix. + + REFERENCES: + + - [Sch1986]_ + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse From ae4d64a8ac98ff7cc6186f3be630b30ee7fbccb2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 24 Jul 2023 15:47:15 -0700 Subject: [PATCH 035/262] build/pkgs/cmr/package-version.txt: Update to pick up https://github.com/discopt/cmr/pull/33 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 435bb6e595e..34d09174321 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=43754f5e995b85c09cd8121a875a13ac6dda86ba -md5=e33f4469436ec9cd0a1f9bae9abf543b -cksum=3818534900 +sha1=ce7144e575a0fad0a6a4e63314ede9ceb42afbe6 +md5=b787470dfb83972a5379b42ed106fe59 +cksum=1569961839 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index d3e2e6cd825..dcc9261b477 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -9c309df92a0645872b44996e5fe20d1bd9002a2d +36559106dfdd155e096b88bee3949ed58c53458e From 1918d709f9ba0ea9ecd4071bc0f9251fd87dad2f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 24 Jul 2023 16:11:24 -0700 Subject: [PATCH 036/262] sage.matrix.{matrix_cmr_sparse,seymour_decomposition}: Add UnknownNode, ThreeConnectedIrregularNode --- src/sage/libs/cmr/cmr.pxd | 2 ++ src/sage/matrix/matrix_cmr_sparse.pyx | 22 +++++++++++----------- src/sage/matrix/seymour_decomposition.pyx | 20 +++++++++++++++----- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 913096badbd..813cebfcc8f 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -292,6 +292,8 @@ cdef extern from "cmr/dec.h": bint CMRdecIsGraphic(CMR_DEC* dec) bint CMRdecIsCographic(CMR_DEC* dec) bint CMRdecIsRegular(CMR_DEC* dec) + bint CMRdecIsSeriesParallelReduction(CMR_DEC* dec) + bint CMRdecIsUnknown(CMR_DEC* dec) bint CMRdecNumRows(CMR_DEC* dec) CMR_ELEMENT* CMRdecRowElements(CMR_DEC* dec) size_t* CMRdecRowsParent(CMR_DEC* dec) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1461964a012..4540c24bb92 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -576,21 +576,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate (False, (OneSumNode with 2 children, NotImplemented)) sage: unicode_art(certificate[0]) - ╭────────────────OneSumNode with 2 children - │ │ - SeriesParallelNode DecompositionNode - │ - DecompositionNode + ╭OneSumNode with 2 children─╮ + │ │ + SeriesParallelReductionNode UnknownNode + │ + ThreeConnectedIrregularNode sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) sage: result, certificate (False, (OneSumNode with 2 children, NotImplemented)) sage: unicode_art(certificate[0]) - ╭────────────────OneSumNode with 2 children - │ │ - SeriesParallelNode SeriesParallelNode - │ │ - DecompositionNode DecompositionNode + ╭OneSumNode with 2 children─╮ + │ │ + SeriesParallelReductionNode SeriesParallelReductionNode + │ │ + ThreeConnectedIrregularNode ThreeConnectedIrregularNode TESTS: @@ -622,7 +622,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: unicode_art(certificate) ╭─────TwoSumNode with 2 children │ │ - GraphicNode SeriesParallelNode + GraphicNode SeriesParallelReductionNode │ GraphicNode """ diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 231a46a078e..ef9e8831ce4 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -148,6 +148,15 @@ cdef class DecompositionNode(SageObject): return self.as_ordered_tree()._ascii_art_() +cdef class ThreeConnectedIrregularNode(DecompositionNode): + + pass + +cdef class UnknownNode(DecompositionNode): + + pass + + cdef class SumNode(DecompositionNode): def _repr_(self): @@ -248,7 +257,7 @@ cdef class PlanarNode(BaseGraphicNode): pass -cdef class SeriesParallelNode(DecompositionNode): +cdef class SeriesParallelReductionNode(DecompositionNode): pass @@ -304,10 +313,11 @@ cdef _class(CMR_DEC *dec): return CographicNode if CMRdecIsSpecialLeaf(dec, NULL): return SpecialLeafNode - if CMRdecNumChildren(dec) == 1: - return SeriesParallelNode - assert CMRdecNumChildren(dec) == 0 - return DecompositionNode + if CMRdecIsSeriesParallelReduction(dec): + return SeriesParallelReductionNode + if CMRdecIsUnknown(dec): + return UnknownNode + return ThreeConnectedIrregularNode cdef create_DecompositionNode(CMR_DEC *dec, root=None): From 10cb0b1e9798677f3da458d54c6bd671fa8bc0fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 24 Jul 2023 22:34:38 -0700 Subject: [PATCH 037/262] CMRdecNum{Columns,Rows}: Fix return type, add test --- build/pkgs/cmr/package-version.txt | 2 +- .../CMRdecNumColumns_Rows_return_type.patch | 50 +++++++++++++++++++ src/sage/libs/cmr/cmr.pxd | 4 +- src/sage/matrix/seymour_decomposition.pyx | 21 ++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index dcc9261b477..14328d3675c 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -36559106dfdd155e096b88bee3949ed58c53458e +36559106dfdd155e096b88bee3949ed58c53458e.p1 diff --git a/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch b/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch new file mode 100644 index 00000000000..4dbb06b68de --- /dev/null +++ b/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch @@ -0,0 +1,50 @@ +commit 65bee3c428dd7b64ca93b29b008d4c8fa7364691 +Author: Matthias Koeppe +Date: Mon Jul 24 22:24:27 2023 -0700 + + dec.{h,c} (CMRdecNum{Columns,Rows}): Fix return type + +diff --git a/include/cmr/dec.h b/include/cmr/dec.h +index ab97d2a..20be1dd 100644 +--- a/include/cmr/dec.h ++++ b/include/cmr/dec.h +@@ -211,7 +211,7 @@ bool CMRdecIsUnknown( + */ + + CMR_EXPORT +-bool CMRdecNumRows( ++size_t CMRdecNumRows( + CMR_DEC* dec /**< Decomposition. */ + ); + +@@ -238,7 +238,7 @@ size_t* CMRdecRowsParent( + */ + + CMR_EXPORT +-bool CMRdecNumColumns( ++size_t CMRdecNumColumns( + CMR_DEC* dec /**< Decomposition. */ + ); + +diff --git a/src/cmr/dec.c b/src/cmr/dec.c +index 35fd196..3582c0f 100644 +--- a/src/cmr/dec.c ++++ b/src/cmr/dec.c +@@ -182,7 +182,7 @@ bool CMRdecIsUnknown(CMR_DEC* dec) + return dec->type == CMR_DEC_UNKNOWN; + } + +-bool CMRdecNumRows(CMR_DEC* dec) ++size_t CMRdecNumRows(CMR_DEC* dec) + { + assert(dec); + +@@ -196,7 +196,7 @@ size_t* CMRdecRowsParent(CMR_DEC* dec) + return dec->rowsParent; + } + +-bool CMRdecNumColumns(CMR_DEC* dec) ++size_t CMRdecNumColumns(CMR_DEC* dec) + { + assert(dec); + diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 813cebfcc8f..45ddf57b911 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -294,10 +294,10 @@ cdef extern from "cmr/dec.h": bint CMRdecIsRegular(CMR_DEC* dec) bint CMRdecIsSeriesParallelReduction(CMR_DEC* dec) bint CMRdecIsUnknown(CMR_DEC* dec) - bint CMRdecNumRows(CMR_DEC* dec) + size_t CMRdecNumRows(CMR_DEC* dec) CMR_ELEMENT* CMRdecRowElements(CMR_DEC* dec) size_t* CMRdecRowsParent(CMR_DEC* dec) - bint CMRdecNumColumns(CMR_DEC* dec) + size_t CMRdecNumColumns(CMR_DEC* dec) CMR_ELEMENT* CMRdecColumnElements(CMR_DEC* dec) size_t* CMRdecColumnsParent(CMR_DEC* dec) # CMR_ERROR CMRdecPrint(CMR* cmr, CMR_DEC* dec, FILE* stream, size_t indent, bint printMatrices, bint printGraphs, bint printReductions) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ef9e8831ce4..689f0e8552d 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -74,6 +74,27 @@ cdef class DecompositionNode(SageObject): sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: certificate.parent_rows_and_columns() (None, None) + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) + sage: M2 = block_diagonal_matrix([M, M], sparse=True) + sage: M2cmr = Matrix_cmr_chr_sparse(M2.parent(), M2); M2cmr + [ 1 0 0 0] + [-1 1 0 0] + [ 0 1 0 0] + [ 0 0 1 0] + [ 0 0 -1 1] + [ 0 0 0 1] + sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, + ....: construct_matrices=True) + sage: result, certificate + (True, OneSumNode with 2 children) + sage: C = certificate.summands(); C + (GraphicNode, GraphicNode) + sage: C[0].parent_rows_and_columns() + ((0, 1, 2), (0, 1)) + sage: C[1].parent_rows_and_columns() + ((3, 4, 5), (2, 3)) """ cdef size_t *parent_rows = CMRdecRowsParent(self._dec) From 9fb09b8a551c9aabc5ee4f7c24e34bf629f88ecb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:19:25 -0700 Subject: [PATCH 038/262] build/pkgs/sagemath_cmr, pkgs/sagemath-cmr: New --- .gitignore | 3 + build/pkgs/sagemath_cmr/SPKG.rst | 1 + build/pkgs/sagemath_cmr/bootstrap | 1 + build/pkgs/sagemath_cmr/dependencies | 1 + build/pkgs/sagemath_cmr/distros/conda.txt | 1 + build/pkgs/sagemath_cmr/install-requires.txt | 2 + build/pkgs/sagemath_cmr/package-version.txt | 1 + build/pkgs/sagemath_cmr/spkg-install | 29 +++++++++ build/pkgs/sagemath_cmr/spkg-src | 24 ++++++++ build/pkgs/sagemath_cmr/src | 1 + build/pkgs/sagemath_cmr/type | 1 + pkgs/sagemath-cmr/MANIFEST.in | 21 +++++++ pkgs/sagemath-cmr/README.rst | 40 +++++++++++++ pkgs/sagemath-cmr/VERSION.txt | 1 + pkgs/sagemath-cmr/pyproject.toml.m4 | 12 ++++ pkgs/sagemath-cmr/requirements.txt.m4 | 2 + pkgs/sagemath-cmr/sage | 1 + pkgs/sagemath-cmr/setup.cfg.m4 | 17 ++++++ pkgs/sagemath-cmr/setup.py | 63 ++++++++++++++++++++ 19 files changed, 222 insertions(+) create mode 120000 build/pkgs/sagemath_cmr/SPKG.rst create mode 120000 build/pkgs/sagemath_cmr/bootstrap create mode 100644 build/pkgs/sagemath_cmr/dependencies create mode 100644 build/pkgs/sagemath_cmr/distros/conda.txt create mode 100644 build/pkgs/sagemath_cmr/install-requires.txt create mode 120000 build/pkgs/sagemath_cmr/package-version.txt create mode 100755 build/pkgs/sagemath_cmr/spkg-install create mode 100755 build/pkgs/sagemath_cmr/spkg-src create mode 120000 build/pkgs/sagemath_cmr/src create mode 100644 build/pkgs/sagemath_cmr/type create mode 100644 pkgs/sagemath-cmr/MANIFEST.in create mode 100644 pkgs/sagemath-cmr/README.rst create mode 100644 pkgs/sagemath-cmr/VERSION.txt create mode 100644 pkgs/sagemath-cmr/pyproject.toml.m4 create mode 100644 pkgs/sagemath-cmr/requirements.txt.m4 create mode 120000 pkgs/sagemath-cmr/sage create mode 100644 pkgs/sagemath-cmr/setup.cfg.m4 create mode 100644 pkgs/sagemath-cmr/setup.py diff --git a/.gitignore b/.gitignore index 70a6739c33b..678ffbd48e8 100644 --- a/.gitignore +++ b/.gitignore @@ -225,6 +225,7 @@ build/pkgs/wheel/version_requirements.txt /pkgs/sagemath-sirocco/setup.cfg /pkgs/sagemath-tdlib/setup.cfg /pkgs/sagemath-categories/setup.cfg +/pkgs/sagemath-cmr/setup.cfg /pkgs/sagemath-environment/setup.cfg /pkgs/sagemath-repl/setup.cfg /pkgs/sagemath-objects/pyproject.toml @@ -235,6 +236,7 @@ build/pkgs/wheel/version_requirements.txt /pkgs/sagemath-sirocco/pyproject.toml /pkgs/sagemath-tdlib/pyproject.toml /pkgs/sagemath-categories/pyproject.toml +/pkgs/sagemath-cmr/pyproject.toml /pkgs/sagemath-environment/pyproject.toml /pkgs/sagemath-repl/pyproject.toml /pkgs/sagemath-objects/requirements*.txt @@ -245,6 +247,7 @@ build/pkgs/wheel/version_requirements.txt /pkgs/sagemath-sirocco/requirements*.txt /pkgs/sagemath-tdlib/requirements*.txt /pkgs/sagemath-categories/requirements*.txt +/pkgs/sagemath-cmr/requirements*.txt /pkgs/sagemath-environment/requirements*.txt /pkgs/sagemath-repl/requirements*.txt /pkgs/sagemath-categories/MANIFEST.in diff --git a/build/pkgs/sagemath_cmr/SPKG.rst b/build/pkgs/sagemath_cmr/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_cmr/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_cmr/bootstrap b/build/pkgs/sagemath_cmr/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_cmr/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_cmr/dependencies b/build/pkgs/sagemath_cmr/dependencies new file mode 100644 index 00000000000..dd820598115 --- /dev/null +++ b/build/pkgs/sagemath_cmr/dependencies @@ -0,0 +1 @@ +$(PYTHON) cmr cysignals | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython diff --git a/build/pkgs/sagemath_cmr/distros/conda.txt b/build/pkgs/sagemath_cmr/distros/conda.txt new file mode 100644 index 00000000000..d6139d966ec --- /dev/null +++ b/build/pkgs/sagemath_cmr/distros/conda.txt @@ -0,0 +1 @@ +sagemath-bliss diff --git a/build/pkgs/sagemath_cmr/install-requires.txt b/build/pkgs/sagemath_cmr/install-requires.txt new file mode 100644 index 00000000000..0b61641bebd --- /dev/null +++ b/build/pkgs/sagemath_cmr/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-cmr ~= 10.1 diff --git a/build/pkgs/sagemath_cmr/package-version.txt b/build/pkgs/sagemath_cmr/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_cmr/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_cmr/spkg-install b/build/pkgs/sagemath_cmr/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_cmr/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_cmr/spkg-src b/build/pkgs/sagemath_cmr/spkg-src new file mode 100755 index 00000000000..0df5a1db65d --- /dev/null +++ b/build/pkgs/sagemath_cmr/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-cmr +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_cmr/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_cmr + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_cmr/src b/build/pkgs/sagemath_cmr/src new file mode 120000 index 00000000000..d2d6820f5ec --- /dev/null +++ b/build/pkgs/sagemath_cmr/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-cmr \ No newline at end of file diff --git a/build/pkgs/sagemath_cmr/type b/build/pkgs/sagemath_cmr/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_cmr/type @@ -0,0 +1 @@ +optional diff --git a/pkgs/sagemath-cmr/MANIFEST.in b/pkgs/sagemath-cmr/MANIFEST.in new file mode 100644 index 00000000000..cc9a45b309f --- /dev/null +++ b/pkgs/sagemath-cmr/MANIFEST.in @@ -0,0 +1,21 @@ +include VERSION.txt + +graft sage/libs/cmr +include sage/matrix/*_cmr_*.p* +include sage/matrix/seymour_*.p* + +global-exclude *.c +global-exclude *.cpp + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ + +global-exclude all__*.py +global-include all__sagemath_cmr.py + +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-cmr/README.rst b/pkgs/sagemath-cmr/README.rst new file mode 100644 index 00000000000..545ae16eb32 --- /dev/null +++ b/pkgs/sagemath-cmr/README.rst @@ -0,0 +1,40 @@ +========================================================================== + Sage: Open Source Mathematics Software: Combinatorial matrix recognition +========================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-cmr`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the CMR library (https://github.com/discopt/cmr), +providing recognition and decomposition algorithms for: + +- Totally Unimodular Matrices +- Network Matrices +- Complement Totally Unimodular Matrices +- (Strongly) k-Modular and Unimodular Matrices +- Regular Matroids +- Graphic / Cographic / Planar Matrices +- Series-Parallel Matroids diff --git a/pkgs/sagemath-cmr/VERSION.txt b/pkgs/sagemath-cmr/VERSION.txt new file mode 100644 index 00000000000..2f52450b31d --- /dev/null +++ b/pkgs/sagemath-cmr/VERSION.txt @@ -0,0 +1 @@ +10.0 diff --git a/pkgs/sagemath-cmr/pyproject.toml.m4 b/pkgs/sagemath-cmr/pyproject.toml.m4 new file mode 100644 index 00000000000..439482ad26b --- /dev/null +++ b/pkgs/sagemath-cmr/pyproject.toml.m4 @@ -0,0 +1,12 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools + SPKG_INSTALL_REQUIRES_sage_conf + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-cmr/requirements.txt.m4 b/pkgs/sagemath-cmr/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-cmr/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-cmr/sage b/pkgs/sagemath-cmr/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-cmr/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-cmr/setup.cfg.m4 b/pkgs/sagemath-cmr/setup.cfg.m4 new file mode 100644 index 00000000000..0b0d24054dd --- /dev/null +++ b/pkgs/sagemath-cmr/setup.cfg.m4 @@ -0,0 +1,17 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-bliss +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Combinatorial matrix recognition +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = + SPKG_INSTALL_REQUIRES_cysignals + +[options.extras_require] +test = + SPKG_INSTALL_REQUIRES_sagemath_repl diff --git a/pkgs/sagemath-cmr/setup.py b/pkgs/sagemath-cmr/setup.py new file mode 100644 index 00000000000..a78c51347d6 --- /dev/null +++ b/pkgs/sagemath-cmr/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from ​https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-bliss'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-bliss']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) From e9f0501e88821fc1167c7c6ea1f3dafb5130441d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 00:19:16 -0700 Subject: [PATCH 039/262] Add all__sagemath_cmr.py files --- src/sage/all__sagemath_cmr.py | 0 src/sage/libs/all__sagemath_cmr.py | 0 src/sage/matrix/all__sagemath_cmr.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/sage/all__sagemath_cmr.py create mode 100644 src/sage/libs/all__sagemath_cmr.py create mode 100644 src/sage/matrix/all__sagemath_cmr.py diff --git a/src/sage/all__sagemath_cmr.py b/src/sage/all__sagemath_cmr.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/libs/all__sagemath_cmr.py b/src/sage/libs/all__sagemath_cmr.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/matrix/all__sagemath_cmr.py b/src/sage/matrix/all__sagemath_cmr.py new file mode 100644 index 00000000000..e69de29bb2d From c46e0a4e0f804e7f00a7d05b9a69ea27d3f3de39 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 00:41:03 -0700 Subject: [PATCH 040/262] pkgs/sagemath-cmr: Fixups --- pkgs/sagemath-cmr/setup.cfg.m4 | 2 +- pkgs/sagemath-cmr/setup.py | 4 ++-- src/sage/libs/cmr/__init__.py | 1 + src/sage/libs/cmr/cmr.pxd | 1 + src/sage/libs/cmr/cmr.pyx | 1 + src/sage/matrix/matrix_cmr_sparse.pxd | 1 + src/sage/matrix/matrix_cmr_sparse.pyx | 1 + src/sage/matrix/seymour_decomposition.pxd | 1 + src/sage/matrix/seymour_decomposition.pyx | 1 + 9 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pkgs/sagemath-cmr/setup.cfg.m4 b/pkgs/sagemath-cmr/setup.cfg.m4 index 0b0d24054dd..c98706e36a3 100644 --- a/pkgs/sagemath-cmr/setup.cfg.m4 +++ b/pkgs/sagemath-cmr/setup.cfg.m4 @@ -1,6 +1,6 @@ include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- [metadata] -name = sagemath-bliss +name = sagemath-cmr version = file: VERSION.txt description = Sage: Open Source Mathematics Software: Combinatorial matrix recognition long_description = file: README.rst diff --git a/pkgs/sagemath-cmr/setup.py b/pkgs/sagemath-cmr/setup.py index a78c51347d6..8a642648986 100644 --- a/pkgs/sagemath-cmr/setup.py +++ b/pkgs/sagemath-cmr/setup.py @@ -42,14 +42,14 @@ from sage_setup.command.sage_build_cython import sage_build_cython from sage_setup.command.sage_build_ext import sage_build_ext - sage_build_cython.built_distributions = ['sagemath-bliss'] + sage_build_cython.built_distributions = ['sagemath-cmr'] cmdclass = dict(build_cython=sage_build_cython, build_ext=sage_build_ext) from sage_setup.find import find_python_sources python_packages, python_modules, cython_modules = find_python_sources( - '.', ['sage'], distributions=['sagemath-bliss']) + '.', ['sage'], distributions=['sagemath-cmr']) log.warn('python_packages = {0}'.format(python_packages)) log.warn('python_modules = {0}'.format(python_modules)) diff --git a/src/sage/libs/cmr/__init__.py b/src/sage/libs/cmr/__init__.py index e69de29bb2d..4f89e982ee4 100644 --- a/src/sage/libs/cmr/__init__.py +++ b/src/sage/libs/cmr/__init__.py @@ -0,0 +1 @@ +# sage_setup: distribution = sagemath-cmr diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 45ddf57b911..65f489b7035 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr # -*- python -*- # distutils: libraries = cmr diff --git a/src/sage/libs/cmr/cmr.pyx b/src/sage/libs/cmr/cmr.pyx index 295746a46ac..f451c81c228 100644 --- a/src/sage/libs/cmr/cmr.pyx +++ b/src/sage/libs/cmr/cmr.pyx @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr # -*- python -*- cdef CMR *cmr = NULL diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index 6f4ce1fe2ab..61e8d732ea0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH, CMR_GRAPH_EDGE from .matrix_sparse cimport Matrix_sparse diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4540c24bb92..91e0b51995e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr r""" Sparse Matrices with CMR """ diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 68220eab566..d188e3d8879 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr from sage.libs.cmr.cmr cimport CMR_DEC from sage.structure.sage_object cimport SageObject diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 689f0e8552d..62e9b70e609 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1,3 +1,4 @@ +# sage_setup: distribution = sagemath-cmr r""" Seymour's decomposition of totally unimodular matrices and regular matroids """ From cc1e6b93a47f8c4cbe025895b940ac79fc02defc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 15:01:43 -0700 Subject: [PATCH 041/262] Matrix_cmr_chr_sparse.is_network_matrix: Implement --- src/sage/matrix/matrix_cmr_sparse.pxd | 5 +- src/sage/matrix/matrix_cmr_sparse.pyx | 85 ++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index 61e8d732ea0..b2664aeefd1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH, CMR_GRAPH_EDGE +from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH, CMR_GRAPH_EDGE, bool from .matrix_sparse cimport Matrix_sparse @@ -24,3 +24,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_graph(CMR_GRAPH *graph) + +cdef _sage_arc(CMR_GRAPH *graph, CMR_GRAPH_EDGE e, bint reversed) +cdef _sage_digraph(CMR_GRAPH *graph, bool *arcs_reversed) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 91e0b51995e..f9859cc2a6e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -514,13 +514,69 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): for column in range(self.ncols())) return True, (sage_graph, sage_forest_edges, sage_coforest_edges) - return False, None # submatrix TBD + return False, NotImplemented # submatrix TBD def is_cographic(self, *, time_limit=60.0, certificate=False): raise NotImplementedError def is_network_matrix(self, *, time_limit=60.0, certificate=False): - raise NotImplementedError + r""" + EXAMPLES: + + This is test ``Basic`` in CMR's ``test_network.cpp``:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 7, sparse=True), + ....: [[-1, 0, 0, 0, 1, -1, 0], + ....: [ 1, 0, 0, 1, -1, 1, 0], + ....: [ 0, -1, 0, -1, 1, -1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1, -1, 1, 0, 1], + ....: [ 0, 0, -1, 1, -1, 0, 0]]) + sage: M.is_network_matrix() + True + sage: result, certificate = M.is_network_matrix(certificate=True) + sage: result, certificate + (True, + (Digraph on 7 vertices, + ((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)), + ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) + sage: digraph, forest_arcs, coforest_arcs = certificate + sage: digraph.plot() # TODO: How should we visualize the forest & coforest? + Graphics object consisting of 21 graphics primitives + """ + cdef bool result + cdef CMR_GRAPH *digraph = NULL + cdef CMR_GRAPH_EDGE* forest_arcs = NULL + cdef CMR_GRAPH_EDGE* coforest_arcs = NULL + cdef bool* arcs_reversed = NULL + cdef CMR_SUBMAT* submatrix = NULL + cdef CMR_NETWORK_STATISTICS stats + + sig_on() + try: + if certificate: + CMR_CALL(CMRtestNetworkMatrix(cmr, self._mat, &result, &digraph, &forest_arcs, + &coforest_arcs, &arcs_reversed, &submatrix, &stats, + time_limit)) + else: + CMR_CALL(CMRtestNetworkMatrix(cmr, self._mat, &result, NULL, NULL, + NULL, NULL, NULL, &stats, time_limit)) + finally: + sig_off() + + if not certificate: + return result + + if result: + sage_digraph = _sage_digraph(digraph, arcs_reversed) + sage_forest_arcs = tuple(_sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) + for row in range(self.nrows())) + sage_coforest_arcs = tuple(_sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) + for column in range(self.ncols())) + return True, (sage_digraph, sage_forest_arcs, sage_coforest_arcs) + + return False, NotImplemented # submatrix TBD def is_dual_network_matrix(self, *, time_limit=60.0, certificate=False): raise NotImplementedError @@ -813,3 +869,28 @@ cdef _sage_graph(CMR_GRAPH *graph): i = CMRgraphEdgesNext(graph, i) return Graph([list(vertices()), list(edges())]) + + +cdef _sage_arc(CMR_GRAPH *graph, CMR_GRAPH_EDGE e, bint reversed): + if reversed: + return Integer(CMRgraphEdgeV(graph, e)), Integer(CMRgraphEdgeU(graph, e)) + return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) + + +cdef _sage_digraph(CMR_GRAPH *graph, bool *arcs_reversed): + from sage.graphs.digraph import DiGraph + + def vertices(): + i = CMRgraphNodesFirst(graph) + while CMRgraphNodesValid(graph, i): + yield i + i = CMRgraphNodesNext(graph, i) + + def arcs(): + i = CMRgraphEdgesFirst(graph) + while CMRgraphEdgesValid(graph, i): + e = CMRgraphEdgesEdge(graph, i) + yield _sage_arc(graph, e, arcs_reversed[e]) + i = CMRgraphEdgesNext(graph, i) + + return DiGraph([list(vertices()), list(arcs())]) From 98a0169776582a68ad50c304efded25ad2621f8b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Feb 2024 09:44:33 -0800 Subject: [PATCH 042/262] src/sage/features/sagemath.py: Add features sage.libs.cmr --- src/sage/features/sagemath.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index f536665d8cc..2c886e5e912 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -359,6 +359,30 @@ def __init__(self): spkg='sagemath_libbraiding', type='standard') +class sage__libs__cmr(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.cmr` + and other modules depending on CMR, the Combinatorial Matrix Recognition library. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage__libs__cmr + sage: sage__libs__cmr().is_present() # optional - sage.libs.cmr + FeatureTestResult('sage.libs.cmr', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__cmr + sage: isinstance(sage__libs__cmr(), sage__libs__cmr) + True + """ + JoinFeature.__init__(self, 'sage.libs.cmr', + [PythonModule('sage.matrix.matrix_cmr_sparse')], + spkg='sagemath_cmr', type='standard') + + class sage__libs__ecl(PythonModule): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.libs.ecl`. @@ -1178,6 +1202,7 @@ def all_features(): sage__graphs(), sage__groups(), sage__libs__braiding(), + sage__libs__cmr(), sage__libs__ecl(), sage__libs__flint(), sage__libs__gap(), From 1c74755daeef471d15da733bf21c7842d841e31f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 19:51:43 -0700 Subject: [PATCH 043/262] src/sage/features/sagemath.py: Fix up --- src/sage/features/sagemath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 2c886e5e912..46d43e5bffc 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -380,7 +380,7 @@ def __init__(self): """ JoinFeature.__init__(self, 'sage.libs.cmr', [PythonModule('sage.matrix.matrix_cmr_sparse')], - spkg='sagemath_cmr', type='standard') + spkg='sagemath_cmr') class sage__libs__ecl(PythonModule): From bd12866dff50d89a6424122ff529f9775d18ebc8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 19:52:19 -0700 Subject: [PATCH 044/262] src/sage/libs/cmr/cmr.pxd: Add more declarations --- src/sage/libs/cmr/cmr.pxd | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 65f489b7035..a53b7f40eaa 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -27,6 +27,13 @@ cdef extern from "cmr/env.h": char* CMRgetErrorMessage(CMR* cmr) void CMRclearErrorMessage(CMR* cmr) + CMR_ERROR _CMRallocBlock(CMR* cmr, void** ptr, size_t size) + CMR_ERROR _CMRfreeBlock(CMR* cmr, void** ptr, size_t size) + CMR_ERROR _CMRallocBlockArray(CMR* cmr, void** ptr, size_t size, size_t length) + CMR_ERROR _CMRreallocBlockArray(CMR* cmr, void** ptr, size_t size, size_t length) + CMR_ERROR _CMRduplicateBlockArray(CMR* cmr, void** ptr, size_t size, size_t length, void* source) + CMR_ERROR _CMRfreeBlockArray(CMR* cmr, void** ptr) + cdef extern from "cmr/matrix.h": ctypedef struct CMR_SUBMAT: From 5a779220cf9841c0895fe32d6a09725a819f43f4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 19:52:49 -0700 Subject: [PATCH 045/262] Matrix_cmr_chr_sparse._network_matrix_from_digraph: New --- src/sage/matrix/matrix_cmr_sparse.pyx | 103 ++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index f9859cc2a6e..0519fae9d4a 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -169,6 +169,109 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): result._root = None return result + @staticmethod + def _network_matrix_from_digraph(digraph, forest_arcs=None, arcs=None, vertices=None): + r""" + Return the network matrix of ``digraph``, pivoted according to ``forest_arcs``. + + Its rows are indexed parallel to ``forest_arcs``, and + its columns are indexed parallel to ``vertices``. + + INPUT: + + - ``digraph`` -- a :class:`DiGraph` + + - ``forest_arcs`` -- a sequence of arcs of the ``digraph`` or ``None`` (the default: + use the labels of the ``arcs`` as a boolean value) + + - ``arcs`` -- a sequence of arcs of the digraph or ``None`` (the default: + all arcs between the ``vertices`` of the ``digraph``) + + - ``vertices`` -- a sequence of vertices of the digraph or ``None`` (the default: + all vertices of the ``digraph``) + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + + sage: D = DiGraph([[0, 1, 2], [(0, 1), (1, 2), (0, 2)]]) + sage: T = [(0, 1), (0, 2)] + sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D, T); M + [-1 -1 0 1] + [ 1 1 1 0] + + TESTS:: + + sage: D = DiGraph([[0, 1, 2], [(0, 1), (1, 2), (0, 2)]]) + sage: not_a_forest = [(0, 1), (1, 2), (0, 2)] + sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D, not_a_forest); M + Traceback (most recent call last): + ... + ValueError: not a forest + """ + cdef CMR_GRAPH *cmr_digraph = NULL + cdef dict vertex_to_cmr_node = {} + cdef dict arc_to_cmr_edge = {} + cdef CMR_GRAPH_EDGE cmr_edge + cdef CMR_GRAPH_NODE cmr_node + + if cmr == NULL: + CMRcreateEnvironment(&cmr) + + CMR_CALL(CMRgraphCreateEmpty(cmr, &cmr_digraph, digraph.num_verts(), digraph.num_edges())) + + if vertices is None: + vertices = digraph.vertex_iterator() + for u in vertices: + CMR_CALL(CMRgraphAddNode(cmr, cmr_digraph, &cmr_node)) + vertex_to_cmr_node[u] = cmr_node + + vertices = vertex_to_cmr_node.keys() + if arcs is None: + arcs = digraph.edge_iterator(labels=False, vertices=vertices, ignore_direction=True) + + for a in arcs: + u, v = a + CMR_CALL(CMRgraphAddEdge(cmr, cmr_digraph, vertex_to_cmr_node[u], + vertex_to_cmr_node[v], &cmr_edge)) + arc_to_cmr_edge[a] = cmr_edge + + cdef CMR_GRAPH_EDGE *cmr_forest_arcs = NULL + cdef bool *cmr_arcs_reversed = NULL + cdef CMR_CHRMAT *cmr_matrix = NULL + cdef bool is_correct_forest + cdef size_t num_forest_arcs + + CMR_CALL(_CMRallocBlockArray(cmr, &cmr_forest_arcs, len(forest_arcs), sizeof(CMR_GRAPH_EDGE))) + try: + if forest_arcs is None: + num_forest_arcs = 0 + for u, v, label in digraph.edge_iterator(labels=True, vertices=vertices, + ignore_direction=True): + if label: + cmr_forest_arcs[num_forest_arcs] = arc_to_cmr_edge[(u, v)] + num_forest_arcs += 1 + else: + num_forest_arcs = len(forest_arcs) + for i, a in enumerate(forest_arcs): + cmr_forest_arcs[i] = arc_to_cmr_edge[a] + + CMR_CALL(_CMRallocBlockArray(cmr, &cmr_arcs_reversed, len(arc_to_cmr_edge), sizeof(bool))) + try: + for j in range(len(arc_to_cmr_edge)): + cmr_arcs_reversed[j] = False + CMR_CALL(CMRcomputeNetworkMatrix(cmr, cmr_digraph, &cmr_matrix, NULL, + cmr_arcs_reversed, num_forest_arcs, cmr_forest_arcs, + 0, NULL, &is_correct_forest)) + if not is_correct_forest: + raise ValueError('not a forest') + finally: + CMR_CALL(_CMRfreeBlockArray(cmr, &cmr_arcs_reversed)) + finally: + CMR_CALL(_CMRfreeBlockArray(cmr, &cmr_forest_arcs)) + + return Matrix_cmr_chr_sparse._from_cmr(cmr_matrix) + @staticmethod def one_sum(*summands): r""" From 538b72bd3b65e68987818a9902f22afe8e7b93e0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 23:12:08 -0700 Subject: [PATCH 046/262] Matrix_cmr_chr_sparse._network_matrix_from_digraph: Fixups --- src/sage/matrix/matrix_cmr_sparse.pyx | 90 +++++++++++++++++++++------ 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 0519fae9d4a..152d6c84f41 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -174,8 +174,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return the network matrix of ``digraph``, pivoted according to ``forest_arcs``. - Its rows are indexed parallel to ``forest_arcs``, and - its columns are indexed parallel to ``vertices``. + Its rows are indexed parallel to ``forest_arcs``. + It is in "short tableau" form, i.e., the columns are indexed parallel + to the elements of ``arcs`` that are not in ``forest_arcs``. + + .. NOTE:: + + In [Sch1986]_, the columns are indexed by all arcs of the digraph, + giving a "long tableau" form of the network matrix. INPUT: @@ -185,7 +191,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use the labels of the ``arcs`` as a boolean value) - ``arcs`` -- a sequence of arcs of the digraph or ``None`` (the default: - all arcs between the ``vertices`` of the ``digraph``) + all arcs going out from the ``vertices``) - ``vertices`` -- a sequence of vertices of the digraph or ``None`` (the default: all vertices of the ``digraph``) @@ -194,11 +200,35 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: D = DiGraph([[0, 1, 2], [(0, 1), (1, 2), (0, 2)]]) - sage: T = [(0, 1), (0, 2)] + Defining the forest by arc labels:: + + sage: D = DiGraph([[0, 1, 2, 3], + ....: [(0, 1, True), (0, 2, True), (1, 2), (1, 3, True), (2, 3)]]) + sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D); M + [ 1 -1] + [-1 1] + [ 1 0] + + Defining the forest by a separate list of forest arcs:: + + sage: D = DiGraph([[0, 1, 2, 3], + ....: [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)]]) + sage: T = [(0, 1), (0, 2), (1, 3)] sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D, T); M - [-1 -1 0 1] - [ 1 1 1 0] + [ 1 -1] + [-1 1] + [ 1 0] + + Prescribing an order for the arcs (columns):: + + sage: D = DiGraph([[0, 1, 2, 3], + ....: [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)]]) + sage: T = [(0, 1), (0, 2), (1, 3)] + sage: A = [(2, 3), (0, 1), (0, 2), (1, 2), (1, 3)] + sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D, T, arcs=A); M + [ 1 -1] + [-1 1] + [ 1 0] TESTS:: @@ -207,7 +237,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M = Matrix_cmr_chr_sparse._network_matrix_from_digraph(D, not_a_forest); M Traceback (most recent call last): ... - ValueError: not a forest + ValueError: not a spanning forest """ cdef CMR_GRAPH *cmr_digraph = NULL cdef dict vertex_to_cmr_node = {} @@ -221,20 +251,22 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRgraphCreateEmpty(cmr, &cmr_digraph, digraph.num_verts(), digraph.num_edges())) if vertices is None: - vertices = digraph.vertex_iterator() - for u in vertices: + iter_vertices = digraph.vertex_iterator() + else: + iter_vertices = vertices + for u in iter_vertices: CMR_CALL(CMRgraphAddNode(cmr, cmr_digraph, &cmr_node)) vertex_to_cmr_node[u] = cmr_node vertices = vertex_to_cmr_node.keys() if arcs is None: - arcs = digraph.edge_iterator(labels=False, vertices=vertices, ignore_direction=True) + arcs = digraph.edge_iterator(labels=False, vertices=vertices, ignore_direction=False) for a in arcs: u, v = a CMR_CALL(CMRgraphAddEdge(cmr, cmr_digraph, vertex_to_cmr_node[u], vertex_to_cmr_node[v], &cmr_edge)) - arc_to_cmr_edge[a] = cmr_edge + arc_to_cmr_edge[(u, v)] = cmr_edge cdef CMR_GRAPH_EDGE *cmr_forest_arcs = NULL cdef bool *cmr_arcs_reversed = NULL @@ -242,19 +274,27 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bool is_correct_forest cdef size_t num_forest_arcs - CMR_CALL(_CMRallocBlockArray(cmr, &cmr_forest_arcs, len(forest_arcs), sizeof(CMR_GRAPH_EDGE))) + cdef size_t mem_arcs + if forest_arcs is not None: + mem_arcs = len(forest_arcs) + else: + mem_arcs = len(vertices) - 1 + + CMR_CALL(_CMRallocBlockArray(cmr, &cmr_forest_arcs, mem_arcs, sizeof(CMR_GRAPH_EDGE))) try: if forest_arcs is None: num_forest_arcs = 0 for u, v, label in digraph.edge_iterator(labels=True, vertices=vertices, - ignore_direction=True): + ignore_direction=False): if label: + if num_forest_arcs >= mem_arcs: + raise ValueError('not a spanning forest') cmr_forest_arcs[num_forest_arcs] = arc_to_cmr_edge[(u, v)] num_forest_arcs += 1 else: num_forest_arcs = len(forest_arcs) - for i, a in enumerate(forest_arcs): - cmr_forest_arcs[i] = arc_to_cmr_edge[a] + for i, (u, v) in enumerate(forest_arcs): + cmr_forest_arcs[i] = arc_to_cmr_edge[(u, v)] CMR_CALL(_CMRallocBlockArray(cmr, &cmr_arcs_reversed, len(arc_to_cmr_edge), sizeof(bool))) try: @@ -264,7 +304,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cmr_arcs_reversed, num_forest_arcs, cmr_forest_arcs, 0, NULL, &is_correct_forest)) if not is_correct_forest: - raise ValueError('not a forest') + raise ValueError('not a spanning forest') finally: CMR_CALL(_CMRfreeBlockArray(cmr, &cmr_arcs_reversed)) finally: @@ -645,7 +685,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)), ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) sage: digraph, forest_arcs, coforest_arcs = certificate - sage: digraph.plot() # TODO: How should we visualize the forest & coforest? + sage: list(digraph.edges(sort=True)) + [(0, 6, None), + (0, 8, None), + (3, 4, None), + (3, 8, None), + (3, 9, None), + (4, 0, None), + (4, 6, None), + (4, 9, None), + (5, 3, None), + (5, 4, None), + (5, 6, None), + (9, 0, None), + (9, 8, None)] + sage: digraph.plot(color_by_label=True) # TODO: How should we visualize the forest & coforest? Graphics object consisting of 21 graphics primitives """ cdef bool result From 0b610a22c9f675f9d48aab7ccdf1026973bf5008 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 25 Jul 2023 23:45:16 -0700 Subject: [PATCH 047/262] Matrix_cmr_chr_sparse.is_network_matrix: Add plotting example --- src/sage/matrix/matrix_cmr_sparse.pyx | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 152d6c84f41..b1258479e73 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -686,20 +686,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) sage: digraph, forest_arcs, coforest_arcs = certificate sage: list(digraph.edges(sort=True)) - [(0, 6, None), - (0, 8, None), - (3, 4, None), - (3, 8, None), - (3, 9, None), - (4, 0, None), - (4, 6, None), - (4, 9, None), - (5, 3, None), - (5, 4, None), - (5, 6, None), - (9, 0, None), - (9, 8, None)] - sage: digraph.plot(color_by_label=True) # TODO: How should we visualize the forest & coforest? + [(0, 6, None), (0, 8, None), + (3, 4, None), (3, 8, None), (3, 9, None), + (4, 0, None), (4, 6, None), (4, 9, None), + (5, 3, None), (5, 4, None), (5, 6, None), + (9, 0, None), (9, 8, None)] + sage: digraph.plot(edge_colors={'red': forest_arcs}) # needs sage.plot Graphics object consisting of 21 graphics primitives """ cdef bool result From 6f0cf0ef1d37a94b03cd695ad526e7174d15f356 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jul 2023 13:38:31 -0700 Subject: [PATCH 048/262] sage.matrix.{matrix_cmr_sparse,seymour_decomposition}: Fix object ownership --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- src/sage/matrix/seymour_decomposition.pyx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b1258479e73..d816ab4a034 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -133,7 +133,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return self def __dealloc__(self): - if self._root is not None: + if self._root is None or self._root is self: # We own it, so we have to free it. CMRchrmatFree(cmr, &self._mat) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 62e9b70e609..e8299353104 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -15,7 +15,8 @@ from .matrix_space import MatrixSpace cdef class DecompositionNode(SageObject): cdef _set_dec(self, CMR_DEC *dec, root): - if self._root is None: + if self._root is None or self._root is self: + # We own it, so we have to free it. CMR_CALL(CMRdecFree(cmr, &self._dec)) self._dec = dec self._root = root From e7bea15eb8ce94972ef1fd9ed3b20846c4804047 Mon Sep 17 00:00:00 2001 From: jsantillan3 <70868442+jsantillan3@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:01:30 -0700 Subject: [PATCH 049/262] Add examples to OneSumNode in seymour_decomposition.pyx, add methods block_matrix_form, summand_matrices (#8) * wip onesum * wip onesum2 * wip onesum test * onesum node example * fixed names of .summand_matrices() and .block_matrix_form, ....: and added examples to ._children() * style fixes --------- Co-authored-by: J S Co-authored-by: J S --- src/sage/matrix/seymour_decomposition.pyx | 84 ++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index e8299353104..fe749075fce 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -157,6 +157,35 @@ cdef class DecompositionNode(SageObject): @cached_method def _children(self): + r""" + Returns tuple of summands, () in the case of graphic or leaf nodes. + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]], [[1, 0], [0,1]]); M + [ 1 0| 0 0| 0 0] + [-1 1| 0 0| 0 0] + [-----+-----+-----] + [ 0 0| 1 1| 0 0] + [ 0 0|-1 0| 0 0] + [-----+-----+-----] + [ 0 0| 0 0| 1 0] + [ 0 0| 0 0| 0 1] + sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate + OneSumNode with 4 children + sage: certificate._children() + (GraphicNode, GraphicNode, GraphicNode, GraphicNode) + + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 2, sparse=True), + ...: [[1, 1], [-1, 0]]); M2 + [ 1 1] + [-1 0] + sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate + GraphicNode + certificate._children() + () + """ return tuple(create_DecompositionNode(CMRdecChild(self._dec, index), self._root or self) for index in range(CMRdecNumChildren(self._dec))) @@ -194,14 +223,65 @@ cdef class SumNode(DecompositionNode): summands = DecompositionNode._children + def summand_matrices(self): + return tuple(s.matrix() for s in self._children()) + cdef class OneSumNode(SumNode): - pass + def block_matrix_form(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1, 1], [-1, 0]]) + sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate + OneSumNode with 2 children + sage: certificate.summand_matrices() + ( + [ 1 0] [ 1 1] + [-1 1], [-1 0] + ) + sage: certificate.block_matrix_form() + [ 1 0| 0 0] + [-1 1| 0 0] + [-----+-----] + [ 0 0| 1 1] + [ 0 0|-1 0] + + sage: M3 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1, 1], [-1, 0]], [[1, 0], [0,1]] + ....: [[1, 1], [-1, 0]], [[1, 0], [0,1]]); M3 + [ 1 0| 0 0| 0 0] + [-1 1| 0 0| 0 0] + [-----+-----+-----] + [ 0 0| 1 1| 0 0] + [ 0 0|-1 0| 0 0] + [-----+-----+-----] + [ 0 0| 0 0| 1 0] + [ 0 0| 0 0| 0 1] + sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate + OneSumNode with 4 children + sage: certificate.summand_matrices() + ( + [ 1 0] [ 1 1] + [-1 1], [-1 0], [1], [1] + ) + sage: certificate.block_matrix_form() + [ 1 0| 0 0| 0| 0] + [-1 1| 0 0| 0| 0] + [-----+-----+--+--] + [ 0 0| 1 1| 0| 0] + [ 0 0|-1 0| 0| 0] + [-----+-----+--+--] + [ 0 0| 0 0| 1| 0] + [-----+-----+--+--] + [ 0 0| 0 0| 0| 1] + """ + return Matrix_cmr_chr_sparse.one_sum(*self.summand_matrices()) cdef class TwoSumNode(SumNode): - + pass From 2b8edae82c587b4c333e61bfd1674da2c91c970e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jul 2023 18:04:21 -0700 Subject: [PATCH 050/262] sage.matrix.seymour_decomposition: Another fix for object ownership --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 ++++++++ src/sage/matrix/seymour_decomposition.pyx | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index d816ab4a034..e5ad473a2b5 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -162,6 +162,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): @staticmethod cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=False): + r""" + INPUT: + + - ``mat`` -- a ``CMR_CHRMAT``; after this call, it is owned by the created Python object + + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + + """ cdef Matrix_cmr_chr_sparse result ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms, immutable=immutable) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index fe749075fce..ce2f1978118 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -14,10 +14,14 @@ from .matrix_space import MatrixSpace cdef class DecompositionNode(SageObject): + def __cinit__(self): + self._dec = NULL + cdef _set_dec(self, CMR_DEC *dec, root): if self._root is None or self._root is self: - # We own it, so we have to free it. - CMR_CALL(CMRdecFree(cmr, &self._dec)) + if self._dec != NULL: + # We own it, so we have to free it. + CMR_CALL(CMRdecFree(cmr, &self._dec)) self._dec = dec self._root = root @@ -60,7 +64,7 @@ cdef class DecompositionNode(SageObject): ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms) result._mat = mat - result._root = self._root + result._root = self._root or self return result def parent_rows_and_columns(self): From a6a9a8f2f3476b7673426ec0b350d60d99467be4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jul 2023 19:31:10 -0700 Subject: [PATCH 051/262] sage.matrix.seymour_decomposition: Sort children by parent_rows_and_columns --- src/sage/matrix/seymour_decomposition.pyx | 36 +++++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ce2f1978118..8e8661641bd 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -67,6 +67,7 @@ cdef class DecompositionNode(SageObject): result._root = self._root or self return result + @cached_method def parent_rows_and_columns(self): r""" EXAMPLES:: @@ -102,7 +103,6 @@ cdef class DecompositionNode(SageObject): sage: C[1].parent_rows_and_columns() ((3, 4, 5), (2, 3)) """ - cdef size_t *parent_rows = CMRdecRowsParent(self._dec) cdef size_t *parent_columns = CMRdecColumnsParent(self._dec) if parent_rows == NULL: @@ -162,12 +162,20 @@ cdef class DecompositionNode(SageObject): @cached_method def _children(self): r""" - Returns tuple of summands, () in the case of graphic or leaf nodes. + Return a tuple of the children. + + The children are sorted by their :meth:`parent_rows_and_columns`. + + In the case of :class:`SumNode`, this is the same as :meth:`~SumNode.summands`. + + For graphic or leaf nodes, it returns the empty tuple. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], - ....: [[1, 1], [-1, 0]], [[1, 0], [0,1]]); M + ....: [[1, 1], [-1, 0]], + ....: [[1, 0], [0,1]]); M [ 1 0| 0 0| 0 0] [-1 1| 0 0| 0 0] [-----+-----+-----] @@ -176,23 +184,24 @@ cdef class DecompositionNode(SageObject): [-----+-----+-----] [ 0 0| 0 0| 1 0] [ 0 0| 0 0| 0 1] - sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate + sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate OneSumNode with 4 children sage: certificate._children() (GraphicNode, GraphicNode, GraphicNode, GraphicNode) sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 2, sparse=True), - ...: [[1, 1], [-1, 0]]); M2 + ....: [[1, 1], [-1, 0]]); M2 [ 1 1] [-1 0] - sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate + sage: result, certificate = M2.is_totally_unimodular(certificate=True); certificate GraphicNode - certificate._children() + sage: certificate._children() () """ - return tuple(create_DecompositionNode(CMRdecChild(self._dec, index), - self._root or self) - for index in range(CMRdecNumChildren(self._dec))) + return tuple(sorted((create_DecompositionNode(CMRdecChild(self._dec, index), + self._root or self) + for index in range(CMRdecNumChildren(self._dec))), + key=lambda node: node.parent_rows_and_columns())) def _repr_(self): return f'{self.__class__.__name__}' @@ -228,7 +237,7 @@ cdef class SumNode(DecompositionNode): summands = DecompositionNode._children def summand_matrices(self): - return tuple(s.matrix() for s in self._children()) + return tuple(s.matrix() for s in self.summands()) cdef class OneSumNode(SumNode): @@ -253,8 +262,9 @@ cdef class OneSumNode(SumNode): [ 0 0| 1 1] [ 0 0|-1 0] - sage: M3 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1, 1], [-1, 0]], [[1, 0], [0,1]] - ....: [[1, 1], [-1, 0]], [[1, 0], [0,1]]); M3 + sage: M3 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]], + ....: [[1, 0], [0, 1]]); M3 [ 1 0| 0 0| 0 0] [-1 1| 0 0| 0 0] [-----+-----+-----] From 4d450909b36c8e701c32e2aa601836f4df0daadf Mon Sep 17 00:00:00 2001 From: xuluze <113661384+xuluze@users.noreply.github.com> Date: Wed, 26 Jul 2023 19:39:37 -0700 Subject: [PATCH 052/262] Add two_sum in matrix_cmr_sparse.pyx (#9) --- src/sage/matrix/matrix_cmr_sparse.pyx | 56 +++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e5ad473a2b5..64009cc41b1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -385,8 +385,58 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum.set_immutable() return sum - def two_sum(self, other, *args): - raise NotImplementedError + def two_sum(first_mat, second_mat, column, row): + r""" + Return the 2-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with column index of the first matrix ``column`` and row index of the second matrix ``row``. + Suppose that ``column`` indicates the last column and ``row`` indicates the first row, i.e, the first matrix is `M_1=\begin{bmatrix} A & a\end{bmatrix}` and the second matrix is `M_2=\begin{bmatrix} b^T \\ B\end{bmatrix}`. Then the two sum `M_1 \oplus_2 M_2 =\begin{bmatrix}A & ab^T\\ 0 & B\end{bmatrix}`. + + INPUT: + + - ``first_mat`` -- the first integer matrix + - ``second_mat`` -- the second integer matrix + - ``column`` -- the column index of the first integer matrix + - ``row`` -- the row index of the first integer matrix + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 5, 6]]); M1 + [1 2 3] + [4 5 6] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[7, 8, 9], [-1, -2, -3]]); M2 + [ 7 8 9] + [-1 -2 -3] + sage: Matrix_cmr_chr_sparse.two_sum(M1,M2,2,0) + [ 1 2|21 24 27] + [ 4 5|42 48 54] + [-----+--------] + [ 0 0|-1 -2 -3] + sage: M1.two_sum(M2,1,1) + [ 1 3| -2 -4 -6] + [ 4 6| -5 -10 -15] + [-------+-----------] + [ 0 0| 7 8 9] + """ + cdef Matrix_cmr_chr_sparse sum, first, second + cdef CMR_CHRMAT *sum_mat + first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) + second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) + if column < 0 or column >= first._mat.numColumns: + raise ValueError("First marker should be a column index of the first matrix") + if row < 0 or row >= second._mat.numRows: + raise ValueError("Second marker should be a row index of the second matrix") + row_subdivision = [] + column_subdivision = [] + row_subdivision.append(first._mat.numRows) + column_subdivision.append(first._mat.numColumns - 1) + CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, CMRcolumnToElement(column), CMRrowToElement(row), &sum_mat)) + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) + if row_subdivision or column_subdivision: + sum.subdivide(row_subdivision, column_subdivision) + sum.set_immutable() + return sum def three_sum(self, other, *args): raise NotImplementedError @@ -793,7 +843,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ╭OneSumNode with 2 children─╮ │ │ SeriesParallelReductionNode UnknownNode - │ + │ ThreeConnectedIrregularNode sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) From dacaa75307f88ca371141eaef6803723ff9fc101 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jul 2023 20:18:27 -0700 Subject: [PATCH 053/262] src/sage/matrix/matrix_cmr_sparse.pyx: Mark doctest with incomplete decomposition tree 'random' --- src/sage/matrix/matrix_cmr_sparse.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 64009cc41b1..f5738c68605 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -839,7 +839,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: certificate=True) sage: result, certificate (False, (OneSumNode with 2 children, NotImplemented)) - sage: unicode_art(certificate[0]) + sage: certificate[0].summands()[0].parent_rows_and_columns() + ((0, 1, 2), (0, 4, 5, 6, 2, 3, 1)) + sage: certificate[0].summands()[1].parent_rows_and_columns() + ((3, 4, 5), (7, 11, 12, 13, 9, 10, 8)) + sage: unicode_art(certificate[0]) # random (whether the left or the right branch has been followed) ╭OneSumNode with 2 children─╮ │ │ SeriesParallelReductionNode UnknownNode From 8eb2c5c1af26fe714049f5b153bb358cc8bc922b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jul 2023 21:17:27 -0700 Subject: [PATCH 054/262] sage.matrix.seymour_decomposition: Show dimensions in repr --- src/sage/matrix/matrix_cmr_sparse.pyx | 40 ++++++++++----------- src/sage/matrix/seymour_decomposition.pyx | 42 ++++++++++++++--------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index f5738c68605..ca97e16d0b3 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -838,27 +838,27 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True) sage: result, certificate - (False, (OneSumNode with 2 children, NotImplemented)) + (False, (OneSumNode (6×14) with 2 children, NotImplemented)) sage: certificate[0].summands()[0].parent_rows_and_columns() ((0, 1, 2), (0, 4, 5, 6, 2, 3, 1)) sage: certificate[0].summands()[1].parent_rows_and_columns() ((3, 4, 5), (7, 11, 12, 13, 9, 10, 8)) sage: unicode_art(certificate[0]) # random (whether the left or the right branch has been followed) - ╭OneSumNode with 2 children─╮ - │ │ - SeriesParallelReductionNode UnknownNode + ╭OneSumNode (6×14) with 2 children╮ + │ │ + SeriesParallelReductionNode (3×7) UnknownNode (3×7) │ - ThreeConnectedIrregularNode + ThreeConnectedIrregularNode (3×4) sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) sage: result, certificate - (False, (OneSumNode with 2 children, NotImplemented)) + (False, (OneSumNode (6×14) with 2 children, NotImplemented)) sage: unicode_art(certificate[0]) - ╭OneSumNode with 2 children─╮ - │ │ - SeriesParallelReductionNode SeriesParallelReductionNode - │ │ - ThreeConnectedIrregularNode ThreeConnectedIrregularNode + ╭OneSumNode (6×14) with 2 children╮ + │ │ + SeriesParallelReductionNode (3×7) SeriesParallelReductionNode (3×7) + │ │ + ThreeConnectedIrregularNode (3×4) ThreeConnectedIrregularNode (3×4) TESTS: @@ -879,20 +879,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) sage: result, certificate - (True, GraphicNode) + (True, GraphicNode (11×11)) sage: unicode_art(certificate) - GraphicNode + GraphicNode (11×11) sage: result, certificate = M._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True, ....: use_direct_graphicness_test=False) sage: result, certificate - (True, TwoSumNode with 2 children) + (True, TwoSumNode (11×11) with 2 children) sage: unicode_art(certificate) - ╭─────TwoSumNode with 2 children - │ │ - GraphicNode SeriesParallelReductionNode - │ - GraphicNode + ╭──────────TwoSumNode (11×11) with 2 children + │ │ + GraphicNode (7×8) SeriesParallelReductionNode (5×4) + │ + GraphicNode (4×4) """ cdef bool result cdef CMR_REGULAR_PARAMETERS params @@ -954,7 +954,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_totally_unimodular() True sage: M.is_totally_unimodular(certificate=True) - (True, GraphicNode) + (True, GraphicNode (3×2)) sage: MF = matroids.named_matroids.Fano(); MF Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 8e8661641bd..d67237bc619 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -31,6 +31,15 @@ cdef class DecompositionNode(SageObject): def __hash__(self): return self._dec + def nrows(self): + return CMRdecNumRows(self._dec) + + def ncols(self): + return CMRdecNumColumns(self._dec) + + def dimensions(self): + return self.nrows(), self.ncols() + @cached_method def matrix(self): r""" @@ -44,14 +53,14 @@ cdef class DecompositionNode(SageObject): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode) + (True, GraphicNode (3×2)) sage: certificate.matrix() is None True sage: result, certificate = M.is_totally_unimodular(certificate=True, ....: construct_matrices=True) sage: result, certificate - (True, GraphicNode) + (True, GraphicNode (3×2)) sage: certificate.matrix() [ 1 0] [-1 1] @@ -95,9 +104,9 @@ cdef class DecompositionNode(SageObject): sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, ....: construct_matrices=True) sage: result, certificate - (True, OneSumNode with 2 children) + (True, OneSumNode (6×4) with 2 children) sage: C = certificate.summands(); C - (GraphicNode, GraphicNode) + (GraphicNode (3×2), GraphicNode (3×2)) sage: C[0].parent_rows_and_columns() ((0, 1, 2), (0, 1)) sage: C[1].parent_rows_and_columns() @@ -133,11 +142,11 @@ cdef class DecompositionNode(SageObject): sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, ....: construct_matrices=True) sage: T = certificate.as_ordered_tree(); T - OneSumNode with 2 children[GraphicNode[], GraphicNode[]] + OneSumNode (6×4) with 2 children[GraphicNode (3×2)[], GraphicNode (3×2)[]] sage: unicode_art(T) - ╭─────OneSumNode with 2 children - │ │ - GraphicNode GraphicNode + ╭───────────OneSumNode (6×4) with 2 children + │ │ + GraphicNode (3×2) GraphicNode (3×2) """ from sage.combinat.ordered_tree import LabelledOrderedTree return LabelledOrderedTree([child.as_ordered_tree() for child in self._children()], @@ -185,16 +194,16 @@ cdef class DecompositionNode(SageObject): [ 0 0| 0 0| 1 0] [ 0 0| 0 0| 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate - OneSumNode with 4 children + OneSumNode (6×6) with 4 children sage: certificate._children() - (GraphicNode, GraphicNode, GraphicNode, GraphicNode) + (GraphicNode (2×2), GraphicNode (2×2), GraphicNode (1×1), GraphicNode (1×1)) sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 2, sparse=True), ....: [[1, 1], [-1, 0]]); M2 [ 1 1] [-1 0] sage: result, certificate = M2.is_totally_unimodular(certificate=True); certificate - GraphicNode + GraphicNode (2×2) sage: certificate._children() () """ @@ -204,7 +213,8 @@ cdef class DecompositionNode(SageObject): key=lambda node: node.parent_rows_and_columns())) def _repr_(self): - return f'{self.__class__.__name__}' + nrows, ncols = self.dimensions() + return f'{self.__class__.__name__} ({nrows}×{ncols})' def _unicode_art_(self): return self.as_ordered_tree()._unicode_art_() @@ -249,7 +259,7 @@ cdef class OneSumNode(SumNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], [[1, 1], [-1, 0]]) sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate - OneSumNode with 2 children + OneSumNode (4×4) with 2 children sage: certificate.summand_matrices() ( [ 1 0] [ 1 1] @@ -274,7 +284,7 @@ cdef class OneSumNode(SumNode): [ 0 0| 0 0| 1 0] [ 0 0| 0 0| 0 1] sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate - OneSumNode with 4 children + OneSumNode (6×6) with 4 children sage: certificate.summand_matrices() ( [ 1 0] [ 1 1] @@ -319,7 +329,7 @@ cdef class BaseGraphicNode(DecompositionNode): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode) + (True, GraphicNode (3×2)) sage: G = certificate.graph(); G Graph on 4 vertices sage: G.vertices(sort=True) @@ -342,7 +352,7 @@ cdef class BaseGraphicNode(DecompositionNode): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate - (True, GraphicNode) + (True, GraphicNode (3×2)) sage: certificate.forest_edges() ((1, 2), (7, 1)) """ From ad8f4bbdcf9c49c74b59d6711732032640ec6522 Mon Sep 17 00:00:00 2001 From: jsantillan3 <70868442+jsantillan3@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:01:36 -0700 Subject: [PATCH 055/262] Cmr three_sum and cographicnode (#10) Co-authored-by: J S --- src/sage/matrix/matrix_cmr_sparse.pyx | 174 +++++++++++++++++++++- src/sage/matrix/seymour_decomposition.pyx | 41 ++++- 2 files changed, 206 insertions(+), 9 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index ca97e16d0b3..e033097a9f0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -438,8 +438,132 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum.set_immutable() return sum - def three_sum(self, other, *args): - raise NotImplementedError + def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): + r""" + Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with 'first_col_index1' + and 'first_col_index2' being the indices of the column vectors of the matrix, which are identical except for one row + having a 0 in one column and the other a non-zero entry in that row. The method assumes the nonzero entry is one. The same assumptions + are made for 'second_mat' and its input index variables. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 0, -1, 0, 1], [1, 1, 0, -1, 1], [0, 0, 1, 1, 1], + ....: [1, 1, -1, 0, 0], [-1, -1, 0, 0,1]]); M1 + [ 1 0 -1 0 1] + [ 1 1 0 -1 1] + [ 0 0 1 1 1] + [ 1 1 -1 0 0] + [-1 -1 0 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0], + ....: [0, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 + [1 1 1 1 1] + [1 1 1 0 0] + [1 0 1 1 0] + [0 0 0 1 1] + [1 1 0 0 1] + sage: M3 = Matrix_cmr_chr_sparse.three_sum(M1, M2, 0, 1, 0, 1); M3 + [ 0 -1 1 1 1 0] + [ 1 1 1 0 0 0] + [-1 0 0 1 1 0] + [ 0 0 1 -1 -1 0] + [-1 0 1 1 1 1] + [-1 0 1 1 0 0] + [-1 0 1 0 1 1] + [ 1 0 -1 0 0 1] + """ + fc = len(first_mat.columns()) + sc = len(second_mat.columns()) + fr = len(first_mat.rows()) + sr = len(second_mat.rows()) + if any([fc < 3, sc < 3, fr < 2, sr < 2]): + raise ValueError('Some matrix is not large enough to perform a 3-sum') + if any([first_col_index1 >= fc, first_col_index2 >= fc, second_col_index1 >= sc, second_col_index2 >= sc]): + raise ValueError('Some column indicated exceeds its matrix size') + first_col1 = first_mat.columns()[first_col_index1] + first_col2 = first_mat.columns()[first_col_index2] + second_col1 = second_mat.columns()[second_col_index1] + second_col2 = second_mat.columns()[second_col_index2] + fir_nrows = range(fr) + sec_nrows = range(sr) + valid1 = False + valid2 = False + for i in fir_nrows: + if (first_col1[i] == 1 and first_col2[i] == 0) or (first_col1[i] == 0 and first_col2[i] == 1): + subcol1 = tuple(first_col1[k] for k in fir_nrows if k != i) + subcol2 = tuple(first_col2[k] for k in fir_nrows if k != i) + if subcol1 == subcol2: + valid1 = True + first_row_index = i + break + for i in sec_nrows: + if (second_col1[i] == 1 and second_col2[i] == 0) or (second_col1[i] == 0 and second_col2[i] == 1): + subcol1 = tuple(second_col1[k] for k in sec_nrows if k != i) + subcol2 = tuple(second_col2[k] for k in sec_nrows if k != i) + if subcol1 == subcol2: + valid2 = True + second_row_index = i + break + if not (valid1 and valid2): + raise ValueError('indicated columns of Matrices are not of appropriate form for 3-sum') + first_subcol = first_mat.delete_rows([first_row_index]).columns()[first_col_index1] + second_subcol = first_mat.delete_rows([second_row_index]).columns()[second_col_index1] + first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) + second_submat = second_mat.delete_columns([second_col_index1, second_col_index2]) + first_row = first_submat.rows()[first_row_index] + second_row = second_submat.rows()[second_row_index] + first_submat = first_submat.delete_rows([first_row_index]) + second_submat = second_submat.delete_rows([second_row_index]) + first_subrows = first_submat.rows() + second_subrows = second_submat.rows() + upper_right_rows = first_subcol.tensor_product(second_row).rows() + lower_left_rows = second_subcol.tensor_product(first_row).rows() + n1 = len(first_submat.rows()) + n2 = len(second_submat.rows()) + row_list = [] + for i in range(n1): + r = list(first_subrows[i]) + u = list(upper_right_rows[i]) + r.extend(u) + row_list.append(r) + for i in range(n2): + r = list(lower_left_rows[i]) + u = list(second_subrows[i]) + r.extend(u) + row_list.append(r) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) + + def delete_rows(self, indices): + rows = self.rows() + row_list = [] + n = len(rows) + for i in indices: + if i >= n: + raise ValueError('Found index greater than matrix size') + rows.pop(i) + for r in rows: + x = [] + for i in range(len(r)): + x.append(r[i]) + row_list.append(x) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) + + def delete_columns(self, indices): + rows = self.rows() + n = len(rows) + row_list = [] + for i in indices: + if i >= n: + raise ValueError('Found index greater than matrix size') + for r in rows: + x = [] + for k in range(len(r)): + if not (k in indices): + x.append(r[k]) + row_list.append(x) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) def is_unimodular(self): r""" @@ -718,7 +842,51 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD def is_cographic(self, *, time_limit=60.0, certificate=False): - raise NotImplementedError + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 9, sparse=True), [[1, 0, 0, 0, 1, -1, 1, 0, 0], + ....: [0, 1, 0, 0, 0, 1, -1, 1, 0], [0, 0, 1, 0, 0, 0, 1, -1, 1], + ....: [0, 0, 0, 1, 1, 0, 0, 1, -1]]); M + [ 1 0 0 0 1 -1 1 0 0] + [ 0 1 0 0 0 1 -1 1 0] + [ 0 0 1 0 0 0 1 -1 1] + [ 0 0 0 1 1 0 0 1 -1] + sage: M.is_cographic() + True + """ + cdef bool result + cdef CMR_GRAPH *graph = NULL + cdef CMR_GRAPH_EDGE* forest_edges = NULL + cdef CMR_GRAPH_EDGE* coforest_edges = NULL + cdef CMR_SUBMAT* submatrix = NULL + cdef CMR_GRAPHIC_STATISTICS stats + + sig_on() + try: + if certificate: + CMR_CALL(CMRtestCographicMatrix(cmr, self._mat, &result, &graph, &forest_edges, + &coforest_edges, &submatrix, &stats, time_limit)) + else: + CMR_CALL(CMRtestCographicMatrix(cmr, self._mat, &result, NULL, NULL, + NULL, NULL, &stats, time_limit)) + finally: + sig_off() + + if not certificate: + return result + + if result: + sage_graph = _sage_graph(graph) + sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) + for row in range(self.nrows())) + sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) + for column in range(self.ncols())) + return True, (sage_graph, sage_forest_edges, sage_coforest_edges) + + return False, NotImplemented # submatrix TBD + def is_network_matrix(self, *, time_limit=60.0, certificate=False): r""" diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d67237bc619..157441db07e 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -305,9 +305,33 @@ cdef class OneSumNode(SumNode): cdef class TwoSumNode(SumNode): - - pass + r""" + EXAMPLES:: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0] + ....: ,[1, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 + [1 1 1 1 1] + [1 1 1 0 0] + [1 0 1 1 0] + [1 0 0 1 1] + [1 1 0 0 1] + sage: M3 = Matrix_cmr_chr_sparse.two_sum(M2, M2, 0, 1); M3 + [1 1 1 1|1 1 1 0 0] + [1 1 0 0|1 1 1 0 0] + [0 1 1 0|1 1 1 0 0] + [0 0 1 1|1 1 1 0 0] + [1 0 0 1|1 1 1 0 0] + [-------+---------] + [0 0 0 0|1 1 1 1 1] + [0 0 0 0|1 0 1 1 0] + [0 0 0 0|1 0 0 1 1] + [0 0 0 0|1 1 0 0 1] + sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate + TwoSumNode (9×9) with 2 children + """ + pass cdef class ThreeSumNode(SumNode): @@ -375,13 +399,18 @@ cdef class GraphicNode(BaseGraphicNode): cdef class CographicNode(BaseGraphicNode): - - pass + @cached_method + def graph(self): + r""" + Actually the cograph of matrix, in the case where it is not graphic. + """ + return _sage_graph(CMRdecCograph(self._dec)) cdef class PlanarNode(BaseGraphicNode): - - pass + @cached_method + def cograph(self): + return _sage_graph(CMRdecCograph(self._dec)) cdef class SeriesParallelReductionNode(DecompositionNode): From 0bf6b5c3965c9b8850da4e1af4bd62a2975c6b5f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 12:10:52 -0700 Subject: [PATCH 056/262] src/sage/matrix/seymour_decomposition.pyx: Fix doctests --- src/sage/matrix/seymour_decomposition.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 157441db07e..87611f3d7b4 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -309,9 +309,9 @@ cdef class TwoSumNode(SumNode): EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0] - ....: ,[1, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0], + ....: [1, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 [1 1 1 1 1] [1 1 1 0 0] [1 0 1 1 0] From dae01205e4df419a2b60ae43e2674f5f5d5dca53 Mon Sep 17 00:00:00 2001 From: jsantillan3 <70868442+jsantillan3@users.noreply.github.com> Date: Sat, 12 Aug 2023 13:40:54 -0700 Subject: [PATCH 057/262] three_sum (#11) --- src/sage/matrix/matrix_cmr_sparse.pyx | 44 +++++++++++------------ src/sage/matrix/seymour_decomposition.pyx | 12 +++++-- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e033097a9f0..fa970fb7950 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -444,35 +444,27 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): and 'first_col_index2' being the indices of the column vectors of the matrix, which are identical except for one row having a 0 in one column and the other a non-zero entry in that row. The method assumes the nonzero entry is one. The same assumptions are made for 'second_mat' and its input index variables. - + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 0, -1, 0, 1], [1, 1, 0, -1, 1], [0, 0, 1, 1, 1], - ....: [1, 1, -1, 0, 0], [-1, -1, 0, 0,1]]); M1 - [ 1 0 -1 0 1] - [ 1 1 0 -1 1] - [ 0 0 1 1 1] - [ 1 1 -1 0 0] - [-1 -1 0 0 1] - sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0], - ....: [0, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 + ....: [0, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M [1 1 1 1 1] [1 1 1 0 0] [1 0 1 1 0] [0 0 0 1 1] [1 1 0 0 1] - sage: M3 = Matrix_cmr_chr_sparse.three_sum(M1, M2, 0, 1, 0, 1); M3 - [ 0 -1 1 1 1 0] - [ 1 1 1 0 0 0] - [-1 0 0 1 1 0] - [ 0 0 1 -1 -1 0] - [-1 0 1 1 1 1] - [-1 0 1 1 0 0] - [-1 0 1 0 1 1] - [ 1 0 -1 0 0 1] + sage: M3 = Matrix_cmr_chr_sparse.three_sum(M, M, 0, 1, 0, 1); M3 + [1 1 1 1 1 0] + [1 0 0 1 1 0] + [0 1 1 0 0 0] + [0 0 1 1 1 0] + [1 1 0 1 1 1] + [1 1 0 1 0 0] + [0 0 0 0 1 1] + [1 1 0 0 0 1] """ fc = len(first_mat.columns()) sc = len(second_mat.columns()) @@ -496,7 +488,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): subcol2 = tuple(first_col2[k] for k in fir_nrows if k != i) if subcol1 == subcol2: valid1 = True - first_row_index = i + if i == fr: + first_row_index = i - 1 + else: + first_row_index = i break for i in sec_nrows: if (second_col1[i] == 1 and second_col2[i] == 0) or (second_col1[i] == 0 and second_col2[i] == 1): @@ -504,7 +499,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): subcol2 = tuple(second_col2[k] for k in sec_nrows if k != i) if subcol1 == subcol2: valid2 = True - second_row_index = i + if i == sr: + second_row_index = i - 1 + else: + second_row_index = i break if not (valid1 and valid2): raise ValueError('indicated columns of Matrices are not of appropriate form for 3-sum') @@ -533,7 +531,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): u = list(second_subrows[i]) r.extend(u) row_list.append(r) - return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def delete_rows(self, indices): rows = self.rows() diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 87611f3d7b4..58d2b2a5279 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -331,11 +331,17 @@ cdef class TwoSumNode(SumNode): sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate TwoSumNode (9×9) with 2 children """ - pass + def block_matrix_form(self): + M1, M2 = self.summand_matrices() + x, y= len(M1.columns()), len(M2.rows()) + return Matrix_cmr_chr_sparse.two_sum(M1, M2, x - 1, y - 1) cdef class ThreeSumNode(SumNode): - pass + def block_matrix_form(self): + M1, M2 = self.summand_matrices() + x, y= len(M1.columns()), len(M2.columns()) + return Matrix_cmr_chr_sparse.two_sum(M1, M2, x - 1, x-2, y - 1, y - 2) cdef class BaseGraphicNode(DecompositionNode): @@ -421,7 +427,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): cdef class SpecialLeafNode(DecompositionNode): @cached_method - def matroid(self): + def _matroid(self): r""" """ From 0961a0b217d36bfc5de271a9f825bc7e2eb50db7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 12 Aug 2023 17:30:09 -0700 Subject: [PATCH 058/262] Add documentation, copyright headers --- src/sage/matrix/matrix_cmr_sparse.pyx | 82 ++++++++++++++++++++--- src/sage/matrix/seymour_decomposition.pyx | 19 ++++++ 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index fa970fb7950..7a52e6013a6 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -3,6 +3,18 @@ r""" Sparse Matrices with CMR """ +# **************************************************************************** +# Copyright (C) 2023 Matthias Koeppe +# 2023 Luze Xu +# 2023 Javier Santillan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from libc.stdint cimport SIZE_MAX from cysignals.signals cimport sig_on, sig_off @@ -21,6 +33,14 @@ from .seymour_decomposition cimport create_DecompositionNode cdef class Matrix_cmr_sparse(Matrix_sparse): r""" Base class for sparse matrices implemented in CMR + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]) + sage: isinstance(M, Matrix_cmr_sparse) + True """ pass @@ -330,6 +350,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``summands`` -- integer matrices or data from which integer matrices can be constructed + The terminology "1-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_. + + .. SEEALSO:: :meth:`two_sum`, :meth:`three_sum` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -567,6 +592,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return whether ``self`` is a unimodular matrix. + A nonsingular square matrix `A` is called unimodular if it is integral + and has determinant `\pm1`, i.e., an element of + `\mathop{\operatorname{GL}}_n(\ZZ)` [Sch1986]_, Ch. 4.3. + + A rectangular matrix `A` of full row rank is called unimodular if it + is integral and every basis `B` of `A` has determinant `\pm1`. + [Sch1986]_, Ch. 19.1. + + More generally, a matrix `A` of rank `r` is called unimodular if it is + integral and for every submatrix `B` formed by `r` linearly independent columns, + the greatest common divisor of the determinants of all `r`-by-`r` + submatrices of `B` is `1`. [Sch1986]_, Ch. 21.4. + + .. SEEALSO:: :meth:`is_k_modular`, :meth:`is_strongly_unimodular`, :meth:`is_totally_unimodular` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -599,6 +639,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix is strongly unimodular if ``self`` and ``self.transpose()`` are both unimodular. + .. SEEALSO: meth:`is_unimodular`, :meth:`is_strongly_k_modular` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -632,8 +674,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return the integer `k` such that ``self`` is `k`-modular. - A matrix `M` of rank `r` is `k`-modular if the following two conditions are satisfied: - - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + A matrix `M` of rank `r` is `k`-modular if the following two conditions + are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the + determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. OUTPUT: @@ -641,6 +685,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``k``: ``self`` is `k`-modular - ``None``: ``self`` is not `k`-modular for any `k` + .. SEEALSO:: :meth:`is_k_modular`, :meth:`strong_modulus` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -675,8 +721,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return the integer `k` such that ``self`` is strongly `k`-modular. - A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: - - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + A matrix `M` of rank-`r` is `k`-modular if the following two conditions + are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the + determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. OUTPUT: @@ -684,6 +732,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``k``: ``self`` is `k`-modular - ``None``: ``self`` is not `k`-modular for any `k` + .. SEEALSO:: :meth:`is_strongly_k_modular`, :meth:`modulus` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -718,11 +768,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return whether ``self`` is `k`-modular. - A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: - - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + A matrix `M` of rank-`r` is `k`-modular if the following two conditions + are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the + determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. - If the matrix has full row rank, it is `k`-modular if all the full rank minor of the matrix has determinant `0,\pm k`. - The matrix is also called strictly `k`-modular. + + If the matrix has full row rank, it is `k`-modular if every full rank minor + of the matrix has determinant `0,\pm k`. + + .. NOTE:: + + In parts of the literature, a matrix with the above properties + is called *strictly* `k`-modular. + + .. SEEALSO:: :meth:`is_unimodular`, :meth:`is_strongly_k_modular`, :meth:`_modulus` EXAMPLES:: @@ -755,6 +815,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix is strongly `k`-modular if ``self`` and ``self.transpose()`` are both `k`-modular. + .. SEEALSO:: :meth:`is_k_modular`, :meth:`is_strongly_unimodular`, :meth:`strong_modulus` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1105,9 +1167,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" Return whether ``self`` is a totally unimodular matrix. + A matrix is totally unimodular if every subdeterminant is `0`, `1`, or `-1`. + REFERENCES: - - [Sch1986]_ + - [Sch1986]_, Chapter 19 EXAMPLES:: diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 58d2b2a5279..44ae44d2b30 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -3,6 +3,17 @@ r""" Seymour's decomposition of totally unimodular matrices and regular matroids """ +# **************************************************************************** +# Copyright (C) 2023 Matthias Koeppe +# 2023 Javier Santillan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.libs.cmr.cmr cimport * from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ @@ -13,6 +24,9 @@ from .matrix_space import MatrixSpace cdef class DecompositionNode(SageObject): + r""" + Base class for nodes in Seymour's decomposition + """ def __cinit__(self): self._dec = NULL @@ -154,6 +168,8 @@ cdef class DecompositionNode(SageObject): def plot(self, **kwds): r""" + Plot the decomposition tree rooted at ``self``. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -233,6 +249,9 @@ cdef class UnknownNode(DecompositionNode): cdef class SumNode(DecompositionNode): + r""" + Base class for 1-sum, 2-sum, and 3-sum nodes in Seympur's decomposition + """ def _repr_(self): result = super()._repr_() From 569f679d6867e009a3439676af9bb3c3a37c5f02 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 12 Aug 2023 19:24:38 -0700 Subject: [PATCH 059/262] src/doc/en/reference/references/index.rst: Add Sey1980 --- src/doc/en/reference/references/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 626b954538a..47038ce2a15 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -5910,7 +5910,10 @@ REFERENCES: spaces* in Scientific contributions in honor of Mirian Andrés Gómez, pp 507-519, Univ. La Rioja Serv. Publ., Logroño (2010). -.. [Sey1981] \P. D. Seymour, Nowhere-zero 6-flows, J. Comb. Theory Ser B, +.. [Sey1980] \P. D. Seymour, *Decomposition of regular matroids*, + J. Comb. Theory Ser B, 28 (1980), 305-359. + +.. [Sey1981] \P. D. Seymour, *Nowhere-zero 6-flows*, J. Comb. Theory Ser B, 30 (1981), 130-135. :doi:`10.1016/0095-8956(81)90058-7` .. [SH1995] \C. P. Schnorr and H. H. Hörner. *Attacking the From 090f7f202fbf2851d087f70cce7a0cd72c50b97a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Feb 2024 09:45:37 -0800 Subject: [PATCH 060/262] (Temporarily) add new modules to doc # Conflicts: # build/pkgs/sagelib/dependencies --- build/pkgs/sagelib/dependencies | 2 +- src/doc/en/reference/matrices/index.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build/pkgs/sagelib/dependencies b/build/pkgs/sagelib/dependencies index c468418099f..c738b0072d4 100644 --- a/build/pkgs/sagelib/dependencies +++ b/build/pkgs/sagelib/dependencies @@ -1,4 +1,4 @@ -FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cmr cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran +FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf sagemath_cmr singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran ---------- All lines of this file are ignored except the first. diff --git a/src/doc/en/reference/matrices/index.rst b/src/doc/en/reference/matrices/index.rst index 889a33bd717..e928bcf87fe 100644 --- a/src/doc/en/reference/matrices/index.rst +++ b/src/doc/en/reference/matrices/index.rst @@ -85,6 +85,7 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/matrix_polynomial_dense sage/matrix/matrix_mpolynomial_dense sage/matrix/matrix_cyclo_dense + sage/matrix/matrix_cmr_sparse sage/matrix/operation_table @@ -98,6 +99,7 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/misc_flint sage/matrix/symplectic_basis sage/matrix/compute_J_ideal + sage/matrix/seymour_decomposition sage/matrix/benchmark From 71443f5dafa1d5fbbbd89139eb5dcf0dffd7916b Mon Sep 17 00:00:00 2001 From: jsantillan3 <70868442+jsantillan3@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:00:05 -0700 Subject: [PATCH 061/262] SeriesParallelReductionNode.core, SpecialLeafNode.rep_matrix: New; Matrix_cmr_chr_sparse.three_sum: Add doc (#13) --- src/sage/matrix/matrix_cmr_sparse.pyx | 29 +++++++++++++++--- src/sage/matrix/seymour_decomposition.pyx | 37 +++++++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 7a52e6013a6..4e9f13324af 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -465,10 +465,31 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" - Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with 'first_col_index1' - and 'first_col_index2' being the indices of the column vectors of the matrix, which are identical except for one row - having a 0 in one column and the other a non-zero entry in that row. The method assumes the nonzero entry is one. The same assumptions - are made for 'second_mat' and its input index variables. + Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with ``first_col_index1`` + and ``first_col_index2`` being the indices of the column vectors of the matrix, which are identical except for one row + having a 0 in one column and the other a non-zero entry in that row. The method assumes the nonzero entry is one. The same goes + are made for ``second_mat``, ``second_col_index1``, and ``second_col_index2``. + + The operation performed is effectively as in Schrijver:= + [first_submat first_subcol first_subcol] ___|___ [second_submat second_subcol second_suncol] + [ first_row 0 1 ] | 3 [ second_row 0 1 ] + ----- [ first_submat first_subcol x second_row] + ----- [second_subcol x first_row second_subcol ] + + INPUT: + + - ``first_mat`` -- integer matrix having two collumns which are identical in every entry except for one row in + which one is 0 and the other is 1 + - ``second_mat`` -- integer matrix having two collumns which are identical in every entry except for one row in + which one is 0 and the other is 1 + - ``first_col_index1`` -- index of a column in ``first_mat`` identical to some other column in every entry except for one row in + which one is 0 and the other is 1 + - ``first_col_index2`` -- index of the other column which is identical to first_mat[first_col_index1] in every entry except for one + row in which one is 0 and the other is 1 + - ``second_col_index1`` -- index of a column in ``second_mat`` identical to some other column in every entry except for one row in + which one is 0 and the other is 1 + - ``first_col_index2`` -- index of the other column which is identical to second_mat[second_col_index1] in every entry except for one + row in which one is 0 and the other is 1 EXAMPLES:: diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 44ae44d2b30..a727e000857 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -440,7 +440,31 @@ cdef class PlanarNode(BaseGraphicNode): cdef class SeriesParallelReductionNode(DecompositionNode): - pass + def core(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 1, 1, 1, 0], [1, 1, 1, 0,0, 0], + ....: [1, 0, 1, 1, 0, 1] ,[1, 0,0, 1, 1, 0], + ....: [1, 1, 0, 0, 1, 0]]); M + [1 1 1 1 1 0] + [1 1 1 0 0 0] + [1 0 1 1 0 1] + [1 0 0 1 1 0] + [1 1 0 0 1 0] + sage: result, certificate = M.is_totally_unimodular(certificate = True); result + ....: , certificate + (True, SeriesParallelReductionNode (5×6)) + sage: certificate.core() + [1 1 1 1 1] + [1 1 1 0 0] + [1 0 1 1 0] + [1 0 0 1 1] + [1 1 0 0 1] + """ + return self._children()[0].matrix() cdef class SpecialLeafNode(DecompositionNode): @@ -475,8 +499,17 @@ cdef class SpecialLeafNode(DecompositionNode): assert False, 'special leaf node with unknown type' def _repr_(self): - return f'Minor isomorphic to {self._matroid()}' + return f'Isomorphic to a minor of {self._matroid()}' + + def rep_matrix(self): + r""" + WIP + """ + assert NotImplementedError + cdef int representation_matrix + cdef CMR_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef _class(CMR_DEC *dec): k = CMRdecIsSum(dec, NULL, NULL) From f68fd9d71f074834737ea67b442e4d53386c307d Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 15 Nov 2023 09:41:09 -0800 Subject: [PATCH 062/262] fix doctests --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- src/sage/matrix/seymour_decomposition.pyx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4e9f13324af..101a8c947b0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -36,7 +36,7 @@ cdef class Matrix_cmr_sparse(Matrix_sparse): EXAMPLES:: - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_sparse, Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 2, 3], [4, 0, 6]]) sage: isinstance(M, Matrix_cmr_sparse) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index a727e000857..a79b47be32e 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -454,8 +454,8 @@ cdef class SeriesParallelReductionNode(DecompositionNode): [1 0 1 1 0 1] [1 0 0 1 1 0] [1 1 0 0 1 0] - sage: result, certificate = M.is_totally_unimodular(certificate = True); result - ....: , certificate + sage: result, certificate = M.is_totally_unimodular(certificate = True) + sage: result, certificate (True, SeriesParallelReductionNode (5×6)) sage: certificate.core() [1 1 1 1 1] From 753266b6ffeb3cb531c84dc911fb21b392ea2e60 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 15 Nov 2023 11:46:47 -0800 Subject: [PATCH 063/262] fix doc style --- src/sage/matrix/matrix_cmr_sparse.pyx | 74 +++++++++++++---------- src/sage/matrix/seymour_decomposition.pyx | 13 ++-- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 101a8c947b0..bfc5937976e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -412,8 +412,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def two_sum(first_mat, second_mat, column, row): r""" - Return the 2-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with column index of the first matrix ``column`` and row index of the second matrix ``row``. - Suppose that ``column`` indicates the last column and ``row`` indicates the first row, i.e, the first matrix is `M_1=\begin{bmatrix} A & a\end{bmatrix}` and the second matrix is `M_2=\begin{bmatrix} b^T \\ B\end{bmatrix}`. Then the two sum `M_1 \oplus_2 M_2 =\begin{bmatrix}A & ab^T\\ 0 & B\end{bmatrix}`. + Return the 2-sum matrix constructed from the given matrices ``first_mat`` and + ``second_mat``, with column index of the first matrix ``column`` and row index + of the second matrix ``row``. + Suppose that ``column`` indicates the last column and ``row`` indicates the + first row, i.e, the first matrix is `M_1=\begin{bmatrix} A & a\end{bmatrix}` + and the second matrix is `M_2=\begin{bmatrix} b^T \\ B\end{bmatrix}`. Then + the two sum `M_1 \oplus_2 M_2 =\begin{bmatrix}A & ab^T\\ 0 & B\end{bmatrix}`. INPUT: @@ -465,38 +470,42 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" - Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with ``first_col_index1`` - and ``first_col_index2`` being the indices of the column vectors of the matrix, which are identical except for one row - having a 0 in one column and the other a non-zero entry in that row. The method assumes the nonzero entry is one. The same goes - are made for ``second_mat``, ``second_col_index1``, and ``second_col_index2``. - - The operation performed is effectively as in Schrijver:= - [first_submat first_subcol first_subcol] ___|___ [second_submat second_subcol second_suncol] - [ first_row 0 1 ] | 3 [ second_row 0 1 ] - ----- [ first_submat first_subcol x second_row] - ----- [second_subcol x first_row second_subcol ] + Return the 3-sum matrix constructed from the given matrices ``first_mat`` and + ``second_mat``, with ``first_col_index1`` and ``first_col_index2`` being the + indices of the column vectors of the matrix, which are identical except for + one row having a 0 in one column and the other a non-zero entry in that row. + The method assumes the nonzero entry is one. The same goes are made for ``second_mat``, ``second_col_index1``, and ``second_col_index2``. + + The operation is defined in [Sch1986]_, Ch. 19.4.:= + [first_mat first_col first_col] ___|___ [second_mat second_col second_col] + [first_row 0 1 ] | 3 [second_row 0 1 ] + ----- [ first_mat first_col x second_row] + ----- [second_col x first_row second_col ] INPUT: - - ``first_mat`` -- integer matrix having two collumns which are identical in every entry except for one row in - which one is 0 and the other is 1 - - ``second_mat`` -- integer matrix having two collumns which are identical in every entry except for one row in - which one is 0 and the other is 1 - - ``first_col_index1`` -- index of a column in ``first_mat`` identical to some other column in every entry except for one row in - which one is 0 and the other is 1 - - ``first_col_index2`` -- index of the other column which is identical to first_mat[first_col_index1] in every entry except for one - row in which one is 0 and the other is 1 - - ``second_col_index1`` -- index of a column in ``second_mat`` identical to some other column in every entry except for one row in - which one is 0 and the other is 1 - - ``first_col_index2`` -- index of the other column which is identical to second_mat[second_col_index1] in every entry except for one - row in which one is 0 and the other is 1 + - ``first_mat`` -- integer matrix having two collumns which are identical in + every entry except for one row in which one is 0 and the other is 1 + - ``second_mat`` -- integer matrix having two collumns which are identical in + every entry except for one row in which one is 0 and the other is 1 + - ``first_col_index1`` -- index of a column in ``first_mat`` identical to some + other column in every entry except for one row in which one is 0 and the other is 1 + - ``first_col_index2`` -- index of the other column which is identical to + first_mat[first_col_index1] in every entry except for one row in which + one is 0 and the other is 1 + - ``second_col_index1`` -- index of a column in ``second_mat`` identical to some + other column in every entry except for one row in which one is 0 and the other is 1 + - ``first_col_index2`` -- index of the other column which is identical to + second_mat[second_col_index1] in every entry except for one row in which + one is 0 and the other is 1 EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0], - ....: [0, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M + ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], + ....: [1, 0, 1, 1, 0], [0, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1]]); M [1 1 1 1 1] [1 1 1 0 0] [1 0 1 1 0] @@ -592,7 +601,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): for i in range(len(r)): x.append(r[i]) row_list.append(x) - return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def delete_columns(self, indices): rows = self.rows() @@ -607,7 +616,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not (k in indices): x.append(r[k]) row_list.append(x) - return Matrix_cmr_chr_sparse._from_data(row_list, immutable = False) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def is_unimodular(self): r""" @@ -927,9 +936,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 9, sparse=True), [[1, 0, 0, 0, 1, -1, 1, 0, 0], - ....: [0, 1, 0, 0, 0, 1, -1, 1, 0], [0, 0, 1, 0, 0, 0, 1, -1, 1], - ....: [0, 0, 0, 1, 1, 0, 0, 1, -1]]); M + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 9, sparse=True), + ....: [[1, 0, 0, 0, 1, -1, 1, 0, 0], + ....: [0, 1, 0, 0, 0, 1, -1, 1, 0], + ....: [0, 0, 1, 0, 0, 0, 1, -1, 1], + ....: [0, 0, 0, 1, 1, 0, 0, 1, -1]]); M [ 1 0 0 0 1 -1 1 0 0] [ 0 1 0 0 0 1 -1 1 0] [ 0 0 1 0 0 0 1 -1 1] @@ -968,7 +979,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD - def is_network_matrix(self, *, time_limit=60.0, certificate=False): r""" EXAMPLES: diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index a79b47be32e..fa807c0a301 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -329,8 +329,9 @@ cdef class TwoSumNode(SumNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 1, 0], - ....: [1, 0, 0, 1, 1], [1, 1, 0, 0, 1]]); M2 + ....: [[1, 1, 1, 1, 1], [1, 1, 1, 0, 0], + ....: [1, 0, 1, 1, 0], [1, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1]]); M2 [1 1 1 1 1] [1 1 1 0 0] [1 0 1 1 0] @@ -446,15 +447,15 @@ cdef class SeriesParallelReductionNode(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), - ....: [[1, 1, 1, 1, 1, 0], [1, 1, 1, 0,0, 0], - ....: [1, 0, 1, 1, 0, 1] ,[1, 0,0, 1, 1, 0], - ....: [1, 1, 0, 0, 1, 0]]); M + ....: [[1, 1, 1, 1, 1, 0], [1, 1, 1, 0, 0, 0], + ....: [1, 0, 1, 1, 0, 1] ,[1, 0, 0, 1, 1, 0], + ....: [1, 1, 0, 0, 1, 0]]); M [1 1 1 1 1 0] [1 1 1 0 0 0] [1 0 1 1 0 1] [1 0 0 1 1 0] [1 1 0 0 1 0] - sage: result, certificate = M.is_totally_unimodular(certificate = True) + sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate (True, SeriesParallelReductionNode (5×6)) sage: certificate.core() From 05301e6536f333f31fa3538573927dba91957ef9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Nov 2023 17:23:40 -0800 Subject: [PATCH 064/262] pkgs/sagemath-cmr/pyproject.toml.m4: Move metadata here from setup.cfg.m4 --- pkgs/sagemath-cmr/pyproject.toml.m4 | 26 +++++++++++++++++++++++++- pkgs/sagemath-cmr/setup.cfg.m4 | 17 ----------------- 2 files changed, 25 insertions(+), 18 deletions(-) delete mode 100644 pkgs/sagemath-cmr/setup.cfg.m4 diff --git a/pkgs/sagemath-cmr/pyproject.toml.m4 b/pkgs/sagemath-cmr/pyproject.toml.m4 index 439482ad26b..0997ef4b021 100644 --- a/pkgs/sagemath-cmr/pyproject.toml.m4 +++ b/pkgs/sagemath-cmr/pyproject.toml.m4 @@ -2,7 +2,7 @@ include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - SPKG_INSTALL_REQUIRES_setuptools + SPKG_INSTALL_REQUIRES_setuptools_wheel SPKG_INSTALL_REQUIRES_sage_conf SPKG_INSTALL_REQUIRES_sage_setup SPKG_INSTALL_REQUIRES_sagemath_environment @@ -10,3 +10,27 @@ requires = [ SPKG_INSTALL_REQUIRES_cysignals ] build-backend = "setuptools.build_meta" + +[project] +name = "sagemath-cmr" +description = "Sage: Open Source Mathematics Software: Combinatorial matrix recognition" +dependencies = [ + SPKG_INSTALL_REQUIRES_cysignals +] +dynamic = ["version"] +include(`pyproject_toml_metadata.m4')dnl' + +[project.optional-dependencies] +test = [ + SPKG_INSTALL_REQUIRES_sagemath_repl +] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[tool.setuptools] +include-package-data = false + +[tool.setuptools.dynamic] +version = {file = ["VERSION.txt"]} diff --git a/pkgs/sagemath-cmr/setup.cfg.m4 b/pkgs/sagemath-cmr/setup.cfg.m4 deleted file mode 100644 index c98706e36a3..00000000000 --- a/pkgs/sagemath-cmr/setup.cfg.m4 +++ /dev/null @@ -1,17 +0,0 @@ -include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- -[metadata] -name = sagemath-cmr -version = file: VERSION.txt -description = Sage: Open Source Mathematics Software: Combinatorial matrix recognition -long_description = file: README.rst -long_description_content_type = text/x-rst -include(`setup_cfg_metadata.m4')dnl' - -[options] -python_requires = >=3.8, <3.12 -install_requires = - SPKG_INSTALL_REQUIRES_cysignals - -[options.extras_require] -test = - SPKG_INSTALL_REQUIRES_sagemath_repl From 94da10f22fd7dae8db9378c6fc2e1c504142b5ab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Nov 2023 17:29:24 -0800 Subject: [PATCH 065/262] build/pkgs/cmr: Update to 66a4f9dc17b514f6bdd5bceff41da3bbddb0d119 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 34d09174321..6d522a163f7 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=ce7144e575a0fad0a6a4e63314ede9ceb42afbe6 -md5=b787470dfb83972a5379b42ed106fe59 -cksum=1569961839 +sha1=64391922ef751fb4b2a7bd955abeb8f94ef9f2f1 +md5=277fb87cda55e6e4a92a9fc362ad9fe4 +cksum=2241272713 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 14328d3675c..ef4eb55632d 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -36559106dfdd155e096b88bee3949ed58c53458e.p1 +66a4f9dc17b514f6bdd5bceff41da3bbddb0d119 From ac3713571b75c0d76c3163bf6d1de8c2210a6e99 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Nov 2023 17:30:26 -0800 Subject: [PATCH 066/262] build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch: Remove (upstreamed) --- .../CMRdecNumColumns_Rows_return_type.patch | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch diff --git a/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch b/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch deleted file mode 100644 index 4dbb06b68de..00000000000 --- a/build/pkgs/cmr/patches/CMRdecNumColumns_Rows_return_type.patch +++ /dev/null @@ -1,50 +0,0 @@ -commit 65bee3c428dd7b64ca93b29b008d4c8fa7364691 -Author: Matthias Koeppe -Date: Mon Jul 24 22:24:27 2023 -0700 - - dec.{h,c} (CMRdecNum{Columns,Rows}): Fix return type - -diff --git a/include/cmr/dec.h b/include/cmr/dec.h -index ab97d2a..20be1dd 100644 ---- a/include/cmr/dec.h -+++ b/include/cmr/dec.h -@@ -211,7 +211,7 @@ bool CMRdecIsUnknown( - */ - - CMR_EXPORT --bool CMRdecNumRows( -+size_t CMRdecNumRows( - CMR_DEC* dec /**< Decomposition. */ - ); - -@@ -238,7 +238,7 @@ size_t* CMRdecRowsParent( - */ - - CMR_EXPORT --bool CMRdecNumColumns( -+size_t CMRdecNumColumns( - CMR_DEC* dec /**< Decomposition. */ - ); - -diff --git a/src/cmr/dec.c b/src/cmr/dec.c -index 35fd196..3582c0f 100644 ---- a/src/cmr/dec.c -+++ b/src/cmr/dec.c -@@ -182,7 +182,7 @@ bool CMRdecIsUnknown(CMR_DEC* dec) - return dec->type == CMR_DEC_UNKNOWN; - } - --bool CMRdecNumRows(CMR_DEC* dec) -+size_t CMRdecNumRows(CMR_DEC* dec) - { - assert(dec); - -@@ -196,7 +196,7 @@ size_t* CMRdecRowsParent(CMR_DEC* dec) - return dec->rowsParent; - } - --bool CMRdecNumColumns(CMR_DEC* dec) -+size_t CMRdecNumColumns(CMR_DEC* dec) - { - assert(dec); - From 6e2efb7b0ea2bbabc22874d5fdc4db31a4785cdf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Nov 2023 19:45:58 -0800 Subject: [PATCH 067/262] src/sage/matrix/matrix_cmr_sparse.pyx: Fix markup --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index bfc5937976e..410646d7fe0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -669,7 +669,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix is strongly unimodular if ``self`` and ``self.transpose()`` are both unimodular. - .. SEEALSO: meth:`is_unimodular`, :meth:`is_strongly_k_modular` + .. SEEALSO:: meth:`is_unimodular`, :meth:`is_strongly_k_modular` EXAMPLES:: From d8a2f7a1c14b74db80ea5d22e8f80a8a1569e1c6 Mon Sep 17 00:00:00 2001 From: Matthias Walter Date: Fri, 1 Dec 2023 00:54:54 +0100 Subject: [PATCH 068/262] Run ctest once more with more detailed output. (#21) --- build/pkgs/cmr/spkg-check.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/cmr/spkg-check.in b/build/pkgs/cmr/spkg-check.in index 35f1999505d..d55199a4e91 100644 --- a/build/pkgs/cmr/spkg-check.in +++ b/build/pkgs/cmr/spkg-check.in @@ -1,3 +1,4 @@ cd src cd build ctest +ctest --rerun-failed --output-on-failure From eb6f69c0df50a78b21cb829ea6b829ef44855a33 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Dec 2023 11:38:09 -0800 Subject: [PATCH 069/262] build/pkgs/cmr/dependencies: Remove boost --- build/pkgs/cmr/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cmr/dependencies b/build/pkgs/cmr/dependencies index 2443b003eb1..8e2118051ff 100644 --- a/build/pkgs/cmr/dependencies +++ b/build/pkgs/cmr/dependencies @@ -1 +1 @@ -googletest boost_cropped +googletest From 553b14dee500afe2a81360e52c675bcda2e3e967 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Dec 2023 11:39:14 -0800 Subject: [PATCH 070/262] build/pkgs/cmr: Update to de04ca6f36f81044731360cf336057e77ec60d46 (merge of https://github.com/discopt/cmr/pull/52) --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 6d522a163f7..9c9bfecf536 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=64391922ef751fb4b2a7bd955abeb8f94ef9f2f1 -md5=277fb87cda55e6e4a92a9fc362ad9fe4 -cksum=2241272713 +sha1=f434e3042942bb794826ebd1e10ee8460e16f6b5 +md5=435722c49ab9b87ab6c234e869f27cc9 +cksum=3577442237 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index ef4eb55632d..1362a805b78 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -66a4f9dc17b514f6bdd5bceff41da3bbddb0d119 +de04ca6f36f81044731360cf336057e77ec60d46 From e9e2a6df085b1da51716d7d1e713f4cde4c463ab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Dec 2023 13:28:03 -0800 Subject: [PATCH 071/262] src/sage/libs/cmr/cmr.pxd: CMR_*_STATISTICS now use uint32_t --- src/sage/libs/cmr/cmr.pxd | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index a53b7f40eaa..a276c9f8133 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -71,7 +71,7 @@ cdef extern from "cmr/k_modular.h": cdef extern from "cmr/camion.h": ctypedef struct CMR_CAMION_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime CMR_ERROR CMRstatsCamionInit(CMR_CAMION_STATISTICS* stats) @@ -190,13 +190,13 @@ cdef extern from "cmr/graph.h": cdef extern from "cmr/graphic.h": ctypedef struct CMR_GRAPHIC_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime - size_t checkCount + uint32_t checkCount double checkTime - size_t applyCount + uint32_t applyCount double applyTime - size_t transposeCount + uint32_t transposeCount double transposeTime CMR_ERROR CMRstatsGraphicInit(CMR_GRAPHIC_STATISTICS* stats) @@ -209,13 +209,13 @@ cdef extern from "cmr/graphic.h": cdef extern from "cmr/series_parallel.h": ctypedef struct CMR_SP_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime - size_t reduceCount + uint32_t reduceCount double reduceTime - size_t wheelCount + uint32_t wheelCount double wheelTime - size_t nonbinaryCount + uint32_t nonbinaryCount double nonbinaryTime CMR_ERROR CMRstatsSeriesParallelInit(CMR_SP_STATISTICS* stats) @@ -243,7 +243,7 @@ cdef extern from "cmr/series_parallel.h": cdef extern from "cmr/network.h": ctypedef struct CMR_NETWORK_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime CMR_CAMION_STATISTICS camion CMR_GRAPHIC_STATISTICS graphic @@ -342,18 +342,18 @@ cdef extern from "cmr/regular.h": CMR_ERROR CMRparamsRegularInit(CMR_REGULAR_PARAMETERS* params) ctypedef struct CMR_REGULAR_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime CMR_SP_STATISTICS seriesParallel CMR_GRAPHIC_STATISTICS graphic CMR_NETWORK_STATISTICS network - size_t sequenceExtensionCount + uint32_t sequenceExtensionCount double sequenceExtensionTime - size_t sequenceGraphicCount + uint32_t sequenceGraphicCount double sequenceGraphicTime - size_t enumerationCount + uint32_t enumerationCount double enumerationTime - size_t enumerationCandidatesCount + uint32_t enumerationCandidatesCount CMR_ERROR CMRstatsRegularInit(CMR_REGULAR_STATISTICS* stats) # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATISTICS* stats, const char* prefix) @@ -368,7 +368,7 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMETERS* params) ctypedef struct CMR_TU_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime CMR_CAMION_STATISTICS camion CMR_REGULAR_STATISTICS regular @@ -381,7 +381,7 @@ cdef extern from "cmr/tu.h": cdef extern from "cmr/ctu.h": ctypedef struct CMR_CTU_STATISTICS: - size_t totalCount + uint32_t totalCount double totalTime CMR_TU_STATISTICS tu From 4d16be49b79473f39470c72a0d6f69aa1ada7569 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Dec 2023 14:58:44 -0800 Subject: [PATCH 072/262] src/sage/libs/cmr/cmr.pxd, src/sage/matrix/matrix_cmr_sparse.pyx: Update for new CMR version --- src/sage/libs/cmr/cmr.pxd | 67 ++++++++++++++++++++++++--- src/sage/matrix/matrix_cmr_sparse.pyx | 40 ++++++++++------ 2 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index a276c9f8133..028151aed94 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -4,6 +4,8 @@ # (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "" nil (point) (point-max)) (replace-regexp "[;{}]" "" nil (point) (point-max)) (replace-regexp "CMR_EXPORT *" "" nil (point) (point-max)) (replace-regexp "bool" "bint" nil (point) (point-max))) +from libc.stdint cimport uint32_t, int64_t + cdef extern from "stdbool.h": ctypedef int bool @@ -46,6 +48,21 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRsubmatCreate1x1(CMR* cmr, size_t row, size_t column, CMR_SUBMAT** psubmatrix) CMR_ERROR CMRsubmatFree(CMR* cmr, CMR_SUBMAT** psubmatrix) + ctypedef struct CMR_INTMAT: + size_t numRows + size_t numColumns + size_t numNonzeros + size_t* rowSlice + size_t* entryColumns + int* entryValues + + CMR_ERROR CMRintmatCreate(CMR* cmr, CMR_INTMAT** presult, int numRows, int numColumns, int numNonzeros) + CMR_ERROR CMRintmatSortNonzeros(CMR* cmr, CMR_INTMAT* matrix) + # CMR_ERROR CMRintmatPrintDense(CMR* cmr, CMR_INTMAT* matrix, FILE* stream, char zeroChar, bint header) + CMR_ERROR CMRintmatFindEntry(CMR_INTMAT* matrix, size_t row, size_t column, size_t* pentry) + CMR_ERROR CMRintmatZoomSubmat(CMR* cmr, CMR_INTMAT* matrix, CMR_SUBMAT* submatrix, CMR_INTMAT** presult) + CMR_ERROR CMRintmatFree(CMR* cmr, CMR_INTMAT** pmatrix) + ctypedef struct CMR_CHRMAT: size_t numRows size_t numColumns @@ -61,12 +78,8 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRchrmatZoomSubmat(CMR* cmr, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, CMR_CHRMAT** presult) CMR_ERROR CMRchrmatFree(CMR* cmr, CMR_CHRMAT** pmatrix) -cdef extern from "cmr/k_modular.h": - - CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, int* pisUnimodular) - CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisStronglyUnimodular) - CMR_ERROR CMRtestKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisKmodular, size_t* pk) - CMR_ERROR CMRtestStrongKmodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisStronglyKmodular, size_t* pk) + CMR_ERROR CMRchrmatToInt(CMR* cmr, CMR_CHRMAT* matrix, CMR_INTMAT** presult) + CMR_ERROR CMRintmatToChr(CMR* cmr, CMR_INTMAT* matrix, CMR_CHRMAT** presult) cdef extern from "cmr/camion.h": @@ -362,7 +375,14 @@ cdef extern from "cmr/regular.h": cdef extern from "cmr/tu.h": + const int CMR_TU_ALGORITHM_DECOMPOSITION + const int CMR_TU_ALGORITHM_SUBMATRIX + const int CMR_TU_ALGORITHM_PARTITION + + ctypedef int CMR_TU_ALGORITHM + ctypedef struct CMR_TU_PARAMETERS: + CMR_TU_ALGORITHM algorithm CMR_REGULAR_PARAMETERS regular CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMETERS* params) @@ -378,6 +398,39 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMETERS* params, CMR_TU_STATISTICS* stats, double timeLimit) +cdef extern from "cmr/equimodular.h": + + ctypedef struct CMR_EQUIMODULAR_PARAMETERS: + CMR_TU_PARAMETERS tu + + CMR_ERROR CMRparamsEquimodularityInit(CMR_EQUIMODULAR_PARAMETERS* params) + + ctypedef struct CMR_EQUIMODULAR_STATISTICS: + uint32_t totalCount + double totalTime + double linalgTime + CMR_TU_STATISTICS tu + + CMR_ERROR CMRstatsEquimodularityInit(CMR_EQUIMODULAR_STATISTICS* stats) + + CMR_ERROR CMRtestEquimodularity(CMR* cmr, CMR_INTMAT* matrix, + bool* pisEquimodular, int64_t *pgcdDet, + CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + double timeLimit) + CMR_ERROR CMRtestStrongEquimodularity(CMR* cmr, CMR_INTMAT* matrix, + bool* pisStronglyEquimodular, int64_t *pgcdDet, + CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + double timeLimit) + CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_INTMAT* matrix, + bool* pisUnimodular, + CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + double timeLimit) + CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_INTMAT* matrix, + bool* pisStronglyUnimodular, + CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + double timeLimit) + + cdef extern from "cmr/ctu.h": ctypedef struct CMR_CTU_STATISTICS: @@ -388,7 +441,7 @@ cdef extern from "cmr/ctu.h": CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATISTICS* stats) # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATISTICS* stats, const char* prefix) CMR_ERROR CMRcomplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) - CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats) + CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats, double timeLimit) # Our global CMR environment diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 410646d7fe0..8c6fad5cd34 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -618,7 +618,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_list.append(x) return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) - def is_unimodular(self): + def is_unimodular(self, time_limit=60.0): r""" Return whether ``self`` is a unimodular matrix. @@ -653,17 +653,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_unimodular() False """ + cdef CMR_INTMAT *int_mat = NULL cdef bool result sig_on() try: - CMR_CALL(CMRtestUnimodularity(cmr, self._mat, &result)) + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: + CMRintmatFree(cmr, &int_mat) sig_off() return result - def is_strongly_unimodular(self): + def is_strongly_unimodular(self, time_limit=60.0): r""" Return whether ``self`` is a strongly unimodular matrix. @@ -690,17 +693,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_strongly_unimodular() True """ + cdef CMR_INTMAT *int_mat = NULL cdef bool result sig_on() try: - CMR_CALL(CMRtestStrongUnimodularity(cmr, self._mat, &result)) + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestStrongUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: + CMRintmatFree(cmr, &int_mat) sig_off() return result - def modulus(self): + def modulus(self, time_limit=60.0): r""" Return the integer `k` such that ``self`` is `k`-modular. @@ -733,13 +739,16 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 1 3] sage: M.modulus() """ + cdef CMR_INTMAT *int_mat = NULL cdef bool result - cdef size_t k + cdef int64_t k sig_on() try: - CMR_CALL(CMRtestKmodularity(cmr, self._mat, &result, &k)) + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: + CMRintmatFree(cmr, &int_mat) sig_off() if result: @@ -747,7 +756,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): else: return None - def strong_modulus(self): + def strong_modulus(self, time_limit=60.0): r""" Return the integer `k` such that ``self`` is strongly `k`-modular. @@ -780,13 +789,16 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.strong_modulus() 1 """ + cdef CMR_INTMAT *int_mat = NULL cdef bool result - cdef size_t k + cdef int64_t k sig_on() try: - CMR_CALL(CMRtestStrongKmodularity(cmr, self._mat, &result, &k)) + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: + CMRintmatFree(cmr, &int_mat) sig_off() if result: @@ -794,7 +806,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): else: return None - def is_k_modular(self, k): + def is_k_modular(self, k, time_limit=60.0): r""" Return whether ``self`` is `k`-modular. @@ -833,13 +845,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_k_modular(1) False """ - result = self.modulus() + result = self.modulus(time_limit=time_limit) if not result: return False else: return result == k - def is_strongly_k_modular(self, k): + def is_strongly_k_modular(self, k, time_limit=60.0): r""" Return whether ``self`` is strongly `k`-modular. @@ -864,7 +876,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_strongly_k_modular(1) True """ - result = self.strong_modulus() + result = self.strong_modulus(time_limit=time_limit) if not result: return False else: From 931c82b95f53bc20497ffb327e196b2c173dbf04 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Dec 2023 15:09:26 -0800 Subject: [PATCH 073/262] src/sage/matrix/matrix_cmr_sparse.pyx: Set CMR_TU_ALGORITHM slot --- src/sage/matrix/matrix_cmr_sparse.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 8c6fad5cd34..e45dfcb5b90 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1278,6 +1278,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): construct_transposes=construct_transposes, construct_graphs=construct_graphs) + params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION _set_cmr_regular_parameters(¶ms.regular, kwds) sig_on() try: From 95e86a5d6fb8b10f97711a49ad4082932e1181df Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Dec 2023 11:58:37 -0800 Subject: [PATCH 074/262] build/pkgs/cmr: Update to 9dca928195c4b5bfdb413292eb38e2fb0d388cba --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 9c9bfecf536..b1a9d95fb51 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=f434e3042942bb794826ebd1e10ee8460e16f6b5 -md5=435722c49ab9b87ab6c234e869f27cc9 -cksum=3577442237 +sha1=0596debc024061e059a89dfc16d18fde336ece3e +md5=de719fd28e560277a377a2537e88ab35 +cksum=2141679083 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 1362a805b78..12efdb61d72 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -de04ca6f36f81044731360cf336057e77ec60d46 +9dca928195c4b5bfdb413292eb38e2fb0d388cba From c22d8549a479cc2df5ddfa4e9369dc121a203d1c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Dec 2023 12:23:11 -0800 Subject: [PATCH 075/262] src/sage/libs/cmr: Update --- src/sage/libs/cmr/cmr.pxd | 6 +++--- src/sage/matrix/matrix_cmr_sparse.pyx | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 028151aed94..d8b1d695d75 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -4,7 +4,7 @@ # (progn (replace-regexp "/[*]\\(.\\|\n\\)*?[*]/" "" nil (point) (point-max)) (replace-regexp "[;{}]" "" nil (point) (point-max)) (replace-regexp "CMR_EXPORT *" "" nil (point) (point-max)) (replace-regexp "bool" "bint" nil (point) (point-max))) -from libc.stdint cimport uint32_t, int64_t +from libc.stdint cimport int8_t, uint32_t, int64_t cdef extern from "stdbool.h": @@ -140,8 +140,8 @@ cdef extern from "cmr/separation.h": unsigned char CMRsepaRank(CMR_SEPA* sepa) CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bool* pisTernary, CMR_SUBMAT** psubmatrix) CMR_ERROR CMRoneSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_CHRMAT** presult) - CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, CMR_CHRMAT** presult) - CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, CMR_CHRMAT** presult) + CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, int8_t characteristic, CMR_CHRMAT** presult) + CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, int8_t characteristic, CMR_CHRMAT** presult) cdef extern from "cmr/graph.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e45dfcb5b90..385f099c242 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -461,7 +461,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): column_subdivision = [] row_subdivision.append(first._mat.numRows) column_subdivision.append(first._mat.numColumns - 1) - CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, CMRcolumnToElement(column), CMRrowToElement(row), &sum_mat)) + characteristic = 0 + CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, + CMRcolumnToElement(column), CMRrowToElement(row), characteristic, + &sum_mat)) sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: sum.subdivide(row_subdivision, column_subdivision) From ecd2172242ed16db62105360beb1b97fac1bd9d8 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Dec 2023 15:26:45 -0800 Subject: [PATCH 076/262] add matrix_from_rows_and_columns --- src/sage/matrix/matrix_cmr_sparse.pyx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 385f099c242..1c2f9278dcf 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -128,6 +128,31 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if immutable: self.set_immutable() + def matrix_from_rows_and_columns(self, rows, columns): + if not isinstance(rows, (list, tuple)): + rows = list(rows) + + if not isinstance(columns, (list, tuple)): + columns = list(columns) + + if cmr == NULL: + CMRcreateEnvironment(&cmr) + + cdef CMR_SUBMAT *submatrix = NULL + cdef CMR_CHRMAT *cmr_submatrix = NULL + + CMR_CALL(CMRsubmatCreate(cmr, len(rows), len(columns), &submatrix)) + + for i in range(submatrix.numRows): + submatrix.rows[i] = rows[i] + + for j in range(submatrix.numColumns): + submatrix.columns[j] = columns[j] + + CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) + + return Matrix_cmr_chr_sparse._from_cmr(cmr_submatrix) + cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): cdef size_t index CMR_CALL(CMRchrmatFindEntry(self._mat, i, j, &index)) From cedec82d7a737b6502e88a3e6073bf15160e941a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Feb 2024 09:50:00 -0800 Subject: [PATCH 077/262] add nonzero_block type choice for two sum # Conflicts: # src/sage/matrix/matrix_cmr_sparse.pyx --- src/sage/matrix/matrix_cmr_sparse.pyx | 65 ++++++++++++++++++++------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1c2f9278dcf..179693f2da6 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -435,7 +435,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum.set_immutable() return sum - def two_sum(first_mat, second_mat, column, row): + def two_sum(first_mat, second_mat, first_index, second_index, nonzero_block="top_right"): r""" Return the 2-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with column index of the first matrix ``column`` and row index @@ -449,8 +449,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``first_mat`` -- the first integer matrix - ``second_mat`` -- the second integer matrix - - ``column`` -- the column index of the first integer matrix - - ``row`` -- the row index of the first integer matrix + - ``first_index`` -- the column/row index of the first integer matrix + - ``second_index`` -- the row/column index of the second integer matrix + - ``nonzero_block`` -- ``"top_right"`` (default) or ``"bottom_left"``. + The indicator the type of the 2-sum where the all zero block locates. + If ``nonzero_block="top_right"``, + ``first_index`` is the column index of the first integer matrix, + ``second_index`` is the row index of the second integer matrix. + The outer product of the corresponding column and row + form the nonzero top right block of the 2-sum matrix. + If ``nonzero_block="bottom_left"``, + ``first_index`` is the row index of the first integer matrix, + ``second_index`` is the column index of the second integer matrix. + The outer product of the corresponding row and column + form the nonzero bottom left block of the 2-sum matrix. EXAMPLES:: @@ -468,28 +480,51 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 4 5|42 48 54] [-----+--------] [ 0 0|-1 -2 -3] - sage: M1.two_sum(M2,1,1) + sage: M1.two_sum(M2, 1, 1) [ 1 3| -2 -4 -6] [ 4 6| -5 -10 -15] [-------+-----------] [ 0 0| 7 8 9] + sage: M1.two_sum(M2, 1, 1, nonzero_block="bottom_right") + [ 1 2 3| 0 0] + [-----------+-------] + [ 32 40 48| 7 9] + [ -8 -10 -12| -1 -3] """ cdef Matrix_cmr_chr_sparse sum, first, second cdef CMR_CHRMAT *sum_mat first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) - if column < 0 or column >= first._mat.numColumns: - raise ValueError("First marker should be a column index of the first matrix") - if row < 0 or row >= second._mat.numRows: - raise ValueError("Second marker should be a row index of the second matrix") - row_subdivision = [] - column_subdivision = [] - row_subdivision.append(first._mat.numRows) - column_subdivision.append(first._mat.numColumns - 1) + + if nonzero_block == "top_right": + column = first_index + row = second_index + if column < 0 or column >= first._mat.numColumns: + raise ValueError("First marker should be a column index of the first matrix") + if row < 0 or row >= second._mat.numRows: + raise ValueError("Second marker should be a row index of the second matrix") + row_subdivision = [] + column_subdivision = [] + row_subdivision.append(first._mat.numRows) + column_subdivision.append(first._mat.numColumns - 1) + first_marker = CMRcolumnToElement(column) + second_marker = CMRrowToElement(row) + else: + row = first_index + column = second_index + if row < 0 or row >= first._mat.numRows: + raise ValueError("First marker should be a Row index of the first matrix") + if column < 0 or column >= second._mat.numColumns: + raise ValueError("Second marker should be a column index of the second matrix") + row_subdivision = [] + column_subdivision = [] + row_subdivision.append(first._mat.numRows - 1) + column_subdivision.append(first._mat.numColumns) + first_marker = CMRrowToElement(row) + second_marker = CMRcolumnToElement(column) + characteristic = 0 - CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, - CMRcolumnToElement(column), CMRrowToElement(row), characteristic, - &sum_mat)) + CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, first_marker, second_marker, characteristic, &sum_mat)) sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: sum.subdivide(row_subdivision, column_subdivision) From b441c10bf79e8361fac16dd27720888d029be0cf Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Dec 2023 19:11:38 -0800 Subject: [PATCH 078/262] add nonzero_block value test --- src/sage/matrix/matrix_cmr_sparse.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 179693f2da6..76424bdf773 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -496,6 +496,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) + if nonzero_block not in ["top_right", "bottom_left"]: + raise ValueError("Unknown two sum mode", nonzero_block) + if nonzero_block == "top_right": column = first_index row = second_index From 74c3852baac4d42a2c4a2ece848c7c981dc30539 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Dec 2023 18:23:13 -0800 Subject: [PATCH 079/262] add doc test and other fix --- src/sage/matrix/matrix_cmr_sparse.pyx | 52 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 76424bdf773..2420247b6e8 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -129,12 +129,52 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): self.set_immutable() def matrix_from_rows_and_columns(self, rows, columns): + """ + Return the matrix constructed from ``self`` from the given rows and + columns. + + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = MatrixSpace(Integers(8),3,3) + sage: A = Matrix_cmr_chr_sparse(M, range(9)); A + [0 1 2] + [3 4 5] + [6 7 0] + sage: A.matrix_from_rows_and_columns([1], [0,2]) + [3 5] + sage: A.matrix_from_rows_and_columns([1,2], [1,2]) + [4 5] + [7 0] + + Note that row and column indices can be reordered:: + + sage: A.matrix_from_rows_and_columns([2,1], [2,1]) + [0 7] + [5 4] + + But the column indices can not be repeated:: + + sage: A.matrix_from_rows_and_columns([1,1,1],[2,0]) + [5 3] + [5 3] + [5 3] + sage: A.matrix_from_rows_and_columns([1,1,1],[2,0,0]) + Traceback (most recent call last): + ... + ValueError: The column indices can not be repeated + """ if not isinstance(rows, (list, tuple)): rows = list(rows) if not isinstance(columns, (list, tuple)): columns = list(columns) + if len(list(set(columns))) != len(columns): + raise ValueError("The column indices can not be repeated") + if cmr == NULL: CMRcreateEnvironment(&cmr) @@ -151,6 +191,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) + CMR_CALL(CMRsubmatFree(cmr, &submatrix)) + return Matrix_cmr_chr_sparse._from_cmr(cmr_submatrix) cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): @@ -451,8 +493,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``second_mat`` -- the second integer matrix - ``first_index`` -- the column/row index of the first integer matrix - ``second_index`` -- the row/column index of the second integer matrix - - ``nonzero_block`` -- ``"top_right"`` (default) or ``"bottom_left"``. - The indicator the type of the 2-sum where the all zero block locates. + - ``nonzero_block`` -- either ``"top_right"`` (default) or ``"bottom_left"``; + whether the nonzero block in the 2-sum matrix locates in the top right or bottom left. If ``nonzero_block="top_right"``, ``first_index`` is the column index of the first integer matrix, ``second_index`` is the row index of the second integer matrix. @@ -475,7 +517,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: [[7, 8, 9], [-1, -2, -3]]); M2 [ 7 8 9] [-1 -2 -3] - sage: Matrix_cmr_chr_sparse.two_sum(M1,M2,2,0) + sage: Matrix_cmr_chr_sparse.two_sum(M1, M2, 2, 0) [ 1 2|21 24 27] [ 4 5|42 48 54] [-----+--------] @@ -486,6 +528,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-------+-----------] [ 0 0| 7 8 9] sage: M1.two_sum(M2, 1, 1, nonzero_block="bottom_right") + Traceback (most recent call last): + ... + ValueError: ('Unknown two sum mode', 'bottom_right') + sage: M1.two_sum(M2, 1, 1, nonzero_block="bottom_left") [ 1 2 3| 0 0] [-----------+-------] [ 32 40 48| 7 9] From 651bdb3efe9ad876239a1b88c3edf40d2d4084d2 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Dec 2023 18:35:44 -0800 Subject: [PATCH 080/262] remove CMR_call for CMRsubmatFree --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 2420247b6e8..b4cdb44c656 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -191,7 +191,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) - CMR_CALL(CMRsubmatFree(cmr, &submatrix)) + CMRsubmatFree(cmr, &submatrix) return Matrix_cmr_chr_sparse._from_cmr(cmr_submatrix) From 72b36cf0991c24b25d07d71368e383eaba8c0c9d Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Dec 2023 22:41:35 -0800 Subject: [PATCH 081/262] fix doc and test for equimodular and strongly equimodular --- src/sage/matrix/matrix_cmr_sparse.pyx | 126 ++++++++++++++++---------- 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b4cdb44c656..65e6fb096c1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -818,22 +818,23 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result - def modulus(self, time_limit=60.0): + def equimodulus(self, time_limit=60.0): r""" - Return the integer `k` such that ``self`` is `k`-modular. + Return the integer `k` such that ``self`` is + equimodular with determinant gcd `k`. - A matrix `M` of rank `r` is `k`-modular if the following two conditions - are satisfied: - - for some column basis `B` of `M`, the greatest common divisor of the - determinants of all `r`-by-`r` submatrices of `B` is `k`; + A matrix `M` of rank `r` is equimodular with determinant gcd `k` + if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of + the determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. OUTPUT: - - ``k``: ``self`` is `k`-modular - - ``None``: ``self`` is not `k`-modular for any `k` + - ``k``: ``self`` is equimodular with determinant gcd `k` + - ``None``: ``self`` is not equimodular for any `k` - .. SEEALSO:: :meth:`is_k_modular`, :meth:`strong_modulus` + .. SEEALSO:: :meth:`is_k_equimodular`, :meth:`strong_equimodulus` EXAMPLES:: @@ -843,17 +844,17 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [0 1 1] [1 2 3] - sage: M.modulus() + sage: M.equimodulus() 1 sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 1, 1], [0, 1, 3]]); M [1 1 1] [0 1 3] - sage: M.modulus() + sage: M.equimodulus() """ cdef CMR_INTMAT *int_mat = NULL cdef bool result - cdef int64_t k + cdef int64_t k = 0 sig_on() try: @@ -864,14 +865,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() if result: - return Integer(k) + return k else: return None - def strong_modulus(self, time_limit=60.0): + def strong_equimodulus(self, time_limit=60.0): r""" - Return the integer `k` such that ``self`` is strongly `k`-modular. + Return the integer `k` such that ``self`` is + strongly equimodular with determinant gcd `k`. + + Return whether ``self`` is strongly `k`-equimodular. + A matrix is strongly equimodular if ``self`` and ``self.transpose()`` + are both equimodular, which implies that they are equimodular for + the same determinant gcd `k`. A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: - for some column basis `B` of `M`, the greatest common divisor of the @@ -880,10 +887,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): OUTPUT: - - ``k``: ``self`` is `k`-modular - - ``None``: ``self`` is not `k`-modular for any `k` + - ``k``: ``self`` is `k`-equimodular + - ``None``: ``self`` is not `k`-equimodular for any `k` - .. SEEALSO:: :meth:`is_strongly_k_modular`, :meth:`modulus` + .. SEEALSO:: :meth:`is_strongly_k_equimodular`, :meth:`equimodulus` EXAMPLES:: @@ -893,17 +900,17 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [0 1 1] [1 2 3] - sage: M.strong_modulus() + sage: M.strong_equimodulus() sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 0, 0], [0, 1, 0]]); M [1 0 0] [0 1 0] - sage: M.strong_modulus() + sage: M.strong_equimodulus() 1 """ cdef CMR_INTMAT *int_mat = NULL cdef bool result - cdef int64_t k + cdef int64_t k = 0 sig_on() try: @@ -914,29 +921,30 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() if result: - return Integer(k) + return k else: return None - def is_k_modular(self, k, time_limit=60.0): + def is_k_equimodular(self, k, time_limit=60.0): r""" - Return whether ``self`` is `k`-modular. + Return whether ``self`` is equimodular with determinant gcd `k`. - A matrix `M` of rank-`r` is `k`-modular if the following two conditions - are satisfied: - - for some column basis `B` of `M`, the greatest common divisor of the - determinants of all `r`-by-`r` submatrices of `B` is `k`; + A matrix `M` of rank-`r` is `k`-equimodular if the following two + conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of + the determinants of all `r`-by-`r` submatrices of `B` is `k`; - the matrix `X` such that `M=BX` is totally unimodular. - If the matrix has full row rank, it is `k`-modular if every full rank minor - of the matrix has determinant `0,\pm k`. + If the matrix has full row rank, it is `k`-equimodular if + every full rank minor of the matrix has determinant `0,\pm k`. .. NOTE:: In parts of the literature, a matrix with the above properties is called *strictly* `k`-modular. - .. SEEALSO:: :meth:`is_unimodular`, :meth:`is_strongly_k_modular`, :meth:`_modulus` + .. SEEALSO:: :meth:`is_unimodular`, :meth:`is_strongly_k_equimodular`, + :meth:`equimodulus` EXAMPLES:: @@ -946,30 +954,40 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [0 1 1] [1 2 3] - sage: M.is_k_modular(1) + sage: M.is_k_equimodular(1) True - sage: M.is_k_modular(2) + sage: M.is_k_equimodular(2) False sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 1, 1], [0, 1, 3]]); M [1 1 1] [0 1 3] - sage: M.is_k_modular(1) + sage: M.is_k_equimodular(1) False """ - result = self.modulus(time_limit=time_limit) - if not result: - return False - else: - return result == k + cdef CMR_INTMAT *int_mat = NULL + cdef bool result + cdef int64_t gcd_det = k + + sig_on() + try: + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) + finally: + CMRintmatFree(cmr, &int_mat) + sig_off() + + return True if result else False - def is_strongly_k_modular(self, k, time_limit=60.0): + def is_strongly_k_equimodular(self, k, time_limit=60.0): r""" - Return whether ``self`` is strongly `k`-modular. + Return whether ``self`` is strongly `k`-equimodular. - A matrix is strongly `k`-modular if ``self`` and ``self.transpose()`` are both `k`-modular. + A matrix is strongly `k`-equimodular if ``self`` and ``self.transpose()`` + are both `k`-equimodular. - .. SEEALSO:: :meth:`is_k_modular`, :meth:`is_strongly_unimodular`, :meth:`strong_modulus` + .. SEEALSO:: :meth:`is_k_equimodular`, :meth:`is_strongly_unimodular`, + :meth:`strong_equimodulus` EXAMPLES:: @@ -979,20 +997,28 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [0 1 1] [1 2 3] - sage: M.is_strongly_k_modular(1) + sage: M.is_strongly_k_equimodular(1) False sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), ....: [[1, 0, 0], [0, 1, 0]]); M [1 0 0] [0 1 0] - sage: M.is_strongly_k_modular(1) + sage: M.is_strongly_k_equimodular(1) True """ - result = self.strong_modulus(time_limit=time_limit) - if not result: - return False - else: - return result == k + cdef CMR_INTMAT *int_mat = NULL + cdef bool result + cdef int64_t gcd_det = k + + sig_on() + try: + CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) + CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) + finally: + CMRintmatFree(cmr, &int_mat) + sig_off() + + return True if result else False def is_graphic(self, *, time_limit=60.0, certificate=False): r""" From 51e2588f4e6e74f98cc5c4198a77e426c8f111ed Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 14 Dec 2023 10:36:28 -0800 Subject: [PATCH 082/262] add CMR_CALL --- src/sage/matrix/matrix_cmr_sparse.pyx | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 65e6fb096c1..3d103be392f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -181,17 +181,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef CMR_SUBMAT *submatrix = NULL cdef CMR_CHRMAT *cmr_submatrix = NULL - CMR_CALL(CMRsubmatCreate(cmr, len(rows), len(columns), &submatrix)) - - for i in range(submatrix.numRows): - submatrix.rows[i] = rows[i] + try: + CMR_CALL(CMRsubmatCreate(cmr, len(rows), len(columns), &submatrix)) - for j in range(submatrix.numColumns): - submatrix.columns[j] = columns[j] + for i in range(submatrix.numRows): + submatrix.rows[i] = rows[i] - CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) + for j in range(submatrix.numColumns): + submatrix.columns[j] = columns[j] - CMRsubmatFree(cmr, &submatrix) + CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) + finally: + CMR_CALL(CMRsubmatFree(cmr, &submatrix)) return Matrix_cmr_chr_sparse._from_cmr(cmr_submatrix) @@ -222,7 +223,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def __dealloc__(self): if self._root is None or self._root is self: # We own it, so we have to free it. - CMRchrmatFree(cmr, &self._mat) + CMR_CALL(CMRchrmatFree(cmr, &self._mat)) def _test_change_ring(self, **options): return @@ -773,7 +774,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() return result @@ -813,7 +814,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestStrongUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() return result @@ -861,7 +862,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() if result: @@ -917,7 +918,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() if result: @@ -974,7 +975,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() return True if result else False @@ -1015,7 +1016,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) finally: - CMRintmatFree(cmr, &int_mat) + CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() return True if result else False From d0082a47d4dfb5a595a134d1cee87f862c57ef70 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Feb 2024 10:00:52 -0800 Subject: [PATCH 083/262] pkgs/sagemath-cmr/pyproject.toml.m4: Update --- pkgs/sagemath-cmr/pyproject.toml.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/sagemath-cmr/pyproject.toml.m4 b/pkgs/sagemath-cmr/pyproject.toml.m4 index 0997ef4b021..6bfd3be015d 100644 --- a/pkgs/sagemath-cmr/pyproject.toml.m4 +++ b/pkgs/sagemath-cmr/pyproject.toml.m4 @@ -2,7 +2,7 @@ include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_setuptools SPKG_INSTALL_REQUIRES_sage_conf SPKG_INSTALL_REQUIRES_sage_setup SPKG_INSTALL_REQUIRES_sagemath_environment From 59f97e9ede5c31e1a997614407556c90265a5d4f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 15 Feb 2024 22:50:20 -0800 Subject: [PATCH 084/262] src/sage/matrix/matrix_cmr_sparse.pyx: Use matroids.catalog instead of derecated matroids.named_matroids --- src/sage/matrix/matrix_cmr_sparse.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 3d103be392f..d6ce6d4b9e7 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1227,7 +1227,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M._is_binary_linear_matroid_regular() True - sage: MF = matroids.named_matroids.Fano(); MF + sage: MF = matroids.catalog.Fano(); MF Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) sage: MFR = MF.representation().change_ring(ZZ); MFR [1 0 0 0 1 1 1] @@ -1368,7 +1368,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_totally_unimodular(certificate=True) (True, GraphicNode (3×2)) - sage: MF = matroids.named_matroids.Fano(); MF + sage: MF = matroids.catalog.Fano(); MF Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) sage: MFR = MF.representation().change_ring(ZZ); MFR [1 0 0 0 1 1 1] From d79ce1d425baff0a98f2f5df81f2852612937942 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 22 Dec 2023 16:04:38 -0800 Subject: [PATCH 085/262] add int8_t to characteristic --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index d6ce6d4b9e7..5ea34a2ff34 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -573,7 +573,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): first_marker = CMRrowToElement(row) second_marker = CMRcolumnToElement(column) - characteristic = 0 + cdef int8_t characteristic = 0 CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, first_marker, second_marker, characteristic, &sum_mat)) sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: From 9b12586b45cf3f106d366f2ff2f191ae50e1c773 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 15 Feb 2024 23:01:29 -0800 Subject: [PATCH 086/262] src/sage/matrix/seymour_decomposition.pyx: Add OneSumNode.check --- src/sage/matrix/seymour_decomposition.pyx | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index fa807c0a301..abf8339a48b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -322,6 +322,51 @@ cdef class OneSumNode(SumNode): """ return Matrix_cmr_chr_sparse.one_sum(*self.summand_matrices()) + @staticmethod + def check(result_matrix, summand_matrices, summand_parent_rows_and_columns): + r""" + Check that ``result_matrix`` is a 1-sum of ``summand_matrices``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import OneSumNode + + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True); certificate + OneSumNode (4×4) with 2 children + sage: OneSumNode.check(M2, + ....: certificate.summand_matrices(), + ....: [summand.parent_rows_and_columns() + ....: for summand in certificate.summands()]) + + Symbolic identities:: + + sage: from sage.matrix.seymour_decomposition import OneSumNode + sage: R. = QQ[] + sage: A = matrix([[x, 0], [-x, 1]]) + sage: B = matrix([[x, y], [-x, 0]]) + sage: A1B = block_diagonal_matrix([A, B]) + sage: OneSumNode.check(A1B, [A, B], [([0, 1], [0, 1]), + ....: ([2, 3], [2, 3])]) + + Using program analysis:: + + sage: # optional - cutgeneratingfunctionology + sage: R. = ParametricRealField({x: 1}, {y: -1}, {z: 0}) # true example + sage: A = matrix([[x, 0], [-x, 1]]) + sage: B = matrix([[x, y], [-x, 0]]) + sage: A1B = matrix([[z, 0, 0, 0], [-x, z, 0, 0], [], []]) + sage: OneSumNode.check(A1B, [A, B], [([0, 1], [0, 1]), + ....: ([2, 3], [2, 3])]) + sage: # side-effect: R stores polynomial identities + """ + # TODO: Check that summand_parent_rows_and_columns form partitions of rows and columns + for matrix, rows_and_columns in zip(summand_matrices, summand_parent_rows_and_columns): + assert result_matrix.matrix_from_rows_and_columns(*rows_and_columns) == matrix + # TODO: Check zero blocks + cdef class TwoSumNode(SumNode): r""" From daa3a40301623b5a1fd6080fbc9c79bb0ab2329f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 22 Dec 2023 14:56:20 -0800 Subject: [PATCH 087/262] update cmr to 224beac5b4186dc6b3bbcbaf19d8e8ffdd63507a --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index b1a9d95fb51..b99d0e9d681 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=0596debc024061e059a89dfc16d18fde336ece3e -md5=de719fd28e560277a377a2537e88ab35 -cksum=2141679083 +sha1=9f6fd03d6bea2ff692c368b07aae7f86e10aaee4 +md5=579a141647ef790809f6cd54e7cbb704 +cksum=4013467134 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 12efdb61d72..d23deef0026 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -9dca928195c4b5bfdb413292eb38e2fb0d388cba +224beac5b4186dc6b3bbcbaf19d8e8ffdd63507a \ No newline at end of file From b85fb5775d6fe92d085ddd8df53442fef2ae4923 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 10:15:50 -0800 Subject: [PATCH 088/262] update camion.h --- src/sage/libs/cmr/cmr.pxd | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d8b1d695d75..e1696e25b56 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -84,13 +84,17 @@ cdef extern from "cmr/matrix.h": cdef extern from "cmr/camion.h": ctypedef struct CMR_CAMION_STATISTICS: + uint32_t generalCount + double generalTime + uint32_t graphCount + double graphTime uint32_t totalCount double totalTime - CMR_ERROR CMRstatsCamionInit(CMR_CAMION_STATISTICS* stats) + CMR_ERROR CMRcamionStatsInit(CMR_CAMION_STATISTICS* stats) # CMR_ERROR CMRstatsCamionPrint(FILE* stream, CMR_CAMION_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRtestCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRcomputeCamionSigned(CMR* cmr, CMR_CHRMAT* matrix, bool* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcamionTestSigns(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRcamionComputeSigns(CMR* cmr, CMR_CHRMAT* matrix, bool* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) cdef extern from "cmr/matroid.h": From 9c9a5d6e6f3f71377f353c69a69a4494e898e86f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 10:30:51 -0800 Subject: [PATCH 089/262] update equimodular.h --- src/sage/libs/cmr/cmr.pxd | 42 +++++++++++++-------------- src/sage/matrix/matrix_cmr_sparse.pyx | 16 +++++----- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index e1696e25b56..ed5aa23f64f 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -385,53 +385,53 @@ cdef extern from "cmr/tu.h": ctypedef int CMR_TU_ALGORITHM - ctypedef struct CMR_TU_PARAMETERS: + ctypedef struct CMR_TU_PARAMS: CMR_TU_ALGORITHM algorithm CMR_REGULAR_PARAMETERS regular - CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMETERS* params) + CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMS* params) - ctypedef struct CMR_TU_STATISTICS: + ctypedef struct CMR_TU_STATS: uint32_t totalCount double totalTime CMR_CAMION_STATISTICS camion CMR_REGULAR_STATISTICS regular - CMR_ERROR CMRstatsTotalUnimodularityInit(CMR_TU_STATISTICS* stats) - # CMR_ERROR CMRstatsTotalUnimodularityPrint(FILE* stream, CMR_TU_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMETERS* params, CMR_TU_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRstatsTotalUnimodularityInit(CMR_TU_STATS* stats) + # CMR_ERROR CMRstatsTotalUnimodularityPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) + CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) cdef extern from "cmr/equimodular.h": - ctypedef struct CMR_EQUIMODULAR_PARAMETERS: - CMR_TU_PARAMETERS tu + ctypedef struct CMR_EQUIMODULAR_PARAMS: + CMR_TU_PARAMS tu - CMR_ERROR CMRparamsEquimodularityInit(CMR_EQUIMODULAR_PARAMETERS* params) + CMR_ERROR CMRequimodularParamsInit(CMR_EQUIMODULAR_PARAMS* params) - ctypedef struct CMR_EQUIMODULAR_STATISTICS: + ctypedef struct CMR_EQUIMODULAR_STATS: uint32_t totalCount double totalTime double linalgTime - CMR_TU_STATISTICS tu + CMR_TU_STATS tu - CMR_ERROR CMRstatsEquimodularityInit(CMR_EQUIMODULAR_STATISTICS* stats) + CMR_ERROR CMRequimodularStatsInit(CMR_EQUIMODULAR_STATS* stats) - CMR_ERROR CMRtestEquimodularity(CMR* cmr, CMR_INTMAT* matrix, + CMR_ERROR CMRequimodularTest(CMR* cmr, CMR_INTMAT* matrix, bool* pisEquimodular, int64_t *pgcdDet, - CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + CMR_EQUIMODULAR_PARAMS* params, CMR_EQUIMODULAR_STATS* stats, double timeLimit) - CMR_ERROR CMRtestStrongEquimodularity(CMR* cmr, CMR_INTMAT* matrix, + CMR_ERROR CMRequimodularTestStrong(CMR* cmr, CMR_INTMAT* matrix, bool* pisStronglyEquimodular, int64_t *pgcdDet, - CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + CMR_EQUIMODULAR_PARAMS* params, CMR_EQUIMODULAR_STATS* stats, double timeLimit) - CMR_ERROR CMRtestUnimodularity(CMR* cmr, CMR_INTMAT* matrix, + CMR_ERROR CMRunimodularTest(CMR* cmr, CMR_INTMAT* matrix, bool* pisUnimodular, - CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + CMR_EQUIMODULAR_PARAMS* params, CMR_EQUIMODULAR_STATS* stats, double timeLimit) - CMR_ERROR CMRtestStrongUnimodularity(CMR* cmr, CMR_INTMAT* matrix, + CMR_ERROR CMRunimodularTestStrong(CMR* cmr, CMR_INTMAT* matrix, bool* pisStronglyUnimodular, - CMR_EQUIMODULAR_PARAMETERS* params, CMR_EQUIMODULAR_STATISTICS* stats, + CMR_EQUIMODULAR_PARAMS* params, CMR_EQUIMODULAR_STATS* stats, double timeLimit) @@ -440,7 +440,7 @@ cdef extern from "cmr/ctu.h": ctypedef struct CMR_CTU_STATISTICS: uint32_t totalCount double totalTime - CMR_TU_STATISTICS tu + CMR_TU_STATS tu CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATISTICS* stats) # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATISTICS* stats, const char* prefix) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 5ea34a2ff34..dfa1247a1bc 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -772,7 +772,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) + CMR_CALL(CMRunimodularTest(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -812,7 +812,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestStrongUnimodularity(cmr, int_mat, &result, NULL, NULL, time_limit)) + CMR_CALL(CMRunimodularTestStrong(cmr, int_mat, &result, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -860,7 +860,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) + CMR_CALL(CMRequimodularTest(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -916,7 +916,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) + CMR_CALL(CMRequimodularTestStrong(cmr, int_mat, &result, &k, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -973,7 +973,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) + CMR_CALL(CMRequimodularTest(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -1014,7 +1014,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: CMR_CALL(CMRchrmatToInt(cmr, self._mat, &int_mat)) - CMR_CALL(CMRtestStrongEquimodularity(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) + CMR_CALL(CMRequimodularTestStrong(cmr, int_mat, &result, &gcd_det, NULL, NULL, time_limit)) finally: CMR_CALL(CMRintmatFree(cmr, &int_mat)) sig_off() @@ -1401,8 +1401,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): 2 """ cdef bool result - cdef CMR_TU_PARAMETERS params - cdef CMR_TU_STATISTICS stats + cdef CMR_TU_PARAMS params + cdef CMR_TU_STATS stats cdef CMR_DEC *dec = NULL cdef CMR_SUBMAT *submat = NULL From 638f254fa998fa7092ef919450138818e325415b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 11:38:49 -0800 Subject: [PATCH 090/262] update tu.h matroid.h and delete dec.h --- src/sage/libs/cmr/cmr.pxd | 190 ++++++++++++---------- src/sage/matrix/matrix_cmr_sparse.pyx | 16 +- src/sage/matrix/seymour_decomposition.pxd | 8 +- src/sage/matrix/seymour_decomposition.pyx | 6 +- 4 files changed, 121 insertions(+), 99 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index ed5aa23f64f..d4e2d1a37f5 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -98,6 +98,11 @@ cdef extern from "cmr/camion.h": cdef extern from "cmr/matroid.h": + CMR_ERROR CMRchrmatBinaryPivot(CMR* cmr, CMR_CHRMAT* matrix, size_t pivotRow, size_t pivotColumn, CMR_CHRMAT** presult) + CMR_ERROR CMRchrmatTernaryPivot(CMR* cmr, CMR_CHRMAT* matrix, size_t pivotRow, size_t pivotColumn, CMR_CHRMAT** presult) + CMR_ERROR CMRchrmatBinaryPivots(CMR* cmr, CMR_CHRMAT* matrix, size_t numPivots, size_t* pivotRows, size_t* pivotColumns, CMR_CHRMAT** presult) + CMR_ERROR CMRchrmatTernaryPivots(CMR* cmr, CMR_CHRMAT* matrix, size_t numPivots, size_t* pivotRows, size_t* pivotColumns, CMR_CHRMAT** presult) + ctypedef struct CMR_MINOR: size_t numPivots size_t* pivotRows @@ -107,6 +112,85 @@ cdef extern from "cmr/matroid.h": CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix) CMR_ERROR CMRminorFree(CMR* cmr, CMR_MINOR** pminor) + ctypedef struct CMR_MATROID_DEC + + ctypedef int CMR_MATROID_DEC_TYPE + + const int CMR_MATROID_DEC_TYPE_IRREGULAR + const int CMR_MATROID_DEC_TYPE_UNKNOWN + const int CMR_MATROID_DEC_TYPE_ONE_SUM + const int CMR_MATROID_DEC_TYPE_TWO_SUM + const int CMR_MATROID_DEC_TYPE_THREE_SUM + const int CMR_MATROID_DEC_TYPE_SERIES_PARALLEL + const int CMR_MATROID_DEC_TYPE_PIVOTS + const int CMR_MATROID_DEC_TYPE_SUBMATRIX + const int CMR_MATROID_DEC_TYPE_GRAPH + const int CMR_MATROID_DEC_TYPE_COGRAPH + const int CMR_MATROID_DEC_TYPE_PLANAR + const int CMR_MATROID_DEC_TYPE_R10 + const int CMR_MATROID_DEC_TYPE_FANO + const int CMR_MATROID_DEC_TYPE_FANO_DUAL + const int CMR_MATROID_DEC_TYPE_K5 + const int CMR_MATROID_DEC_TYPE_K5_DUAL + const int CMR_MATROID_DEC_TYPE_K33 + const int CMR_MATROID_DEC_TYPE_K33_DUAL + const int CMR_MATROID_DEC_TYPE_DETERMINANT + + ctypedef int CMR_MATROID_DEC_THREESUM_FLAG + + const int CMR_MATROID_DEC_THREESUM_FLAG_NO_PIVOTS + const int CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS + const int CMR_MATROID_DEC_THREESUM_FLAG_CONCENTRATED_RANK + const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE + const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_TALL + const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_MIXED + const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_ALLREPR + const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE + const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_TALL + const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_MIXED + const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_ALLREPR + const int CMR_MATROID_DEC_THREESUM_FLAG_SEYMOUR + const int CMR_MATROID_DEC_THREESUM_FLAG_TRUEMPER + + bool CMRmatroiddecIsTernary(CMR_MATROID_DEC* dec) + bool CMRmatroiddecThreeSumDistributedRanks(CMR_MATROID_DEC* dec) + bool CMRmatroiddecThreeSumConcentratedRank(CMR_MATROID_DEC* dec) + bool CMRmatroiddecHasTranspose(CMR_MATROID_DEC* dec) + CMR_CHRMAT* CMRmatroiddecGetMatrix(CMR_MATROID_DEC* dec) + CMR_CHRMAT* CMRmatroiddecGetTranspose(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecNumChildren(CMR_MATROID_DEC* dec) + CMR_MATROID_DEC* CMRmatroiddecChild(CMR_MATROID_DEC* dec, size_t childIndex) + CMR_MATROID_DEC_TYPE CMRmatroiddecType(CMR_MATROID_DEC* dec) + int8_t CMRmatroiddecGraphicness(CMR_MATROID_DEC* dec) + int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) + int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) + size_t* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) + size_t* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) + CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecGraphSizeCoforest(CMR_MATROID_DEC* dec) + bool* CMRmatroiddecGraphArcsReversed(CMR_MATROID_DEC* dec) + CMR_GRAPH* CMRmatroiddecCograph(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecCographSizeForest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecCographSizeCoforest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) + bool* CMRmatroiddecCographArcsReversed(CMR_MATROID_DEC* dec) + size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) + size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) + size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) + # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) + CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) + CMR_ERROR CMRmatroiddecUpdateOneSum(CMR* cmr, CMR_MATROID_DEC* dec, size_t numChildren) + + cdef extern from "cmr/element.h": ctypedef int CMR_ELEMENT @@ -271,74 +355,6 @@ cdef extern from "cmr/network.h": CMR_ERROR CMRtestNetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) CMR_ERROR CMRtestConetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) -cdef extern from "cmr/dec.h": - - ctypedef struct CMR_DEC - - ctypedef int CMR_DEC_TYPE - - const int CMR_DEC_IRREGULAR - const int CMR_DEC_UNKNOWN - const int CMR_DEC_ONE_SUM - const int CMR_DEC_TWO_SUM - const int CMR_DEC_THREE_SUM - const int CMR_DEC_GRAPHIC - const int CMR_DEC_COGRAPHIC - const int CMR_DEC_PLANAR - const int CMR_DEC_SERIES_PARALLEL - const int CMR_DEC_SPECIAL_R10 - const int CMR_DEC_SPECIAL_FANO - const int CMR_DEC_SPECIAL_FANO_DUAL - const int CMR_DEC_SPECIAL_K_5 - const int CMR_DEC_SPECIAL_K_5_DUAL - const int CMR_DEC_SPECIAL_K_3_3 - const int CMR_DEC_SPECIAL_K_3_3_DUAL - - ctypedef int CMR_DEC_FLAGS - - const int CMR_DEC_MASK_REPRESENTATION - const int CMR_DEC_IS_GRAPHIC - const int CMR_DEC_IS_COGRAPHIC - const int CMR_DEC_IS_REGULAR - const int CMR_DEC_HAS_LOWER_LEFT_NONZEROS - const int CMR_DEC_HAS_UPPER_RIGHT_NONZEROS - - CMR_ERROR CMRdecFree(CMR* cmr, CMR_DEC** pdec) - bint CMRdecHasMatrix(CMR_DEC* dec) - bint CMRdecHasTranspose(CMR_DEC* dec) - CMR_CHRMAT* CMRdecGetMatrix(CMR_DEC* dec) - CMR_CHRMAT* CMRdecGetTranspose(CMR_DEC* dec) - size_t CMRdecNumChildren(CMR_DEC* dec) - CMR_DEC* CMRdecChild(CMR_DEC* dec, size_t childIndex) - int CMRdecIsSum(CMR_DEC* dec, bool* plowerLeftNonzeros, bool* pupperRightNonzeros) - CMR_DEC_TYPE CMRdecIsSpecialLeaf(CMR_DEC* dec, int* prepresentationMatrix) - bint CMRdecIsGraphicLeaf(CMR_DEC* dec) - bint CMRdecIsCographicLeaf(CMR_DEC* dec) - bint CMRdecIsGraphic(CMR_DEC* dec) - bint CMRdecIsCographic(CMR_DEC* dec) - bint CMRdecIsRegular(CMR_DEC* dec) - bint CMRdecIsSeriesParallelReduction(CMR_DEC* dec) - bint CMRdecIsUnknown(CMR_DEC* dec) - size_t CMRdecNumRows(CMR_DEC* dec) - CMR_ELEMENT* CMRdecRowElements(CMR_DEC* dec) - size_t* CMRdecRowsParent(CMR_DEC* dec) - size_t CMRdecNumColumns(CMR_DEC* dec) - CMR_ELEMENT* CMRdecColumnElements(CMR_DEC* dec) - size_t* CMRdecColumnsParent(CMR_DEC* dec) - # CMR_ERROR CMRdecPrint(CMR* cmr, CMR_DEC* dec, FILE* stream, size_t indent, bint printMatrices, bint printGraphs, bint printReductions) - char* CMRdecConsistency(CMR_DEC* dec, bint recurse) - CMR_GRAPH* CMRdecGraph(CMR_DEC* dec) - CMR_GRAPH_EDGE* CMRdecGraphForest(CMR_DEC* dec) - size_t CMRdecGraphSizeForest(CMR_DEC* dec) - CMR_GRAPH_EDGE* CMRdecGraphCoforest(CMR_DEC* dec) - size_t CMRdecGraphSizeCoforest(CMR_DEC* dec) - bool* CMRdecGraphArcsReversed(CMR_DEC* dec) - CMR_GRAPH* CMRdecCograph(CMR_DEC* dec) - CMR_GRAPH_EDGE* CMRdecCographForest(CMR_DEC* dec) - CMR_GRAPH_EDGE* CMRdecCographCoforest(CMR_DEC* dec) - bool* CMRdecCographArcsReversed(CMR_DEC* dec) - - cdef extern from "cmr/regular.h": ctypedef int CMR_DEC_CONSTRUCT @@ -347,7 +363,7 @@ cdef extern from "cmr/regular.h": const int CMR_DEC_CONSTRUCT_LEAVES const int CMR_DEC_CONSTRUCT_ALL - ctypedef struct CMR_REGULAR_PARAMETERS: + ctypedef struct CMR_REGULAR_PARAMS: bint directGraphicness bint seriesParallel bint planarityCheck @@ -356,9 +372,9 @@ cdef extern from "cmr/regular.h": CMR_DEC_CONSTRUCT transposes CMR_DEC_CONSTRUCT graphs - CMR_ERROR CMRparamsRegularInit(CMR_REGULAR_PARAMETERS* params) + CMR_ERROR CMRparamsRegularInit(CMR_REGULAR_PARAMS* params) - ctypedef struct CMR_REGULAR_STATISTICS: + ctypedef struct CMR_REGULAR_STATS: uint32_t totalCount double totalTime CMR_SP_STATISTICS seriesParallel @@ -372,34 +388,40 @@ cdef extern from "cmr/regular.h": double enumerationTime uint32_t enumerationCandidatesCount - CMR_ERROR CMRstatsRegularInit(CMR_REGULAR_STATISTICS* stats) - # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRtestBinaryRegular(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMETERS* params, CMR_REGULAR_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRstatsRegularInit(CMR_REGULAR_STATS* stats) + # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATS* stats, const char* prefix) + CMR_ERROR CMRtestBinaryRegular(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_MATROID_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) cdef extern from "cmr/tu.h": const int CMR_TU_ALGORITHM_DECOMPOSITION - const int CMR_TU_ALGORITHM_SUBMATRIX + const int CMR_TU_ALGORITHM_EULERIAN const int CMR_TU_ALGORITHM_PARTITION ctypedef int CMR_TU_ALGORITHM ctypedef struct CMR_TU_PARAMS: CMR_TU_ALGORITHM algorithm - CMR_REGULAR_PARAMETERS regular + bool directCamion + CMR_REGULAR_PARAMS regular - CMR_ERROR CMRparamsTotalUnimodularityInit(CMR_TU_PARAMS* params) + CMR_ERROR CMRtuParamsInit(CMR_TU_PARAMS* params) ctypedef struct CMR_TU_STATS: - uint32_t totalCount - double totalTime - CMR_CAMION_STATISTICS camion - CMR_REGULAR_STATISTICS regular + CMR_REGULAR_STATS decomposition + + uint32_t enumerationRowSubsets + uint32_t enumerationColumnSubsets + double enumerationTime + + uint32_t partitionRowSubsets + uint32_t partitionColumnSubsets + double partitionTime - CMR_ERROR CMRstatsTotalUnimodularityInit(CMR_TU_STATS* stats) - # CMR_ERROR CMRstatsTotalUnimodularityPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) - CMR_ERROR CMRtestTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) + CMR_ERROR CMRtuStatsInit(CMR_TU_STATS* stats) + # CMR_ERROR CMRtuStatsPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) + CMR_ERROR CMRtuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_MATROID_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) cdef extern from "cmr/equimodular.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index dfa1247a1bc..db38fe748a9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1305,12 +1305,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): GraphicNode (4×4) """ cdef bool result - cdef CMR_REGULAR_PARAMETERS params - cdef CMR_REGULAR_STATISTICS stats - cdef CMR_DEC *dec = NULL + cdef CMR_REGULAR_PARAMS params + cdef CMR_REGULAR_STATS stats + cdef CMR_MATROID_DEC *dec = NULL cdef CMR_MINOR *minor = NULL - cdef CMR_DEC **pdec = &dec + cdef CMR_MATROID_DEC **pdec = &dec cdef CMR_MINOR **pminor = &minor cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, @@ -1403,10 +1403,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bool result cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats - cdef CMR_DEC *dec = NULL + cdef CMR_MATROID_DEC *dec = NULL cdef CMR_SUBMAT *submat = NULL - cdef CMR_DEC **pdec = &dec + cdef CMR_MATROID_DEC **pdec = &dec cdef CMR_SUBMAT **psubmat = &submat cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, @@ -1421,7 +1421,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): _set_cmr_regular_parameters(¶ms.regular, kwds) sig_on() try: - CMR_CALL(CMRtestTotalUnimodularity(cmr, self._mat, &result, pdec, psubmat, + CMR_CALL(CMRtuTest(cmr, self._mat, &result, pdec, psubmat, ¶ms, &stats, time_limit)) finally: sig_off() @@ -1460,7 +1460,7 @@ cdef _cmr_dec_construct(param): return CMR_DEC_CONSTRUCT_ALL -cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMETERS *params, dict kwds): +cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): CMR_CALL(CMRparamsRegularInit(params)) params.directGraphicness = kwds['use_direct_graphicness_test'] params.seriesParallel = kwds['series_parallel_ok'] diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index d188e3d8879..828b738ebc2 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -5,10 +5,10 @@ from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): - cdef CMR_DEC *_dec - cdef DecompositionNode _root # my CMR_DEC is owned by this + cdef CMR_MATROID_DEC *_dec + cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this - cdef _set_dec(self, CMR_DEC *dec, root) + cdef _set_dec(self, CMR_MATROID_DEC *dec, root) -cdef create_DecompositionNode(CMR_DEC *dec, root=?) +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index abf8339a48b..3302bcfbb4f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -31,7 +31,7 @@ cdef class DecompositionNode(SageObject): def __cinit__(self): self._dec = NULL - cdef _set_dec(self, CMR_DEC *dec, root): + cdef _set_dec(self, CMR_MATROID_DEC *dec, root): if self._root is None or self._root is self: if self._dec != NULL: # We own it, so we have to free it. @@ -557,7 +557,7 @@ cdef class SpecialLeafNode(DecompositionNode): cdef CMR_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) -cdef _class(CMR_DEC *dec): +cdef _class(CMR_MATROID_DEC *dec): k = CMRdecIsSum(dec, NULL, NULL) if k == 1: return OneSumNode @@ -580,7 +580,7 @@ cdef _class(CMR_DEC *dec): return ThreeConnectedIrregularNode -cdef create_DecompositionNode(CMR_DEC *dec, root=None): +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. From 6c5bd9c382b516843143719444a2d3ea160cffd8 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 11:43:07 -0800 Subject: [PATCH 091/262] update ctu.h --- src/sage/libs/cmr/cmr.pxd | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d4e2d1a37f5..e8ee7ad42cb 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -459,15 +459,20 @@ cdef extern from "cmr/equimodular.h": cdef extern from "cmr/ctu.h": - ctypedef struct CMR_CTU_STATISTICS: + ctypedef struct CMR_CTU_PARAMS: + CMR_TU_PARAMS tu + + CMR_ERROR CMRctuParamsInit(CMR_CTU_PARAMS* params) + + ctypedef struct CMR_CTU_STATS: uint32_t totalCount double totalTime CMR_TU_STATS tu - CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATISTICS* stats) - # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATS* stats) + # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATS* stats, const char* prefix) CMR_ERROR CMRcomplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) - CMR_ERROR CMRtestComplementTotalUnimodularity(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRctuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_PARAMS* params, CMR_CTU_STATS* stats, double timeLimit) # Our global CMR environment From cfd84df0400b1d1ff97950c4fc1d5649b8b905c4 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 11:46:45 -0800 Subject: [PATCH 092/262] update graphic.h --- src/sage/libs/cmr/cmr.pxd | 14 +++++++------- src/sage/matrix/matrix_cmr_sparse.pyx | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index e8ee7ad42cb..c668cc5a8c8 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -284,7 +284,7 @@ cdef extern from "cmr/graph.h": CMR_GRAPH_ITER CMRgraphEdgesNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) bint CMRgraphEdgesValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) CMR_GRAPH_EDGE CMRgraphEdgesEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - # CMR_ERROR CMRgraphPrint(FILE* stream, CMR_GRAPH* graph) + # CMR_ERROR CMRgraphPrint(CMR_GRAPH* graph, FILE* stream) CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) @@ -300,12 +300,12 @@ cdef extern from "cmr/graphic.h": uint32_t transposeCount double transposeTime - CMR_ERROR CMRstatsGraphicInit(CMR_GRAPHIC_STATISTICS* stats) - # CMR_ERROR CMRstatsGraphicPrint(FILE* stream, CMR_GRAPHIC_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRcomputeGraphicMatrix(CMR* cmr, CMR_GRAPH* graph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, int numForestEdges, CMR_GRAPH_EDGE* forestEdges, int numCoforestEdges, CMR_GRAPH_EDGE* coforestEdges, bool* pisCorrectForest) - CMR_ERROR CMRtestGraphicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisGraphic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestCographicMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestGraphicColumnSubmatrixGreedy(CMR* cmr, CMR_CHRMAT* transpose, size_t* orderedColumns, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRgraphicStatsInit(CMR_GRAPHIC_STATISTICS* stats) + # CMR_ERROR CMRgraphicStatsPrint(FILE* stream, CMR_GRAPHIC_STATISTICS* stats, const char* prefix) + CMR_ERROR CMRgraphicComputeMatrix(CMR* cmr, CMR_GRAPH* graph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, int numForestEdges, CMR_GRAPH_EDGE* forestEdges, int numCoforestEdges, CMR_GRAPH_EDGE* coforestEdges, bool* pisCorrectForest) + CMR_ERROR CMRgraphicTestMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisGraphic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRgraphicTestTranspose(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCographic, CMR_GRAPH** pgraph, CMR_GRAPH_EDGE** pforestEdges, CMR_GRAPH_EDGE** pcoforestEdges, CMR_SUBMAT** psubmatrix, CMR_GRAPHIC_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRgraphicTestColumnSubmatrixGreedy(CMR* cmr, CMR_CHRMAT* transpose, size_t* orderedColumns, CMR_SUBMAT** psubmatrix) cdef extern from "cmr/series_parallel.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index db38fe748a9..1041175d9de 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1061,10 +1061,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: if certificate: - CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, &graph, &forest_edges, + CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result, &graph, &forest_edges, &coforest_edges, &submatrix, &stats, time_limit)) else: - CMR_CALL(CMRtestGraphicMatrix(cmr, self._mat, &result, NULL, NULL, + CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result, NULL, NULL, NULL, NULL, &stats, time_limit)) finally: sig_off() @@ -1109,10 +1109,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: if certificate: - CMR_CALL(CMRtestCographicMatrix(cmr, self._mat, &result, &graph, &forest_edges, + CMR_CALL(CMRgraphicTestTranspose(cmr, self._mat, &result, &graph, &forest_edges, &coforest_edges, &submatrix, &stats, time_limit)) else: - CMR_CALL(CMRtestCographicMatrix(cmr, self._mat, &result, NULL, NULL, + CMR_CALL(CMRgraphicTestTranspose(cmr, self._mat, &result, NULL, NULL, NULL, NULL, &stats, time_limit)) finally: sig_off() From eec3345a8f16946db4e74a05d799db707133cd88 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 11:50:55 -0800 Subject: [PATCH 093/262] update network.h --- src/sage/libs/cmr/cmr.pxd | 9 +++++---- src/sage/matrix/matrix_cmr_sparse.pyx | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index c668cc5a8c8..d9fa75be2eb 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -47,6 +47,7 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRsubmatCreate(CMR* cmr, size_t numRows, size_t numColumns, CMR_SUBMAT** psubmatrix) CMR_ERROR CMRsubmatCreate1x1(CMR* cmr, size_t row, size_t column, CMR_SUBMAT** psubmatrix) CMR_ERROR CMRsubmatFree(CMR* cmr, CMR_SUBMAT** psubmatrix) + # CMR_ERROR CMRsubmatPrint(CMR* cmr, CMR_SUBMAT* submatrix, size_t numRows, size_t numColumns, FILE* stream) ctypedef struct CMR_INTMAT: size_t numRows @@ -349,11 +350,11 @@ cdef extern from "cmr/network.h": CMR_CAMION_STATISTICS camion CMR_GRAPHIC_STATISTICS graphic - CMR_ERROR CMRstatsNetworkInit(CMR_NETWORK_STATISTICS* stats) + CMR_ERROR CMRnetworkStatsInit(CMR_NETWORK_STATISTICS* stats) # CMR_ERROR CMRstatsNetworkPrint(FILE* stream, CMR_NETWORK_STATISTICS* stats, const char* prefix) - CMR_ERROR CMRcomputeNetworkMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bool* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bool* pisCorrectForest) - CMR_ERROR CMRtestNetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestConetworkMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRnetworkComputeMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bool* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bool* pisCorrectForest) + CMR_ERROR CMRnetworkTestMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRnetworkTestTranspose(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) cdef extern from "cmr/regular.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1041175d9de..6332e1cc6c9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -396,7 +396,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): try: for j in range(len(arc_to_cmr_edge)): cmr_arcs_reversed[j] = False - CMR_CALL(CMRcomputeNetworkMatrix(cmr, cmr_digraph, &cmr_matrix, NULL, + CMR_CALL(CMRnetworkComputeMatrix(cmr, cmr_digraph, &cmr_matrix, NULL, cmr_arcs_reversed, num_forest_arcs, cmr_forest_arcs, 0, NULL, &is_correct_forest)) if not is_correct_forest: @@ -1173,11 +1173,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: if certificate: - CMR_CALL(CMRtestNetworkMatrix(cmr, self._mat, &result, &digraph, &forest_arcs, + CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, &digraph, &forest_arcs, &coforest_arcs, &arcs_reversed, &submatrix, &stats, time_limit)) else: - CMR_CALL(CMRtestNetworkMatrix(cmr, self._mat, &result, NULL, NULL, + CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, NULL, NULL, NULL, NULL, NULL, &stats, time_limit)) finally: sig_off() From 27030d848547fe35a684188cf6ceb05c68a14ada Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 14:17:28 -0800 Subject: [PATCH 094/262] update regular.h --- src/sage/libs/cmr/cmr.pxd | 11 ++++++----- src/sage/matrix/matrix_cmr_sparse.pyx | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d9fa75be2eb..cb91ed3064a 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -369,11 +369,11 @@ cdef extern from "cmr/regular.h": bint seriesParallel bint planarityCheck bint completeTree - CMR_DEC_CONSTRUCT matrices - CMR_DEC_CONSTRUCT transposes + bool threeSumPivotChildren + int threeSumStrategy CMR_DEC_CONSTRUCT graphs - CMR_ERROR CMRparamsRegularInit(CMR_REGULAR_PARAMS* params) + CMR_ERROR CMRregularParamsInit(CMR_REGULAR_PARAMS* params) ctypedef struct CMR_REGULAR_STATS: uint32_t totalCount @@ -381,6 +381,7 @@ cdef extern from "cmr/regular.h": CMR_SP_STATISTICS seriesParallel CMR_GRAPHIC_STATISTICS graphic CMR_NETWORK_STATISTICS network + CMR_CAMION_STATISTICS camion uint32_t sequenceExtensionCount double sequenceExtensionTime uint32_t sequenceGraphicCount @@ -389,9 +390,9 @@ cdef extern from "cmr/regular.h": double enumerationTime uint32_t enumerationCandidatesCount - CMR_ERROR CMRstatsRegularInit(CMR_REGULAR_STATS* stats) + CMR_ERROR CMRregularStatsInit(CMR_REGULAR_STATS* stats) # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATS* stats, const char* prefix) - CMR_ERROR CMRtestBinaryRegular(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_MATROID_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRregularTest(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_MATROID_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) cdef extern from "cmr/tu.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 6332e1cc6c9..1e5a15f6ea9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1324,7 +1324,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): _set_cmr_regular_parameters(¶ms, kwds) sig_on() try: - CMR_CALL(CMRtestBinaryRegular(cmr, self._mat, &result, pdec, pminor, + CMR_CALL(CMRregularTest(cmr, self._mat, &result, pdec, pminor, ¶ms, &stats, time_limit)) finally: sig_off() @@ -1461,7 +1461,7 @@ cdef _cmr_dec_construct(param): cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): - CMR_CALL(CMRparamsRegularInit(params)) + CMR_CALL(CMRregularParamsInit(params)) params.directGraphicness = kwds['use_direct_graphicness_test'] params.seriesParallel = kwds['series_parallel_ok'] params.planarityCheck = kwds['check_graphic_minors_planar'] From 7308378ed03cae71bda61276f3e948ad7deda8f3 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 17:09:07 -0800 Subject: [PATCH 095/262] update separation.h --- src/sage/libs/cmr/cmr.pxd | 43 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index cb91ed3064a..9fde3d8ad93 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -208,26 +208,37 @@ cdef extern from "cmr/element.h": cdef extern from "cmr/separation.h": + ctypedef int CMR_SEPA_FLAGS + + const int CMR_SEPA_FIRST + const int CMR_SEPA_SECOND + const int CMR_SEPA_FLAG_RANK1 + const int CMR_SEPA_FLAG_RANK2 + const int CMR_SEPA_MASK_CHILD + const int CMR_SEPA_MASK_EXTRA + + ctypedef int CMR_SEPA_TYPE + + const int CMR_SEPA_TYPE_TWO + const int CMR_SEPA_TYPE_THREE_DISTRIBUTED_RANKS + const int CMR_SEPA_TYPE_THREE_CONCENTRATED_RANK + ctypedef struct CMR_SEPA: - unsigned char* rowsToPart - unsigned char* columnsToPart - size_t numRows[2] - size_t numColumns[2] - size_t* rows[2] - size_t* columns[2] - size_t extraRows[2][2] - size_t extraColumns[2][2] - unsigned char* indicatorMemory - size_t* elementMemory + size_t numRows + size_t numColumns + CMR_SEPA_FLAGS* rowsFlags + CMR_SEPA_FLAGS* columnsFlags + CMR_SEPA_TYPE type CMR_ERROR CMRsepaCreate(CMR* cmr, size_t numRows, size_t numColumns, CMR_SEPA** psepa) - CMR_ERROR CMRsepaInitialize(CMR* cmr, CMR_SEPA* separation, size_t firstExtraRow0, size_t firstExtraColumn1, size_t firstExtraRow1, size_t firstExtraColumn0, size_t secondExtraRow0, size_t secondExtraColumn1, size_t secondExtraRow1, size_t secondExtraColumn0) - CMR_ERROR CMRsepaInitializeMatrix(CMR* cmr, CMR_SEPA* separation, CMR_CHRMAT* matrix, unsigned char totalRank) CMR_ERROR CMRsepaFree(CMR* cmr, CMR_SEPA** psepa) - unsigned char CMRsepaRankBottomLeft(CMR_SEPA* sepa) - unsigned char CMRsepaRankTopRight(CMR_SEPA* sepa) - unsigned char CMRsepaRank(CMR_SEPA* sepa) - CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bool* pisTernary, CMR_SUBMAT** psubmatrix) + CMR_ERROR CMRsepaComputeSizes(CMR_SEPA* sepa, size_t* pnumRowsTopLeft, size_t* pnumColumnsTopLeft, size_t* pnumRowsBottomRight, size_t* pnumColumnsBottomRight) + CMR_ERROR CMRsepaFindBinaryRepresentatives(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_CHRMAT* transpose, bool* pswapped, CMR_SUBMAT** pviolator) + CMR_ERROR CMRsepaFindBinaryRepresentativesSubmatrix(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_CHRMAT* transpose, CMR_SUBMAT* submatrix, bool* pswapped, CMR_SUBMAT** pviolator) + CMR_ERROR CMRsepaGetRepresentatives(CMR* cmr, CMR_SEPA* sepa, size_t reprRows[2][3], size_t reprColumns[2][3]) + CMR_ERROR CMRsepaGetProjection(CMR_SEPA* sepa, size_t part, size_t* rowsToPart, size_t* columnsToPart, size_t* pnumPartRows, size_t* pnumPartColumns) + CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, bool* pisTernary, CMR_SUBMAT** pviolator) + CMR_ERROR CMRsepaCheckTernarySubmatrix(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bool* pisTernary, CMR_SUBMAT** pviolator) CMR_ERROR CMRoneSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_CHRMAT** presult) CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, int8_t characteristic, CMR_CHRMAT** presult) CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, int8_t characteristic, CMR_CHRMAT** presult) From cec45598462b8635e7ffd8d6676eed2cb7fd2804 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 17:32:37 -0800 Subject: [PATCH 096/262] add balenced.h --- src/sage/libs/cmr/cmr.pxd | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 9fde3d8ad93..827af1cebb9 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -331,9 +331,9 @@ cdef extern from "cmr/series_parallel.h": uint32_t nonbinaryCount double nonbinaryTime - CMR_ERROR CMRstatsSeriesParallelInit(CMR_SP_STATISTICS* stats) + CMR_ERROR CMRspStatsInit(CMR_SP_STATISTICS* stats) - # CMR_ERROR CMRstatsSeriesParallelPrint(FILE* stream, CMR_SP_STATISTICS* stats, const char* prefix) + # CMR_ERROR CMRspStatsPrint(FILE* stream, CMR_SP_STATISTICS* stats, const char* prefix) ctypedef struct CMR_SP_REDUCTION: CMR_ELEMENT element @@ -488,6 +488,33 @@ cdef extern from "cmr/ctu.h": CMR_ERROR CMRctuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_PARAMS* params, CMR_CTU_STATS* stats, double timeLimit) +cdef extern from "balanced.h": + ctypedef int CMR_BALANCED_ALGORITHM + + const int CMR_BALANCED_ALGORITHM_AUTO + const int CMR_BALANCED_ALGORITHM_SUBMATRIX + const int CMR_BALANCED_ALGORITHM_GRAPH + + ctypedef struct CMR_BALANCED_PARAMS: + CMR_BALANCED_ALGORITHM algorithm + bool seriesParallel + + ctypedef struct CMR_BALANCED_STATS: + uint32_t totalCount + double totalTime + CMR_SP_STATISTICS seriesParallel + size_t enumeratedRowSubsets + size_t enumeratedColumnSubsets + + CMR_ERROR CMRbalancedParamsInit(CMR_BALANCED_PARAMS* params) + + CMR_ERROR CMRbalancedStatsInit(CMR_BALANCED_STATS* stats) + + # CMR_ERROR CMRbalancedStatsPrint(FILE* stream, CMR_BALANCED_STATS* stats, const char* prefix) + + CMR_ERROR CMRbalancedTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisBalanced, CMR_SUBMAT** psubmatrix, CMR_BALANCED_PARAMS* params, CMR_BALANCED_STATS* stats, double timeLimit) + + # Our global CMR environment cdef CMR *cmr From 3dd8947a49da2593904d17df2cce9febd784b1bb Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 18:45:51 -0800 Subject: [PATCH 097/262] fix some dec to matroid_dec --- src/sage/libs/cmr/cmr.pxd | 36 ++++++++++++++ src/sage/matrix/seymour_decomposition.pxd | 2 +- src/sage/matrix/seymour_decomposition.pyx | 58 +++++++++++------------ 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 827af1cebb9..08d8ca925df 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -515,6 +515,42 @@ cdef extern from "balanced.h": CMR_ERROR CMRbalancedTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisBalanced, CMR_SUBMAT** psubmatrix, CMR_BALANCED_PARAMS* params, CMR_BALANCED_STATS* stats, double timeLimit) +cdef extern from "block_decomposition.h": + + ctypedef struct CMR_BLOCK: + CMR_MATRIX* matrix + CMR_MATRIX* transpose + size_t* rowsToOriginal + size_t* columnsToOriginal + + CMR_ERROR CMRdecomposeBlocks( + CMR* cmr, + CMR_MATRIX* matrix, + size_t matrixType, + size_t targetType, + size_t* pnumBlocks, + CMR_BLOCK** pblocks, + size_t* rowsToBlock, + size_t* columnsToBlock, + size_t* rowsToBlockRows, + size_t* columnsToBlockColumns + ) + + +cdef extern from "matrix_internal.h": + ctypedef struct CMR_MATRIX: + size_t numRows + size_t numColumns + size_t numNonzeros + size_t* rowSlice + size_t* entryColumns + void* entryValues + + CMR_ERROR CMRsortSubmatrix(CMR* cmr, CMR_SUBMAT* submatrix) + + CMR_ERROR CMRchrmatFilter(CMR* cmr, CMR_CHRMAT* matrix, size_t numRows, size_t* rows, size_t numColumns, size_t* columns, CMR_CHRMAT** presult) + + # Our global CMR environment cdef CMR *cmr diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 828b738ebc2..e113270b04f 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_DEC +from sage.libs.cmr.cmr cimport CMR_MATROID_DEC from sage.structure.sage_object cimport SageObject diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 3302bcfbb4f..f3e19084926 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -35,7 +35,7 @@ cdef class DecompositionNode(SageObject): if self._root is None or self._root is self: if self._dec != NULL: # We own it, so we have to free it. - CMR_CALL(CMRdecFree(cmr, &self._dec)) + CMR_CALL(CMRmatroiddecFree(cmr, &self._dec)) self._dec = dec self._root = root @@ -46,10 +46,10 @@ cdef class DecompositionNode(SageObject): return self._dec def nrows(self): - return CMRdecNumRows(self._dec) + return CMRmatroiddecNumRows(self._dec) def ncols(self): - return CMRdecNumColumns(self._dec) + return CMRmatroiddecNumColumns(self._dec) def dimensions(self): return self.nrows(), self.ncols() @@ -81,7 +81,7 @@ cdef class DecompositionNode(SageObject): [ 0 1] """ cdef Matrix_cmr_chr_sparse result - cdef CMR_CHRMAT *mat = CMRdecGetMatrix(self._dec) + cdef CMR_CHRMAT *mat = CMRmatroiddecGetMatrix(self._dec) if mat == NULL: return None ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) @@ -126,16 +126,16 @@ cdef class DecompositionNode(SageObject): sage: C[1].parent_rows_and_columns() ((3, 4, 5), (2, 3)) """ - cdef size_t *parent_rows = CMRdecRowsParent(self._dec) - cdef size_t *parent_columns = CMRdecColumnsParent(self._dec) + cdef size_t *parent_rows = CMRmatroiddecRowsParent(self._dec) + cdef size_t *parent_columns = CMRmatroiddecColumnsParent(self._dec) if parent_rows == NULL: parent_rows_tuple = None else: - parent_rows_tuple = tuple(parent_rows[i] for i in range(CMRdecNumRows(self._dec))) + parent_rows_tuple = tuple(parent_rows[i] for i in range(CMRmatroiddecNumRows(self._dec))) if parent_columns == NULL: parent_columns_tuple = None else: - parent_columns_tuple = tuple(parent_columns[i] for i in range(CMRdecNumColumns(self._dec))) + parent_columns_tuple = tuple(parent_columns[i] for i in range(CMRmatroiddecNumColumns(self._dec))) return parent_rows_tuple, parent_columns_tuple @@ -223,9 +223,9 @@ cdef class DecompositionNode(SageObject): sage: certificate._children() () """ - return tuple(sorted((create_DecompositionNode(CMRdecChild(self._dec, index), + return tuple(sorted((create_DecompositionNode(CMRmatroiddecChild(self._dec, index), self._root or self) - for index in range(CMRdecNumChildren(self._dec))), + for index in range(CMRmatroiddecNumChildren(self._dec))), key=lambda node: node.parent_rows_and_columns())) def _repr_(self): @@ -432,7 +432,7 @@ cdef class BaseGraphicNode(DecompositionNode): sage: G.edges(sort=True) [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] """ - return _sage_graph(CMRdecGraph(self._dec)) + return _sage_graph(CMRmatroiddecGraph(self._dec)) @cached_method def forest_edges(self): @@ -451,16 +451,16 @@ cdef class BaseGraphicNode(DecompositionNode): sage: certificate.forest_edges() ((1, 2), (7, 1)) """ - cdef CMR_GRAPH *graph = CMRdecGraph(self._dec) - cdef size_t num_edges = CMRdecGraphSizeForest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRdecGraphForest(self._dec) + cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) @cached_method def coforest_edges(self): - cdef CMR_GRAPH *graph = CMRdecGraph(self._dec) - cdef size_t num_edges = CMRdecGraphSizeCoforest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRdecGraphCoforest(self._dec) + cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) @@ -475,13 +475,13 @@ cdef class CographicNode(BaseGraphicNode): r""" Actually the cograph of matrix, in the case where it is not graphic. """ - return _sage_graph(CMRdecCograph(self._dec)) + return _sage_graph(CMRmatroiddecCograph(self._dec)) cdef class PlanarNode(BaseGraphicNode): @cached_method def cograph(self): - return _sage_graph(CMRdecCograph(self._dec)) + return _sage_graph(CMRmatroiddecCograph(self._dec)) cdef class SeriesParallelReductionNode(DecompositionNode): @@ -521,26 +521,26 @@ cdef class SpecialLeafNode(DecompositionNode): """ cdef int representation_matrix - cdef CMR_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) import sage.matroids.matroids_catalog as matroids from sage.graphs.graph_generators import graphs from sage.matroids.matroid import Matroid - if typ == CMR_DEC_SPECIAL_R10: + if typ == CMR_MATROID_DEC_TYPE_R10: return matroids.named_matroids.R10() - if typ == CMR_DEC_SPECIAL_FANO: + if typ == CMR_MATROID_DEC_TYPE_FANO: return matroids.named_matroids.Fano() - if typ == CMR_DEC_SPECIAL_FANO_DUAL: + if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: return matroids.named_matroids.Fano().dual() - if typ == CMR_DEC_SPECIAL_K_5: + if typ == CMR_MATROID_DEC_TYPE_K5: return matroids.CompleteGraphic(5) - if typ == CMR_DEC_SPECIAL_K_5_DUAL: + if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: return matroids.CompleteGraphic(5).dual() - if typ == CMR_DEC_SPECIAL_K_3_3: + if typ == CMR_MATROID_DEC_TYPE_K33: E = 'abcdefghi' G = graphs.CompleteBipartiteGraph(3, 3) return Matroid(groundset=E, graph=G, regular=True) - if typ == CMR_DEC_SPECIAL_K_3_3_DUAL: + if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: return matroids.named_matroids.K33dual() assert False, 'special leaf node with unknown type' @@ -554,7 +554,7 @@ cdef class SpecialLeafNode(DecompositionNode): assert NotImplementedError cdef int representation_matrix - cdef CMR_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef _class(CMR_MATROID_DEC *dec): @@ -586,7 +586,7 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): INPUT: - - ``dec`` -- a ``CMR_DEC`` + - ``dec`` -- a ``CMR_MATROID_DEC`` - ``root`` -- a :class:`DecompositionNode` or ``None``. If ``None``, ``dec`` will be owned by the returned instance. If non-``None``, ``dec`` is owned by that instance. From c64c37b8021a01dc6256c4b38e093a59f4022f05 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 18:47:46 -0800 Subject: [PATCH 098/262] WIP fix ISSUM --- src/sage/matrix/seymour_decomposition.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index f3e19084926..d336afd705a 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -520,6 +520,7 @@ cdef class SpecialLeafNode(DecompositionNode): r""" """ + pass cdef int representation_matrix cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) import sage.matroids.matroids_catalog as matroids @@ -558,6 +559,7 @@ cdef class SpecialLeafNode(DecompositionNode): return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef _class(CMR_MATROID_DEC *dec): + pass k = CMRdecIsSum(dec, NULL, NULL) if k == 1: return OneSumNode From ff4769e933136825e6084e8b7c8191d0648aa850 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 22 Feb 2024 19:22:09 -0800 Subject: [PATCH 099/262] WIP --- src/sage/libs/cmr/cmr.pxd | 12 +-- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- src/sage/matrix/seymour_decomposition.pyx | 92 +++++++++++------------ 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 08d8ca925df..66de5ab8f81 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -166,22 +166,22 @@ cdef extern from "cmr/matroid.h": int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) + # CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) + # CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) + # CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) + # CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeCoforest(CMR_MATROID_DEC* dec) bool* CMRmatroiddecGraphArcsReversed(CMR_MATROID_DEC* dec) CMR_GRAPH* CMRmatroiddecCograph(CMR_MATROID_DEC* dec) size_t CMRmatroiddecCographSizeForest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) + # CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecCographSizeCoforest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) + # CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) bool* CMRmatroiddecCographArcsReversed(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1e5a15f6ea9..a797b082447 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1460,7 +1460,7 @@ cdef _cmr_dec_construct(param): return CMR_DEC_CONSTRUCT_ALL -cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): +cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS* params, dict kwds): CMR_CALL(CMRregularParamsInit(params)) params.directGraphicness = kwds['use_direct_graphicness_test'] params.seriesParallel = kwds['series_parallel_ok'] diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d336afd705a..011e59df1bc 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -521,29 +521,29 @@ cdef class SpecialLeafNode(DecompositionNode): """ pass - cdef int representation_matrix - cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) - import sage.matroids.matroids_catalog as matroids - from sage.graphs.graph_generators import graphs - from sage.matroids.matroid import Matroid - - if typ == CMR_MATROID_DEC_TYPE_R10: - return matroids.named_matroids.R10() - if typ == CMR_MATROID_DEC_TYPE_FANO: - return matroids.named_matroids.Fano() - if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: - return matroids.named_matroids.Fano().dual() - if typ == CMR_MATROID_DEC_TYPE_K5: - return matroids.CompleteGraphic(5) - if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: - return matroids.CompleteGraphic(5).dual() - if typ == CMR_MATROID_DEC_TYPE_K33: - E = 'abcdefghi' - G = graphs.CompleteBipartiteGraph(3, 3) - return Matroid(groundset=E, graph=G, regular=True) - if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: - return matroids.named_matroids.K33dual() - assert False, 'special leaf node with unknown type' + # cdef int representation_matrix + # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + # import sage.matroids.matroids_catalog as matroids + # from sage.graphs.graph_generators import graphs + # from sage.matroids.matroid import Matroid + + # if typ == CMR_MATROID_DEC_TYPE_R10: + # return matroids.named_matroids.R10() + # if typ == CMR_MATROID_DEC_TYPE_FANO: + # return matroids.named_matroids.Fano() + # if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: + # return matroids.named_matroids.Fano().dual() + # if typ == CMR_MATROID_DEC_TYPE_K5: + # return matroids.CompleteGraphic(5) + # if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: + # return matroids.CompleteGraphic(5).dual() + # if typ == CMR_MATROID_DEC_TYPE_K33: + # E = 'abcdefghi' + # G = graphs.CompleteBipartiteGraph(3, 3) + # return Matroid(groundset=E, graph=G, regular=True) + # if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: + # return matroids.named_matroids.K33dual() + # assert False, 'special leaf node with unknown type' def _repr_(self): return f'Isomorphic to a minor of {self._matroid()}' @@ -554,32 +554,32 @@ cdef class SpecialLeafNode(DecompositionNode): """ assert NotImplementedError - cdef int representation_matrix - cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) - return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) + # cdef int representation_matrix + # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + # return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef _class(CMR_MATROID_DEC *dec): pass - k = CMRdecIsSum(dec, NULL, NULL) - if k == 1: - return OneSumNode - if k == 2: - return TwoSumNode - if k == 3: - return ThreeSumNode - if CMRdecIsGraphicLeaf(dec): - if CMRdecIsCographicLeaf(dec): - return PlanarNode - return GraphicNode - if CMRdecIsCographicLeaf(dec): - return CographicNode - if CMRdecIsSpecialLeaf(dec, NULL): - return SpecialLeafNode - if CMRdecIsSeriesParallelReduction(dec): - return SeriesParallelReductionNode - if CMRdecIsUnknown(dec): - return UnknownNode - return ThreeConnectedIrregularNode + # k = CMRdecIsSum(dec, NULL, NULL) + # if k == 1: + # return OneSumNode + # if k == 2: + # return TwoSumNode + # if k == 3: + # return ThreeSumNode + # if CMRdecIsGraphicLeaf(dec): + # if CMRdecIsCographicLeaf(dec): + # return PlanarNode + # return GraphicNode + # if CMRdecIsCographicLeaf(dec): + # return CographicNode + # if CMRdecIsSpecialLeaf(dec, NULL): + # return SpecialLeafNode + # if CMRdecIsSeriesParallelReduction(dec): + # return SeriesParallelReductionNode + # if CMRdecIsUnknown(dec): + # return UnknownNode + # return ThreeConnectedIrregularNode cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): From e2c523e831df4040a82e0bd33be24cfa8a1fe1ca Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 23 Feb 2024 09:18:51 -0800 Subject: [PATCH 100/262] WIP --- src/sage/libs/cmr/cmr.pxd | 70 +++++++++++------------ src/sage/matrix/matrix_cmr_sparse.pyx | 6 +- src/sage/matrix/seymour_decomposition.pyx | 18 +++--- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 66de5ab8f81..7072e64b4a6 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -488,7 +488,7 @@ cdef extern from "cmr/ctu.h": CMR_ERROR CMRctuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_PARAMS* params, CMR_CTU_STATS* stats, double timeLimit) -cdef extern from "balanced.h": +cdef extern from "cmr/balanced.h": ctypedef int CMR_BALANCED_ALGORITHM const int CMR_BALANCED_ALGORITHM_AUTO @@ -515,40 +515,40 @@ cdef extern from "balanced.h": CMR_ERROR CMRbalancedTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisBalanced, CMR_SUBMAT** psubmatrix, CMR_BALANCED_PARAMS* params, CMR_BALANCED_STATS* stats, double timeLimit) -cdef extern from "block_decomposition.h": - - ctypedef struct CMR_BLOCK: - CMR_MATRIX* matrix - CMR_MATRIX* transpose - size_t* rowsToOriginal - size_t* columnsToOriginal - - CMR_ERROR CMRdecomposeBlocks( - CMR* cmr, - CMR_MATRIX* matrix, - size_t matrixType, - size_t targetType, - size_t* pnumBlocks, - CMR_BLOCK** pblocks, - size_t* rowsToBlock, - size_t* columnsToBlock, - size_t* rowsToBlockRows, - size_t* columnsToBlockColumns - ) - - -cdef extern from "matrix_internal.h": - ctypedef struct CMR_MATRIX: - size_t numRows - size_t numColumns - size_t numNonzeros - size_t* rowSlice - size_t* entryColumns - void* entryValues - - CMR_ERROR CMRsortSubmatrix(CMR* cmr, CMR_SUBMAT* submatrix) - - CMR_ERROR CMRchrmatFilter(CMR* cmr, CMR_CHRMAT* matrix, size_t numRows, size_t* rows, size_t numColumns, size_t* columns, CMR_CHRMAT** presult) +# cdef extern from "cmr/block_decomposition.h": + +# ctypedef struct CMR_BLOCK: +# CMR_MATRIX* matrix +# CMR_MATRIX* transpose +# size_t* rowsToOriginal +# size_t* columnsToOriginal + +# CMR_ERROR CMRdecomposeBlocks( +# CMR* cmr, +# CMR_MATRIX* matrix, +# size_t matrixType, +# size_t targetType, +# size_t* pnumBlocks, +# CMR_BLOCK** pblocks, +# size_t* rowsToBlock, +# size_t* columnsToBlock, +# size_t* rowsToBlockRows, +# size_t* columnsToBlockColumns +# ) + + +# cdef extern from "cmr/matrix_internal.h": +# ctypedef struct CMR_MATRIX: +# size_t numRows +# size_t numColumns +# size_t numNonzeros +# size_t* rowSlice +# size_t* entryColumns +# void* entryValues + +# CMR_ERROR CMRsortSubmatrix(CMR* cmr, CMR_SUBMAT* submatrix) + +# CMR_ERROR CMRchrmatFilter(CMR* cmr, CMR_CHRMAT* matrix, size_t numRows, size_t* rows, size_t numColumns, size_t* columns, CMR_CHRMAT** presult) # Our global CMR environment diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index a797b082447..b31b70f456c 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1460,14 +1460,14 @@ cdef _cmr_dec_construct(param): return CMR_DEC_CONSTRUCT_ALL -cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS* params, dict kwds): +cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): CMR_CALL(CMRregularParamsInit(params)) params.directGraphicness = kwds['use_direct_graphicness_test'] params.seriesParallel = kwds['series_parallel_ok'] params.planarityCheck = kwds['check_graphic_minors_planar'] params.completeTree = kwds['complete_tree'] is True - params.matrices = _cmr_dec_construct(kwds['construct_matrices']) - params.transposes = _cmr_dec_construct(kwds['construct_transposes']) + # params.threeSumPivotChildren = _cmr_dec_construct(kwds['construct_matrices']) + # params.threeSumStrategy = _cmr_dec_construct(kwds['construct_transposes']) params.graphs = _cmr_dec_construct(kwds['construct_graphs']) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 011e59df1bc..5b1610d6bdf 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -451,17 +451,19 @@ cdef class BaseGraphicNode(DecompositionNode): sage: certificate.forest_edges() ((1, 2), (7, 1)) """ - cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) - return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + pass + # cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + # cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) + # cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) + # return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) @cached_method def coforest_edges(self): - cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) - return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + pass + # cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + # cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) + # cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) + # return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) cdef class GraphicNode(BaseGraphicNode): From 94a9cc430d6ce9957b41a1d5e6f3c2fc01b36df4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Feb 2024 17:55:55 -0800 Subject: [PATCH 101/262] src/sage/libs/cmr/cmr.pxd: Move import from cmr/element.h earlier --- src/sage/libs/cmr/cmr.pxd | 43 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 7072e64b4a6..d1474ab59ab 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -97,6 +97,20 @@ cdef extern from "cmr/camion.h": CMR_ERROR CMRcamionTestSigns(CMR* cmr, CMR_CHRMAT* matrix, bool* pisCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) CMR_ERROR CMRcamionComputeSigns(CMR* cmr, CMR_CHRMAT* matrix, bool* pwasCamionSigned, CMR_SUBMAT** psubmatrix, CMR_CAMION_STATISTICS* stats, double timeLimit) +cdef extern from "cmr/element.h": + + ctypedef int CMR_ELEMENT + + const char* CMRelementString(CMR_ELEMENT element, char* buffer) + bint CMRelementIsValid(CMR_ELEMENT element) + CMR_ELEMENT CMRrowToElement(size_t row) + CMR_ELEMENT CMRcolumnToElement(size_t column) + bint CMRelementIsRow(CMR_ELEMENT element) + size_t CMRelementToRowIndex(CMR_ELEMENT element) + bint CMRelementIsColumn(CMR_ELEMENT element) + size_t CMRelementToColumnIndex(CMR_ELEMENT element) + CMR_ELEMENT CMRelementTranspose(CMR_ELEMENT element) + cdef extern from "cmr/matroid.h": CMR_ERROR CMRchrmatBinaryPivot(CMR* cmr, CMR_CHRMAT* matrix, size_t pivotRow, size_t pivotColumn, CMR_CHRMAT** presult) @@ -166,46 +180,31 @@ cdef extern from "cmr/matroid.h": int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) - # CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) - # CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) - # CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) - # CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeCoforest(CMR_MATROID_DEC* dec) bool* CMRmatroiddecGraphArcsReversed(CMR_MATROID_DEC* dec) CMR_GRAPH* CMRmatroiddecCograph(CMR_MATROID_DEC* dec) size_t CMRmatroiddecCographSizeForest(CMR_MATROID_DEC* dec) - # CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecCographSizeCoforest(CMR_MATROID_DEC* dec) - # CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) + CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) bool* CMRmatroiddecCographArcsReversed(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) - # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) CMR_ERROR CMRmatroiddecUpdateOneSum(CMR* cmr, CMR_MATROID_DEC* dec, size_t numChildren) - -cdef extern from "cmr/element.h": - - ctypedef int CMR_ELEMENT - - const char* CMRelementString(CMR_ELEMENT element, char* buffer) - bint CMRelementIsValid(CMR_ELEMENT element) - CMR_ELEMENT CMRrowToElement(size_t row) - CMR_ELEMENT CMRcolumnToElement(size_t column) - bint CMRelementIsRow(CMR_ELEMENT element) - size_t CMRelementToRowIndex(CMR_ELEMENT element) - bint CMRelementIsColumn(CMR_ELEMENT element) - size_t CMRelementToColumnIndex(CMR_ELEMENT element) - CMR_ELEMENT CMRelementTranspose(CMR_ELEMENT element) - cdef extern from "cmr/separation.h": ctypedef int CMR_SEPA_FLAGS From 90adcfad63117bfd0de61f36f515b47d45ed94d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Feb 2024 17:58:52 -0800 Subject: [PATCH 102/262] src/sage/libs/cmr/cmr.pxd: Move import from cmr/graph.h earlier --- src/sage/libs/cmr/cmr.pxd | 114 +++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d1474ab59ab..1e2d0866a08 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -111,6 +111,63 @@ cdef extern from "cmr/element.h": size_t CMRelementToColumnIndex(CMR_ELEMENT element) CMR_ELEMENT CMRelementTranspose(CMR_ELEMENT element) +cdef extern from "cmr/graph.h": + + ctypedef int CMR_GRAPH_NODE + ctypedef int CMR_GRAPH_EDGE + ctypedef int CMR_GRAPH_ITER + + ctypedef struct CMR_GRAPH_NODE_DATA: + int prev + int next + int firstOut + + ctypedef struct CMR_GRAPH_ARC_DATA: + int target + int prev + int next + + ctypedef struct CMR_GRAPH: + size_t numNodes + size_t memNodes + CMR_GRAPH_NODE_DATA* nodes + int firstNode + int freeNode + size_t numEdges + size_t memEdges + CMR_GRAPH_ARC_DATA* arcs + int freeEdge + + size_t CMRgraphMemNodes(CMR_GRAPH* graph) + size_t CMRgraphNumNodes(CMR_GRAPH* graph) + size_t CMRgraphMemEdges(CMR_GRAPH* graph) + size_t CMRgraphNumEdges(CMR_GRAPH* graph) + CMR_GRAPH_NODE CMRgraphEdgeU(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_GRAPH_NODE CMRgraphEdgeV(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_ERROR CMRgraphCreateEmpty(CMR* cmr, CMR_GRAPH** pgraph, int memNodes, int memEdges) + CMR_ERROR CMRgraphFree(CMR* cmr, CMR_GRAPH** pgraph) + CMR_ERROR CMRgraphClear(CMR* cmr, CMR_GRAPH* graph) + CMR_ERROR CMRgraphAddNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE* pnode) + CMR_ERROR CMRgraphAddEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v, CMR_GRAPH_EDGE* pedge) + CMR_ERROR CMRgraphDeleteNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_ERROR CMRgraphDeleteEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_EDGE e) + CMR_GRAPH_NODE CMRgraphNodesFirst(CMR_GRAPH* graph) + bint CMRgraphNodesValid(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_GRAPH_NODE CMRgraphNodesNext(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + CMR_GRAPH_ITER CMRgraphIncFirst(CMR_GRAPH* graph, CMR_GRAPH_NODE v) + bint CMRgraphIncValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_ITER CMRgraphIncNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_EDGE CMRgraphIncEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_NODE CMRgraphIncSource(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_NODE CMRgraphIncTarget(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_ITER CMRgraphEdgesFirst(CMR_GRAPH* graph) + CMR_GRAPH_ITER CMRgraphEdgesNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + bint CMRgraphEdgesValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + CMR_GRAPH_EDGE CMRgraphEdgesEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) + # CMR_ERROR CMRgraphPrint(CMR_GRAPH* graph, FILE* stream) + CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) + # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) + cdef extern from "cmr/matroid.h": CMR_ERROR CMRchrmatBinaryPivot(CMR* cmr, CMR_CHRMAT* matrix, size_t pivotRow, size_t pivotColumn, CMR_CHRMAT** presult) @@ -242,63 +299,6 @@ cdef extern from "cmr/separation.h": CMR_ERROR CMRtwoSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker, CMR_ELEMENT secondMarker, int8_t characteristic, CMR_CHRMAT** presult) CMR_ERROR CMRthreeSum(CMR* cmr, CMR_CHRMAT* first, CMR_CHRMAT* second, CMR_ELEMENT firstMarker1, CMR_ELEMENT secondMarker1, CMR_ELEMENT firstMarker2, CMR_ELEMENT secondMarker2, int8_t characteristic, CMR_CHRMAT** presult) -cdef extern from "cmr/graph.h": - - ctypedef int CMR_GRAPH_NODE - ctypedef int CMR_GRAPH_EDGE - ctypedef int CMR_GRAPH_ITER - - ctypedef struct CMR_GRAPH_NODE_DATA: - int prev - int next - int firstOut - - ctypedef struct CMR_GRAPH_ARC_DATA: - int target - int prev - int next - - ctypedef struct CMR_GRAPH: - size_t numNodes - size_t memNodes - CMR_GRAPH_NODE_DATA* nodes - int firstNode - int freeNode - size_t numEdges - size_t memEdges - CMR_GRAPH_ARC_DATA* arcs - int freeEdge - - size_t CMRgraphMemNodes(CMR_GRAPH* graph) - size_t CMRgraphNumNodes(CMR_GRAPH* graph) - size_t CMRgraphMemEdges(CMR_GRAPH* graph) - size_t CMRgraphNumEdges(CMR_GRAPH* graph) - CMR_GRAPH_NODE CMRgraphEdgeU(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) - CMR_GRAPH_NODE CMRgraphEdgeV(CMR_GRAPH* graph, CMR_GRAPH_EDGE e) - CMR_ERROR CMRgraphCreateEmpty(CMR* cmr, CMR_GRAPH** pgraph, int memNodes, int memEdges) - CMR_ERROR CMRgraphFree(CMR* cmr, CMR_GRAPH** pgraph) - CMR_ERROR CMRgraphClear(CMR* cmr, CMR_GRAPH* graph) - CMR_ERROR CMRgraphAddNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE* pnode) - CMR_ERROR CMRgraphAddEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v, CMR_GRAPH_EDGE* pedge) - CMR_ERROR CMRgraphDeleteNode(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE v) - CMR_ERROR CMRgraphDeleteEdge(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_EDGE e) - CMR_GRAPH_NODE CMRgraphNodesFirst(CMR_GRAPH* graph) - bint CMRgraphNodesValid(CMR_GRAPH* graph, CMR_GRAPH_NODE v) - CMR_GRAPH_NODE CMRgraphNodesNext(CMR_GRAPH* graph, CMR_GRAPH_NODE v) - CMR_GRAPH_ITER CMRgraphIncFirst(CMR_GRAPH* graph, CMR_GRAPH_NODE v) - bint CMRgraphIncValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_ITER CMRgraphIncNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_EDGE CMRgraphIncEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_NODE CMRgraphIncSource(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_NODE CMRgraphIncTarget(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_ITER CMRgraphEdgesFirst(CMR_GRAPH* graph) - CMR_GRAPH_ITER CMRgraphEdgesNext(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - bint CMRgraphEdgesValid(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - CMR_GRAPH_EDGE CMRgraphEdgesEdge(CMR_GRAPH* graph, CMR_GRAPH_ITER i) - # CMR_ERROR CMRgraphPrint(CMR_GRAPH* graph, FILE* stream) - CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) - # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) - cdef extern from "cmr/graphic.h": ctypedef struct CMR_GRAPHIC_STATISTICS: From 2b1c63911297823e7cc273bc6a002041b6c7523d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Feb 2024 17:59:55 -0800 Subject: [PATCH 103/262] src/sage/libs/cmr/cmr.pxd: Comment out use of FILE * --- src/sage/libs/cmr/cmr.pxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 1e2d0866a08..0ac2698f056 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -257,7 +257,7 @@ cdef extern from "cmr/matroid.h": size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) - CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) CMR_ERROR CMRmatroiddecUpdateOneSum(CMR* cmr, CMR_MATROID_DEC* dec, size_t numChildren) From 1ad9dafd630ad357d389ddc7e502643bb9d3e96b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Feb 2024 18:01:18 -0800 Subject: [PATCH 104/262] build/pkgs/cmr/patches: Add https://github.com/discopt/cmr/pull/62 as a patch --- ...larity_internal.h-Add-missing-header.patch | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch diff --git a/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch b/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch new file mode 100644 index 00000000000..f71eaa8af4c --- /dev/null +++ b/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch @@ -0,0 +1,25 @@ +From eb6a7800c65f85151b4df86e5ce52f84326ff264 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Fri, 23 Feb 2024 17:47:52 -0800 +Subject: [PATCH] src/cmr/regularity_internal.h: Add missing header + +--- + src/cmr/regularity_internal.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/cmr/regularity_internal.h b/src/cmr/regularity_internal.h +index 119fd08..833c936 100644 +--- a/src/cmr/regularity_internal.h ++++ b/src/cmr/regularity_internal.h +@@ -1,6 +1,8 @@ + #ifndef CMR_REGULAR_INTERNAL_H + #define CMR_REGULAR_INTERNAL_H + ++#include ++ + #include + + #include "matroid_internal.h" +-- +2.42.0 + From a02de1fb1fe4f6e078927c6745349b8c5d36763f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 26 Feb 2024 09:32:26 -0800 Subject: [PATCH 105/262] fix class for node type --- src/sage/matrix/seymour_decomposition.pyx | 83 ++++++++++++++--------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 5b1610d6bdf..c2a9f7bf740 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -451,19 +451,17 @@ cdef class BaseGraphicNode(DecompositionNode): sage: certificate.forest_edges() ((1, 2), (7, 1)) """ - pass - # cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - # cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) - # cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) - # return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) + return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) @cached_method def coforest_edges(self): - pass - # cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - # cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) - # cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) - # return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) + cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) + return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) cdef class GraphicNode(BaseGraphicNode): @@ -522,7 +520,28 @@ cdef class SpecialLeafNode(DecompositionNode): r""" """ - pass + cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(self._dec) + import sage.matroids.matroids_catalog as matroids + from sage.graphs.graph_generators import graphs + from sage.matroids.matroid import Matroid + + if typ == CMR_MATROID_DEC_TYPE_R10: + return matroids.named_matroids.R10() + if typ == CMR_MATROID_DEC_TYPE_FANO: + return matroids.named_matroids.Fano() + if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: + return matroids.named_matroids.Fano().dual() + if typ == CMR_MATROID_DEC_TYPE_K5: + return matroids.CompleteGraphic(5) + if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: + return matroids.CompleteGraphic(5).dual() + if typ == CMR_MATROID_DEC_TYPE_K33: + E = 'abcdefghi' + G = graphs.CompleteBipartiteGraph(3, 3) + return Matroid(groundset=E, graph=G, regular=True) + if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: + return matroids.named_matroids.K33dual() + assert False, 'special leaf node with unknown type' # cdef int representation_matrix # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) # import sage.matroids.matroids_catalog as matroids @@ -561,27 +580,27 @@ cdef class SpecialLeafNode(DecompositionNode): # return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef _class(CMR_MATROID_DEC *dec): - pass - # k = CMRdecIsSum(dec, NULL, NULL) - # if k == 1: - # return OneSumNode - # if k == 2: - # return TwoSumNode - # if k == 3: - # return ThreeSumNode - # if CMRdecIsGraphicLeaf(dec): - # if CMRdecIsCographicLeaf(dec): - # return PlanarNode - # return GraphicNode - # if CMRdecIsCographicLeaf(dec): - # return CographicNode - # if CMRdecIsSpecialLeaf(dec, NULL): - # return SpecialLeafNode - # if CMRdecIsSeriesParallelReduction(dec): - # return SeriesParallelReductionNode - # if CMRdecIsUnknown(dec): - # return UnknownNode - # return ThreeConnectedIrregularNode + cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(dec) + + if typ == CMR_MATROID_DEC_TYPE_ONE_SUM: + return OneSumNode + if typ == CMR_MATROID_DEC_TYPE_TWO_SUM: + return TwoSumNode + if typ == CMR_MATROID_DEC_TYPE_THREE_SUM: + return ThreeSumNode + if typ == CMR_MATROID_DEC_TYPE_GRAPH: + if typ == CMR_MATROID_DEC_TYPE_COGRAPH: + return PlanarNode + return GraphicNode + if typ == CMR_MATROID_DEC_TYPE_COGRAPH: + return CographicNode + if typ < -1: + return SpecialLeafNode + if typ == CMR_MATROID_DEC_TYPE_SERIES_PARALLEL: + return SeriesParallelReductionNode + if typ == CMR_MATROID_DEC_TYPE_UNKNOWN: + return UnknownNode + return ThreeConnectedIrregularNode cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): From 0f6b2a31384a30759221cc3977d3e81c39c28541 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 26 Feb 2024 10:25:49 -0800 Subject: [PATCH 106/262] build/pkgs/cmr: Update to 4daea2e5ca6bbe9638c4f4e7dde4d660524608b3 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index b99d0e9d681..86d91003bd0 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=9f6fd03d6bea2ff692c368b07aae7f86e10aaee4 -md5=579a141647ef790809f6cd54e7cbb704 -cksum=4013467134 +sha1=2e3b291cdba4c481beb7d2ae4ac2fd64eb2a2899 +md5=73d846c492c481414ee1bbeb664420eb +cksum=3289370783 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index d23deef0026..a262c74a6e1 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -224beac5b4186dc6b3bbcbaf19d8e8ffdd63507a \ No newline at end of file +4daea2e5ca6bbe9638c4f4e7dde4d660524608b3 From 4910f3c1a4e1d3aabc922841f378e74948bbbbae Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 26 Feb 2024 11:25:05 -0800 Subject: [PATCH 107/262] fix parameters in tu test (remove construct_matrices) and fix an example in BaseGraphicNode --- build/pkgs/cmr/package-version.txt | 2 +- ...larity_internal.h-Add-missing-header.patch | 25 --------------- src/sage/libs/cmr/cmr.pxd | 20 +++--------- src/sage/matrix/matrix_cmr_sparse.pyx | 31 ++++++++++--------- src/sage/matrix/seymour_decomposition.pyx | 18 +++-------- 5 files changed, 25 insertions(+), 71 deletions(-) delete mode 100644 build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index a262c74a6e1..7ce09c65248 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -4daea2e5ca6bbe9638c4f4e7dde4d660524608b3 +4daea2e5ca6bbe9638c4f4e7dde4d660524608b3.p1 diff --git a/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch b/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch deleted file mode 100644 index f71eaa8af4c..00000000000 --- a/build/pkgs/cmr/patches/0001-src-cmr-regularity_internal.h-Add-missing-header.patch +++ /dev/null @@ -1,25 +0,0 @@ -From eb6a7800c65f85151b4df86e5ce52f84326ff264 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Fri, 23 Feb 2024 17:47:52 -0800 -Subject: [PATCH] src/cmr/regularity_internal.h: Add missing header - ---- - src/cmr/regularity_internal.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/cmr/regularity_internal.h b/src/cmr/regularity_internal.h -index 119fd08..833c936 100644 ---- a/src/cmr/regularity_internal.h -+++ b/src/cmr/regularity_internal.h -@@ -1,6 +1,8 @@ - #ifndef CMR_REGULAR_INTERNAL_H - #define CMR_REGULAR_INTERNAL_H - -+#include -+ - #include - - #include "matroid_internal.h" --- -2.42.0 - diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 0ac2698f056..cbd1868ab2a 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -363,8 +363,8 @@ cdef extern from "cmr/network.h": CMR_ERROR CMRnetworkStatsInit(CMR_NETWORK_STATISTICS* stats) # CMR_ERROR CMRstatsNetworkPrint(FILE* stream, CMR_NETWORK_STATISTICS* stats, const char* prefix) CMR_ERROR CMRnetworkComputeMatrix(CMR* cmr, CMR_GRAPH* digraph, CMR_CHRMAT** pmatrix, CMR_CHRMAT** ptranspose, bool* arcsReversed, int numForestArcs, CMR_GRAPH_EDGE* forestArcs, int numCoforestArcs, CMR_GRAPH_EDGE* coforestArcs, bool* pisCorrectForest) - CMR_ERROR CMRnetworkTestMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRnetworkTestTranspose(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRnetworkTestMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, bool* psupportIsGraphic, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRnetworkTestTranspose(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, bool* psupportIsCographic, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) cdef extern from "cmr/regular.h": @@ -516,6 +516,8 @@ cdef extern from "cmr/balanced.h": # cdef extern from "cmr/block_decomposition.h": +# ctypedef struct CMR_MATRIX + # ctypedef struct CMR_BLOCK: # CMR_MATRIX* matrix # CMR_MATRIX* transpose @@ -536,20 +538,6 @@ cdef extern from "cmr/balanced.h": # ) -# cdef extern from "cmr/matrix_internal.h": -# ctypedef struct CMR_MATRIX: -# size_t numRows -# size_t numColumns -# size_t numNonzeros -# size_t* rowSlice -# size_t* entryColumns -# void* entryValues - -# CMR_ERROR CMRsortSubmatrix(CMR* cmr, CMR_SUBMAT* submatrix) - -# CMR_ERROR CMRchrmatFilter(CMR* cmr, CMR_CHRMAT* matrix, size_t numRows, size_t* rows, size_t numColumns, size_t* columns, CMR_CHRMAT** presult) - - # Our global CMR environment cdef CMR *cmr diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b31b70f456c..afec7e0fca0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1163,6 +1163,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): Graphics object consisting of 21 graphics primitives """ cdef bool result + cdef bool support_result cdef CMR_GRAPH *digraph = NULL cdef CMR_GRAPH_EDGE* forest_arcs = NULL cdef CMR_GRAPH_EDGE* coforest_arcs = NULL @@ -1173,11 +1174,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: if certificate: - CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, &digraph, &forest_arcs, + CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, &support_result, &digraph, &forest_arcs, &coforest_arcs, &arcs_reversed, &submatrix, &stats, time_limit)) else: - CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, NULL, NULL, + CMR_CALL(CMRnetworkTestMatrix(cmr, self._mat, &result, &support_result, NULL, NULL, NULL, NULL, NULL, &stats, time_limit)) finally: sig_off() @@ -1203,8 +1204,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): series_parallel_ok=True, check_graphic_minors_planar=False, complete_tree='if_regular', - construct_matrices=False, - construct_transposes=False, + three_sum_pivot_children=False, + three_sum_strategy=None, construct_graphs=False): r""" Return whether the linear matroid of ``self`` over `\GF{2}` is regular. @@ -1317,8 +1318,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, complete_tree=complete_tree, - construct_matrices=construct_matrices, - construct_transposes=construct_transposes, + three_sum_pivot_children=three_sum_pivot_children, + three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) _set_cmr_regular_parameters(¶ms, kwds) @@ -1343,8 +1344,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): series_parallel_ok=True, check_graphic_minors_planar=False, complete_tree='if_regular', - construct_matrices=False, - construct_transposes=False, + three_sum_pivot_children=False, + three_sum_strategy=None, construct_graphs=False): r""" Return whether ``self`` is a totally unimodular matrix. @@ -1386,11 +1387,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): Full MatrixSpace of 6 by 14 sparse matrices over Integer Ring sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: MFR2cmr = Matrix_cmr_chr_sparse(MS2, MFR2) - sage: MFR2cmr.is_totally_unimodular(certificate=True, construct_matrices=True) + sage: MFR2cmr.is_totally_unimodular(certificate=True) (False, (None, ((0, 1, 2), (3, 4, 5)))) sage: result, certificate = MFR2cmr.is_totally_unimodular(certificate=True, - ....: complete_tree=True, - ....: construct_matrices=True) + ....: complete_tree=True) sage: result, certificate (False, (None, ((0, 1, 2), (3, 4, 5)))) sage: submatrix = MFR2.matrix_from_rows_and_columns(*certificate[1]); submatrix @@ -1413,8 +1413,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, complete_tree=complete_tree, - construct_matrices=construct_matrices, - construct_transposes=construct_transposes, + three_sum_pivot_children=three_sum_pivot_children, + three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION @@ -1466,8 +1466,9 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): params.seriesParallel = kwds['series_parallel_ok'] params.planarityCheck = kwds['check_graphic_minors_planar'] params.completeTree = kwds['complete_tree'] is True - # params.threeSumPivotChildren = _cmr_dec_construct(kwds['construct_matrices']) - # params.threeSumStrategy = _cmr_dec_construct(kwds['construct_transposes']) + params.threeSumPivotChildren = kwds['three_sum_pivot_children'] + if kwds['three_sum_strategy'] is not None: + params.threeSumStrategy = kwds['three_sum_strategy'] params.graphs = _cmr_dec_construct(kwds['construct_graphs']) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index c2a9f7bf740..48fa85e9bcc 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -68,13 +68,6 @@ cdef class DecompositionNode(SageObject): sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate (True, GraphicNode (3×2)) - sage: certificate.matrix() is None - True - - sage: result, certificate = M.is_totally_unimodular(certificate=True, - ....: construct_matrices=True) - sage: result, certificate - (True, GraphicNode (3×2)) sage: certificate.matrix() [ 1 0] [-1 1] @@ -115,8 +108,7 @@ cdef class DecompositionNode(SageObject): [ 0 0 1 0] [ 0 0 -1 1] [ 0 0 0 1] - sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, - ....: construct_matrices=True) + sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True) sage: result, certificate (True, OneSumNode (6×4) with 2 children) sage: C = certificate.summands(); C @@ -153,8 +145,7 @@ cdef class DecompositionNode(SageObject): [ 0 0 1 0] [ 0 0 -1 1] [ 0 0 0 1] - sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True, - ....: construct_matrices=True) + sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True) sage: T = certificate.as_ordered_tree(); T OneSumNode (6×4) with 2 children[GraphicNode (3×2)[], GraphicNode (3×2)[]] sage: unicode_art(T) @@ -176,8 +167,7 @@ cdef class DecompositionNode(SageObject): sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) sage: M2MT = block_diagonal_matrix([M, M, M.T], sparse=True) sage: M2MTcmr = Matrix_cmr_chr_sparse(M2MT.parent(), M2MT) - sage: result, certificate = M2MTcmr.is_totally_unimodular(certificate=True, - ....: construct_matrices=True) + sage: result, certificate = M2MTcmr.is_totally_unimodular(certificate=True) sage: T = certificate.as_ordered_tree() sage: T.plot() # needs sage.plot Graphics object consisting of 8 graphics primitives @@ -449,7 +439,7 @@ cdef class BaseGraphicNode(DecompositionNode): sage: result, certificate (True, GraphicNode (3×2)) sage: certificate.forest_edges() - ((1, 2), (7, 1)) + ((1, 2), (7, 1), (12, 7)) """ cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) From 82d163cab4a38ff54d39e50cac023eebba5a87a3 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 27 Feb 2024 10:32:07 -0800 Subject: [PATCH 108/262] add CompleteDecomposition --- src/sage/libs/cmr/cmr.pxd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index cbd1868ab2a..27e60938802 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -259,8 +259,7 @@ cdef extern from "cmr/matroid.h": size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) - CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) - CMR_ERROR CMRmatroiddecUpdateOneSum(CMR* cmr, CMR_MATROID_DEC* dec, size_t numChildren) + CMR_ERROR CMRmatroiddecFreeNode(CMR* cmr, CMR_MATROID_DEC** pdec) cdef extern from "cmr/separation.h": @@ -403,6 +402,7 @@ cdef extern from "cmr/regular.h": CMR_ERROR CMRregularStatsInit(CMR_REGULAR_STATS* stats) # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATS* stats, const char* prefix) CMR_ERROR CMRregularTest(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_MATROID_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRregularCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) cdef extern from "cmr/tu.h": @@ -434,6 +434,7 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRtuStatsInit(CMR_TU_STATS* stats) # CMR_ERROR CMRtuStatsPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) CMR_ERROR CMRtuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_MATROID_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) + CMR_ERROR CMRtuCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) cdef extern from "cmr/equimodular.h": From c50c5fa9dbdad76aaabc0e663d5acb74ebc5f76b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 27 Feb 2024 11:13:49 -0800 Subject: [PATCH 109/262] fix root dec node with no parent --- src/sage/matrix/seymour_decomposition.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 48fa85e9bcc..37e0b4b7866 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -14,6 +14,8 @@ Seymour's decomposition of totally unimodular matrices and regular matroids # https://www.gnu.org/licenses/ # **************************************************************************** +from libc.stdint cimport SIZE_MAX + from sage.libs.cmr.cmr cimport * from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ @@ -120,11 +122,11 @@ cdef class DecompositionNode(SageObject): """ cdef size_t *parent_rows = CMRmatroiddecRowsParent(self._dec) cdef size_t *parent_columns = CMRmatroiddecColumnsParent(self._dec) - if parent_rows == NULL: + if parent_rows == NULL or parent_rows[0] == SIZE_MAX: parent_rows_tuple = None else: parent_rows_tuple = tuple(parent_rows[i] for i in range(CMRmatroiddecNumRows(self._dec))) - if parent_columns == NULL: + if parent_columns == NULL or parent_columns[0] == SIZE_MAX: parent_columns_tuple = None else: parent_columns_tuple = tuple(parent_columns[i] for i in range(CMRmatroiddecNumColumns(self._dec))) From 6892f7aa48456799b8eca56cbacef799b2864987 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 27 Feb 2024 18:44:49 -0800 Subject: [PATCH 110/262] add PivotsNode --- src/sage/matrix/seymour_decomposition.pyx | 28 ++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 37e0b4b7866..ab25906d20b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -533,6 +533,8 @@ cdef class SpecialLeafNode(DecompositionNode): return Matroid(groundset=E, graph=G, regular=True) if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: return matroids.named_matroids.K33dual() + if typ == CMR_MATROID_DEC_TYPE_DETERMINANT: + return '|det| = 2 submatrix' assert False, 'special leaf node with unknown type' # cdef int representation_matrix # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) @@ -571,6 +573,24 @@ cdef class SpecialLeafNode(DecompositionNode): # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) # return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) + +cdef class PivotsNode(DecompositionNode): + def npivots(self): + return CMRmatroiddecNumPivots(self._dec) + + @cached_method + def pivot_rows_and_columns(self): + r""" + """ + cdef size_t *pivot_rows = CMRmatroiddecPivotRows(self._dec) + cdef size_t *pivot_columns = CMRmatroiddecPivotColumns(self._dec) + + return tuple((pivot_rows[i], pivot_columns[i]) for i in range(self.npivots())) + + +cdef class SubmatrixNode(DecompositionNode): + pass + cdef _class(CMR_MATROID_DEC *dec): cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(dec) @@ -590,9 +610,15 @@ cdef _class(CMR_MATROID_DEC *dec): return SpecialLeafNode if typ == CMR_MATROID_DEC_TYPE_SERIES_PARALLEL: return SeriesParallelReductionNode + if typ == CMR_MATROID_DEC_TYPE_PIVOTS: + return PivotsNode + if typ == CMR_MATROID_DEC_TYPE_SUBMATRIX: + return SubmatrixNode + if typ == CMR_MATROID_DEC_TYPE_IRREGULAR: + return ThreeConnectedIrregularNode if typ == CMR_MATROID_DEC_TYPE_UNKNOWN: return UnknownNode - return ThreeConnectedIrregularNode + assert NotImplementedError cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): From bd0cae8f49cdea924c98c685b4f99344de21f192 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 28 Feb 2024 09:31:11 -0800 Subject: [PATCH 111/262] add threesum distributed_ranks or concentrated_rank --- src/sage/matrix/seymour_decomposition.pyx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ab25906d20b..b93650ee7a8 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -176,6 +176,12 @@ cdef class DecompositionNode(SageObject): """ return self.as_ordered_tree().plot(**kwds) + def is_ternary(self): + r""" + Returns true iff the decomposition is over `\mathbb{F}_3`. + """ + return CMRmatroiddecIsTernary(self._dec) + @cached_method def _children(self): r""" @@ -395,6 +401,12 @@ cdef class TwoSumNode(SumNode): cdef class ThreeSumNode(SumNode): + def is_distributed_ranks(self): + return CMRmatroiddecThreeSumDistributedRanks(self._dec) + + def is_concentrated_rank(self): + return CMRmatroiddecThreeSumConcentratedRank(self._dec) + def block_matrix_form(self): M1, M2 = self.summand_matrices() x, y= len(M1.columns()), len(M2.columns()) From f0cdd85ebd37d899358d82658d76a759ba872736 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 28 Feb 2024 09:58:18 -0800 Subject: [PATCH 112/262] add binary and ternary pivot --- src/sage/matrix/matrix_cmr_sparse.pyx | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index afec7e0fca0..e820c3ed5f0 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -731,6 +731,62 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_list.append(x) return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + def binary_pivot(self, row, column): + cdef Matrix_cmr_chr_sparse result + cdef size_t pivot_row = row + cdef size_t pivot_column = column + cdef CMR_CHRMAT *result_mat + + CMR_CALL(CMRchrmatBinaryPivot(cmr, self._mat, pivot_row, pivot_column, &result_mat)) + result = Matrix_cmr_chr_sparse._from_cmr(result_mat) + return result + + def binary_pivots(self, rows, columns): + cdef Matrix_cmr_chr_sparse result + cdef size_t* pivot_rows + cdef size_t* pivot_columns + cdef CMR_CHRMAT *result_mat + + npivots = len(rows) + if len(columns) != npivots: + raise ValueError("The pivot rows and columns must have the same length") + + for i in range(npivots): + pivot_rows[i] = rows[i] + pivot_columns[i] = columns[i] + + CMR_CALL(CMRchrmatBinaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) + result = Matrix_cmr_chr_sparse._from_cmr(result_mat) + return result + + def ternary_pivot(self, row, column): + cdef Matrix_cmr_chr_sparse result + cdef size_t pivot_row = row + cdef size_t pivot_column = column + cdef CMR_CHRMAT *result_mat + + CMR_CALL(CMRchrmatTernaryPivot(cmr, self._mat, pivot_row, pivot_column, &result_mat)) + result = Matrix_cmr_chr_sparse._from_cmr(result_mat) + return result + + def ternary_pivots(self, rows, columns): + cdef Matrix_cmr_chr_sparse result + cdef size_t* pivot_rows + cdef size_t* pivot_columns + cdef CMR_CHRMAT *result_mat + + cdef size_t npivots = len(rows) + if len(columns) != npivots: + raise ValueError("The pivot rows and columns must have the same length") + + for i in range(npivots): + pivot_rows[i] = rows[i] + pivot_columns[i] = columns[i] + + CMR_CALL(CMRchrmatTernaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) + result = Matrix_cmr_chr_sparse._from_cmr(result_mat) + return result + def is_unimodular(self, time_limit=60.0): r""" Return whether ``self`` is a unimodular matrix. From 2eaca20809a17a3cf814a262b4f97512634a22e8 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 28 Feb 2024 11:14:22 -0800 Subject: [PATCH 113/262] fix the output of is_ternary is_distributed_ranks --- src/sage/matrix/seymour_decomposition.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b93650ee7a8..f6a1a86748e 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -180,7 +180,7 @@ cdef class DecompositionNode(SageObject): r""" Returns true iff the decomposition is over `\mathbb{F}_3`. """ - return CMRmatroiddecIsTernary(self._dec) + return CMRmatroiddecIsTernary(self._dec) @cached_method def _children(self): @@ -402,10 +402,10 @@ cdef class TwoSumNode(SumNode): cdef class ThreeSumNode(SumNode): def is_distributed_ranks(self): - return CMRmatroiddecThreeSumDistributedRanks(self._dec) + return CMRmatroiddecThreeSumDistributedRanks(self._dec) def is_concentrated_rank(self): - return CMRmatroiddecThreeSumConcentratedRank(self._dec) + return CMRmatroiddecThreeSumConcentratedRank(self._dec) def block_matrix_form(self): M1, M2 = self.summand_matrices() From c887abb96fb12cda9779504fd1013ca43649f4ea Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 28 Feb 2024 12:40:39 -0800 Subject: [PATCH 114/262] three_sum_pivot_children should be False --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e820c3ed5f0..276e7a185b4 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1465,6 +1465,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef CMR_MATROID_DEC **pdec = &dec cdef CMR_SUBMAT **psubmat = &submat + if three_sum_pivot_children: + raise NotImplementedError cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, From de9a82989b79a93e125caf1e808e77ea402b8f6f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 29 Feb 2024 12:23:49 -0800 Subject: [PATCH 115/262] add three_sum_cmr --- src/sage/matrix/matrix_cmr_sparse.pyx | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 276e7a185b4..4f707226d2f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -581,6 +581,72 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum.set_immutable() return sum + def three_sum_cmr(first_mat, second_mat, + first_index1, first_index2, second_index1, second_index2, + three_sum_strategy="distributed_ranks"): + r""" + + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 5, 6]]); M1 + [1 2 3] + [4 5 6] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[7, 8, 9], [-1, -2, -3]]); M2 + [ 7 8 9] + [-1 -2 -3] + """ + cdef Matrix_cmr_chr_sparse sum, first, second + cdef CMR_CHRMAT *sum_mat + first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) + second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) + + if three_sum_strategy not in ["distributed_ranks", "concentrated_rank"]: + raise ValueError("Unknown three sum mode", three_sum_strategy) + + if three_sum_strategy == "distributed_ranks": + row1 = first_index1 + column2 = first_index2 + column1 = second_index1 + row2 = second_index2 + if row1 < 0 or row1 >= first._mat.numRows: + raise ValueError("First marker 1 should be a row index of the first matrix") + if column2 < 0 or column2 >= first._mat.numColumns: + raise ValueError("First marker 2 should be a column index of the first matrix") + if column1 < 0 or column1 >= second._mat.numColumns: + raise ValueError("Second marker 1 should be a column index of the second matrix") + if row2 < 0 or row2 >= second._mat.numRows: + raise ValueError("Second marker 2 should be a row index of the second matrix") + first_marker1 = CMRrowToElement(row1) + first_marker2 = CMRcolumnToElement(column2) + second_marker1 = CMRcolumnToElement(column1) + second_marker2 = CMRrowToElement(row2) + else: + row1 = first_index1 + row2 = first_index2 + column1 = second_index1 + column2 = second_index2 + if row1 < 0 or row1 >= first._mat.numRows: + raise ValueError("First marker 1 should be a Row index of the first matrix") + if row2 < 0 or row2 >= first._mat.numRows: + raise ValueError("First marker 2 should be a Row index of the first matrix") + if column1 < 0 or column1 >= second._mat.numColumns: + raise ValueError("Second marker 1 should be a column index of the second matrix") + if column2 < 0 or column2 >= second._mat.numColumns: + raise ValueError("Second marker 2 should be a column index of the second matrix") + first_marker1 = CMRrowToElement(row1) + first_marker2 = CMRrowToElement(row2) + second_marker1 = CMRcolumnToElement(column1) + second_marker2 = CMRcolumnToElement(column2) + + cdef int8_t characteristic = 0 + CMR_CALL(CMRthreeSum(cmr, first._mat, second._mat, first_marker1, second_marker1, first_marker2, second_marker2, characteristic, &sum_mat)) + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat) + return sum + def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and From c3d6a10b1a79f4baec6be3564ea16005b7ab4543 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 29 Feb 2024 13:16:46 -0800 Subject: [PATCH 116/262] add PivotsNode example --- src/sage/matrix/seymour_decomposition.pyx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index f6a1a86748e..283eebaf0db 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -593,6 +593,22 @@ cdef class PivotsNode(DecompositionNode): @cached_method def pivot_rows_and_columns(self): r""" + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: certificate + PivotsNode (9×12) + sage: certificate.pivot_rows_and_columns() + ((1, 8),) """ cdef size_t *pivot_rows = CMRmatroiddecPivotRows(self._dec) cdef size_t *pivot_columns = CMRmatroiddecPivotColumns(self._dec) From 659b274d560674e62ee264436a3b0e5f02198c76 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 29 Feb 2024 13:19:26 -0800 Subject: [PATCH 117/262] build/pkgs/cmr: Update to 8b0dda14be73d9afc5eeda1461191b2b062072db --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 86d91003bd0..a18c1299e8e 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=2e3b291cdba4c481beb7d2ae4ac2fd64eb2a2899 -md5=73d846c492c481414ee1bbeb664420eb -cksum=3289370783 +sha1=6e55e008de787217fa5b021c693100b98365b311 +md5=51844915d4bcd1200a18a46e8ce764f2 +cksum=3720610576 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 7ce09c65248..1e987aadd6f 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -4daea2e5ca6bbe9638c4f4e7dde4d660524608b3.p1 +8b0dda14be73d9afc5eeda1461191b2b062072db From 0ed6c892231fa02d3fffea8bc2c5fd3c751d6bed Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 4 Mar 2024 09:14:47 -0800 Subject: [PATCH 118/262] change characteristic to MatrixSpace.characteristic() --- src/sage/matrix/matrix_cmr_sparse.pyx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4f707226d2f..7009ce21f4d 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -573,7 +573,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): first_marker = CMRrowToElement(row) second_marker = CMRcolumnToElement(column) - cdef int8_t characteristic = 0 + cdef int8_t characteristic = first_mat.parent().characteristic() + + if second_mat.parent().characteristic() != characteristic: + raise ValueError("The characteristic of two matrices are different") + CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, first_marker, second_marker, characteristic, &sum_mat)) sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: @@ -642,7 +646,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): second_marker1 = CMRcolumnToElement(column1) second_marker2 = CMRcolumnToElement(column2) - cdef int8_t characteristic = 0 + cdef int8_t characteristic = first_mat.parent().characteristic() + + if second_mat.parent().characteristic() != characteristic: + raise ValueError("The characteristic of two matrices are different") + CMR_CALL(CMRthreeSum(cmr, first._mat, second._mat, first_marker1, second_marker1, first_marker2, second_marker2, characteristic, &sum_mat)) sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat) return sum From 1644a52a6cc96f7d0240502a2a915b1169808ea1 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 4 Mar 2024 09:55:53 -0800 Subject: [PATCH 119/262] build/pkgs/cmr: Update to 33415103202d46b1bd1f4832f83494fbe583bc1b --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index a18c1299e8e..6c4f1df1afb 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=6e55e008de787217fa5b021c693100b98365b311 -md5=51844915d4bcd1200a18a46e8ce764f2 -cksum=3720610576 +sha1=e38b305f32db415f75d6d76b30f9f40e5c116d8f +md5=99db21d9919fd357a16b4a2efa2da0ed +cksum=80832571 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 1e987aadd6f..86300fa4b75 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -8b0dda14be73d9afc5eeda1461191b2b062072db +33415103202d46b1bd1f4832f83494fbe583bc1b From a6151935f82691f4e947aaef25532aaea5be51c0 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 4 Mar 2024 10:06:21 -0800 Subject: [PATCH 120/262] change size_t to CMR_ELEMENT --- src/sage/libs/cmr/cmr.pxd | 8 +++----- src/sage/matrix/seymour_decomposition.pyx | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 27e60938802..e5cb9ca1f9b 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -237,11 +237,9 @@ cdef extern from "cmr/matroid.h": int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecRowsRootElement(CMR_MATROID_DEC* dec) - size_t* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecColumnsRootElement(CMR_MATROID_DEC* dec) - size_t* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) @@ -257,7 +255,7 @@ cdef extern from "cmr/matroid.h": size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) - # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentRowsColumns, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) CMR_ERROR CMRmatroiddecFreeNode(CMR* cmr, CMR_MATROID_DEC** pdec) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 283eebaf0db..18be6b34608 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -120,8 +120,8 @@ cdef class DecompositionNode(SageObject): sage: C[1].parent_rows_and_columns() ((3, 4, 5), (2, 3)) """ - cdef size_t *parent_rows = CMRmatroiddecRowsParent(self._dec) - cdef size_t *parent_columns = CMRmatroiddecColumnsParent(self._dec) + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) if parent_rows == NULL or parent_rows[0] == SIZE_MAX: parent_rows_tuple = None else: From 96b26ca9a909d995960ea84523764f95df9d0e6e Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Mar 2024 08:23:12 -0800 Subject: [PATCH 121/262] build/pkgs/cmr: Update to 7abbabe27e9a0a05e5c8f4ae19a2e7c5c8c07bc9 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 6c4f1df1afb..c1705d3be2d 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=e38b305f32db415f75d6d76b30f9f40e5c116d8f -md5=99db21d9919fd357a16b4a2efa2da0ed -cksum=80832571 +sha1=f0849b3e0f3957542ef97cf5ebb9cd24d3689153 +md5=8cc9d68d12401474ca0487d33408694f +cksum=3197857397 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 86300fa4b75..32d48680fc2 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -33415103202d46b1bd1f4832f83494fbe583bc1b +7abbabe27e9a0a05e5c8f4ae19a2e7c5c8c07bc9 From b200052171be04bcc9d1a53eaf8c8658dce79617 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Mar 2024 09:25:53 -0800 Subject: [PATCH 122/262] fix row and column indices --- src/sage/matrix/seymour_decomposition.pyx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 18be6b34608..6b6ec66a3ef 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -122,14 +122,16 @@ cdef class DecompositionNode(SageObject): """ cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) - if parent_rows == NULL or parent_rows[0] == SIZE_MAX: + if parent_rows == NULL or parent_rows[0] == 0: parent_rows_tuple = None else: - parent_rows_tuple = tuple(parent_rows[i] for i in range(CMRmatroiddecNumRows(self._dec))) - if parent_columns == NULL or parent_columns[0] == SIZE_MAX: + parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) + for i in range(self.nrows())) + if parent_columns == NULL or parent_columns[0] == 0: parent_columns_tuple = None else: - parent_columns_tuple = tuple(parent_columns[i] for i in range(CMRmatroiddecNumColumns(self._dec))) + parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) + for i in range(self.ncols())) return parent_rows_tuple, parent_columns_tuple @@ -182,6 +184,12 @@ cdef class DecompositionNode(SageObject): """ return CMRmatroiddecIsTernary(self._dec) + def nchildren(self): + r""" + Returns the number of children of the node. + """ + return CMRmatroiddecNumChildren(self._dec) + @cached_method def _children(self): r""" @@ -221,10 +229,8 @@ cdef class DecompositionNode(SageObject): sage: certificate._children() () """ - return tuple(sorted((create_DecompositionNode(CMRmatroiddecChild(self._dec, index), - self._root or self) - for index in range(CMRmatroiddecNumChildren(self._dec))), - key=lambda node: node.parent_rows_and_columns())) + return tuple(create_DecompositionNode(CMRmatroiddecChild(self._dec, index), self) + for index in range(self.nchildren())) def _repr_(self): nrows, ncols = self.dimensions() From 75e1bb082c1300ad5999658d239499dc417fa4e4 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Mar 2024 09:31:05 -0800 Subject: [PATCH 123/262] add back self._root --- src/sage/matrix/seymour_decomposition.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 6b6ec66a3ef..e40928e8992 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -229,7 +229,7 @@ cdef class DecompositionNode(SageObject): sage: certificate._children() () """ - return tuple(create_DecompositionNode(CMRmatroiddecChild(self._dec, index), self) + return tuple(create_DecompositionNode(CMRmatroiddecChild(self._dec, index), self._root or self) for index in range(self.nchildren())) def _repr_(self): From 37f394f01b487193e58b8d7a250789c5704fc10f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Mar 2024 10:23:17 -0800 Subject: [PATCH 124/262] initial attemp to use label for pivot nodes --- src/sage/matrix/seymour_decomposition.pyx | 122 +++++++++++++++++----- 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index e40928e8992..c028617da34 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -86,7 +86,25 @@ cdef class DecompositionNode(SageObject): return result @cached_method - def parent_rows_and_columns(self): + def _parent_rows_and_columns(self): + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) + + if parent_rows == NULL or parent_rows[0] == 0: + parent_rows_cmr_tuple = None + else: + parent_rows_cmr_tuple = tuple(parent_rows[i] + for i in range(self.nrows())) + if parent_columns == NULL or parent_columns[0] == 0: + parent_columns_cmr_tuple = None + else: + parent_columns_cmr_tuple = tuple(parent_columns[i] + for i in range(self.ncols())) + + return parent_rows_cmr_tuple, parent_columns_cmr_tuple + + @cached_method + def parent_rows_and_columns(self, indices_label=False): r""" EXAMPLES:: @@ -119,18 +137,54 @@ cdef class DecompositionNode(SageObject): ((0, 1, 2), (0, 1)) sage: C[1].parent_rows_and_columns() ((3, 4, 5), (2, 3)) + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: C = certificate._children()[0]; C + ThreeSumNode (9×12) with 2 children + sage: C.parent_rows_and_columns(indices_label=True) + ((('r', 0), + ('c', 8), + ('r', 2), + ('r', 3), + ('r', 4), + ('r', 5), + ('r', 6), + ('r', 7), + ('r', 8)), + (('c', 0), + ('c', 1), + ('c', 2), + ('c', 3), + ('c', 4), + ('c', 5), + ('c', 6), + ('c', 7), + ('r', 1), + ('c', 9), + ('c', 10), + ('c', 11))) """ - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) - if parent_rows == NULL or parent_rows[0] == 0: + parent_rows, parent_columns = self._parent_rows_and_columns() + if parent_rows is None: parent_rows_tuple = None else: - parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) - for i in range(self.nrows())) - if parent_columns == NULL or parent_columns[0] == 0: + parent_rows_tuple = tuple(CMRelement_to_label(parent_rows[i], indices_label) + for i in range(self.nrows())) + if parent_columns is None: parent_columns_tuple = None else: - parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) + parent_columns_tuple = tuple(CMRelement_to_label(parent_columns[i], indices_label) for i in range(self.ncols())) return parent_rows_tuple, parent_columns_tuple @@ -599,22 +653,24 @@ cdef class PivotsNode(DecompositionNode): @cached_method def pivot_rows_and_columns(self): r""" - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) - sage: result, certificate = R12.is_totally_unimodular(certificate=True) - sage: certificate - PivotsNode (9×12) - sage: certificate.pivot_rows_and_columns() - ((1, 8),) + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: certificate + PivotsNode (9×12) + sage: certificate.pivot_rows_and_columns() + ((1, 8),) """ cdef size_t *pivot_rows = CMRmatroiddecPivotRows(self._dec) cdef size_t *pivot_columns = CMRmatroiddecPivotColumns(self._dec) @@ -625,6 +681,7 @@ cdef class PivotsNode(DecompositionNode): cdef class SubmatrixNode(DecompositionNode): pass + cdef _class(CMR_MATROID_DEC *dec): cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(dec) @@ -671,3 +728,20 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) return result + + +cdef CMRelement_to_label(CMR_ELEMENT element, indices_label=False): + r""" + """ + if not CMRelementIsValid(element): + raise ValueError('CMRelement index not valid') + if CMRelementIsRow(element): + if indices_label: + return ('r',CMRelementToRowIndex(element)) + else: + return CMRelementToRowIndex(element) + else: + if indices_label: + return ('c', CMRelementToColumnIndex(element)) + else: + return CMRelementToColumnIndex(element) \ No newline at end of file From 14fe51fa9821c47f1ced9f33758154004fcf915b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 7 Mar 2024 09:41:43 -0800 Subject: [PATCH 125/262] add is_distributed_ranks example --- src/sage/matrix/seymour_decomposition.pyx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index c028617da34..32ee54d8af8 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -462,6 +462,28 @@ cdef class TwoSumNode(SumNode): cdef class ThreeSumNode(SumNode): def is_distributed_ranks(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: C = certificate._children()[0]; C + ThreeSumNode (9×12) with 2 children + sage: C.is_distributed_ranks() + True + sage: C.is_concentrated_rank() + False + """ return CMRmatroiddecThreeSumDistributedRanks(self._dec) def is_concentrated_rank(self): From ca910755adbab2758a3361e9bb7595ad972ced84 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 7 Mar 2024 10:13:01 -0800 Subject: [PATCH 126/262] add two_sum example from cmr --- src/sage/matrix/matrix_cmr_sparse.pyx | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 7009ce21f4d..e4cb9e2ce75 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -537,6 +537,52 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-----------+-------] [ 32 40 48| 7 9] [ -8 -10 -12| -1 -3] + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 0, 0, 0], + ....: [1, 0, 1,-1, 1], + ....: [0,-1, 1, 0,-1], + ....: [0, 0,-1, 1, 0], + ....: [0, 1, 1, 0, 1]]); M1 + [ 1 1 0 0 0] + [ 1 0 1 -1 1] + [ 0 -1 1 0 -1] + [ 0 0 -1 1 0] + [ 0 1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1,-1, 1, 0, 0], + ....: [1, 1, 1, 1,-1], + ....: [0, 0,-1, 0, 1], + ....: [1, 0, 0,-1, 0], + ....: [0, 1, 0, 0, 1]]); M2 + [ 1 -1 1 0 0] + [ 1 1 1 1 -1] + [ 0 0 -1 0 1] + [ 1 0 0 -1 0] + [ 0 1 0 0 1] + sage: M1.two_sum(M2, 1, 2, nonzero_block="bottom_left") + [ 1 1 0 0 0| 0 0 0 0] + [ 0 -1 1 0 -1| 0 0 0 0] + [ 0 0 -1 1 0| 0 0 0 0] + [ 0 1 1 0 1| 0 0 0 0] + [--------------+-----------] + [ 1 0 1 -1 1| 1 -1 0 0] + [ 1 0 1 -1 1| 1 1 1 -1] + [-1 0 -1 1 -1| 0 0 0 1] + [ 0 0 0 0 0| 1 0 -1 0] + [ 0 0 0 0 0| 0 1 0 1] + sage: M1.two_sum(M2, 4, 0) + [ 1 1 0 0| 0 0 0 0 0] + [ 1 0 1 -1| 1 -1 1 0 0] + [ 0 -1 1 0|-1 1 -1 0 0] + [ 0 0 -1 1| 0 0 0 0 0] + [ 0 1 1 0| 1 -1 1 0 0] + [-----------+--------------] + [ 0 0 0 0| 1 1 1 1 -1] + [ 0 0 0 0| 0 0 -1 0 1] + [ 0 0 0 0| 1 0 0 -1 0] + [ 0 0 0 0| 0 1 0 0 1] """ cdef Matrix_cmr_chr_sparse sum, first, second cdef CMR_CHRMAT *sum_mat From 1620a7d8cc50a921a61df7409f475f1436ad68b5 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 7 Mar 2024 11:19:25 -0800 Subject: [PATCH 127/262] fix TwoSumNode block_matrix_form --- src/sage/matrix/seymour_decomposition.pyx | 122 ++++++++++++++++------ 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 32ee54d8af8..1ef9a4ca742 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -427,7 +427,9 @@ cdef class OneSumNode(SumNode): cdef class TwoSumNode(SumNode): - r""" + + def block_matrix_form(self): + r""" EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -453,11 +455,90 @@ cdef class TwoSumNode(SumNode): [0 0 0 0|1 1 0 0 1] sage: result, certificate = M3.is_totally_unimodular(certificate=True); certificate TwoSumNode (9×9) with 2 children - """ - def block_matrix_form(self): + + sage: K33 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 4, sparse=True), + ....: [[1, 1, 0, 0], [1, 1, 1, 0], + ....: [1, 0, 0,-1], [0, 1, 1, 1], + ....: [0, 0, 1, 1]]); K33 + [ 1 1 0 0] + [ 1 1 1 0] + [ 1 0 0 -1] + [ 0 1 1 1] + [ 0 0 1 1] + sage: K33_dual = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[1, 1, 1, 0, 0], [1, 1, 0, 1, 0], + ....: [0, 1, 0, 1, 1], [0, 0,-1, 1, 1]]); K33_dual + [ 1 1 1 0 0] + [ 1 1 0 1 0] + [ 0 1 0 1 1] + [ 0 0 -1 1 1] + sage: M = Matrix_cmr_chr_sparse.two_sum(K33, K33_dual, 0, 0, + ....: nonzero_block="bottom_left"); M + [ 1 1 1 0| 0 0 0 0] + [ 1 0 0 -1| 0 0 0 0] + [ 0 1 1 1| 0 0 0 0] + [ 0 0 1 1| 0 0 0 0] + [-----------+-----------] + [ 1 1 0 0| 1 1 0 0] + [ 1 1 0 0| 1 0 1 0] + [ 0 0 0 0| 1 0 1 1] + [ 0 0 0 0| 0 -1 1 1] + sage: result1, certificate1 = M.is_totally_unimodular(certificate=True); certificate1 + TwoSumNode (8×8) with 2 children + sage: certificate1.summand_matrices() + ( + [ 1 1 1 0] + [ 1 0 0 -1] [ 1 1 1 0 0] + [ 0 1 1 1] [ 1 1 0 1 0] + [ 0 0 1 1] [ 0 1 0 1 1] + [ 1 1 0 0], [ 0 0 -1 1 1] + ) + sage: certificate1.block_matrix_form() + [ 1 1 1 0| 0 0 0 0] + [ 1 0 0 -1| 0 0 0 0] + [ 0 1 1 1| 0 0 0 0] + [ 0 0 1 1| 0 0 0 0] + [-----------+-----------] + [ 1 1 0 0| 1 1 0 0] + [ 1 1 0 0| 1 0 1 0] + [ 0 0 0 0| 1 0 1 1] + [ 0 0 0 0| 0 -1 1 1] + sage: [M.parent_rows_and_columns() for M in certificate1._children()] + [((0, 1, 2, 3, 4), (0, 1, 2, 3)), ((4, 5, 6, 7), (0, 4, 5, 6, 7))] + sage: M_perm = M.matrix_from_rows_and_columns([4, 6, 5, 7, 0, 1, 2, 3], range(M.ncols())) + sage: M_perm + [ 1 1 0 0 1 1 0 0] + [ 0 0 0 0 1 0 1 1] + [ 1 1 0 0 1 0 1 0] + [ 0 0 0 0 0 -1 1 1] + [ 1 1 1 0 0 0 0 0] + [ 1 0 0 -1 0 0 0 0] + [ 0 1 1 1 0 0 0 0] + [ 0 0 1 1 0 0 0 0] + sage: result2, certificate2 = M_perm.is_totally_unimodular(certificate=True) + sage: certificate2.summand_matrices() + ( + [ 1 1 1 0] + [ 1 0 0 -1] [ 1 1 1 0 0] + [ 0 1 1 1] [ 0 1 0 1 1] + [ 0 0 1 1] [ 1 1 0 1 0] + [ 1 1 0 0], [ 0 0 -1 1 1] + ) + sage: certificate2.block_matrix_form() + [ 1 1 1 0| 0 0 0 0] + [ 1 0 0 -1| 0 0 0 0] + [ 0 1 1 1| 0 0 0 0] + [ 0 0 1 1| 0 0 0 0] + [-----------+-----------] + [ 1 1 0 0| 1 1 0 0] + [ 0 0 0 0| 1 0 1 1] + [ 1 1 0 0| 1 0 1 0] + [ 0 0 0 0| 0 -1 1 1] + sage: [M.parent_rows_and_columns() for M in certificate2._children()] + [((4, 5, 6, 7, 0), (0, 1, 2, 3)), ((0, 1, 2, 3), (0, 4, 5, 6, 7))] + """ M1, M2 = self.summand_matrices() - x, y= len(M1.columns()), len(M2.rows()) - return Matrix_cmr_chr_sparse.two_sum(M1, M2, x - 1, y - 1) + return Matrix_cmr_chr_sparse.two_sum(M1, M2, M1.nrows() - 1, 0, "bottom_left") cdef class ThreeSumNode(SumNode): @@ -612,11 +693,11 @@ cdef class SpecialLeafNode(DecompositionNode): from sage.matroids.matroid import Matroid if typ == CMR_MATROID_DEC_TYPE_R10: - return matroids.named_matroids.R10() + return matroids.catalog.R10() if typ == CMR_MATROID_DEC_TYPE_FANO: - return matroids.named_matroids.Fano() + return matroids.catalog.Fano() if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: - return matroids.named_matroids.Fano().dual() + return matroids.catalog.Fano().dual() if typ == CMR_MATROID_DEC_TYPE_K5: return matroids.CompleteGraphic(5) if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: @@ -626,33 +707,10 @@ cdef class SpecialLeafNode(DecompositionNode): G = graphs.CompleteBipartiteGraph(3, 3) return Matroid(groundset=E, graph=G, regular=True) if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: - return matroids.named_matroids.K33dual() + return matroids.catalog.K33dual() if typ == CMR_MATROID_DEC_TYPE_DETERMINANT: return '|det| = 2 submatrix' assert False, 'special leaf node with unknown type' - # cdef int representation_matrix - # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) - # import sage.matroids.matroids_catalog as matroids - # from sage.graphs.graph_generators import graphs - # from sage.matroids.matroid import Matroid - - # if typ == CMR_MATROID_DEC_TYPE_R10: - # return matroids.named_matroids.R10() - # if typ == CMR_MATROID_DEC_TYPE_FANO: - # return matroids.named_matroids.Fano() - # if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: - # return matroids.named_matroids.Fano().dual() - # if typ == CMR_MATROID_DEC_TYPE_K5: - # return matroids.CompleteGraphic(5) - # if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: - # return matroids.CompleteGraphic(5).dual() - # if typ == CMR_MATROID_DEC_TYPE_K33: - # E = 'abcdefghi' - # G = graphs.CompleteBipartiteGraph(3, 3) - # return Matroid(groundset=E, graph=G, regular=True) - # if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: - # return matroids.named_matroids.K33dual() - # assert False, 'special leaf node with unknown type' def _repr_(self): return f'Isomorphic to a minor of {self._matroid()}' From 9659b185ece501053e5555da7b90e8ae28d34dca Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 8 Mar 2024 10:21:28 -0800 Subject: [PATCH 128/262] WIP three_sum --- src/sage/matrix/matrix_cmr_sparse.pyx | 75 ++++++++++++++++++----- src/sage/matrix/seymour_decomposition.pyx | 69 ++++++++++++++------- 2 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e4cb9e2ce75..6280e7a35d5 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -586,8 +586,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): """ cdef Matrix_cmr_chr_sparse sum, first, second cdef CMR_CHRMAT *sum_mat - first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) - second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) + first = Matrix_cmr_chr_sparse._from_data(first_mat) + second = Matrix_cmr_chr_sparse._from_data(second_mat) if nonzero_block not in ["top_right", "bottom_left"]: raise ValueError("Unknown two sum mode", nonzero_block) @@ -701,6 +701,48 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat) return sum + def three_sum_wide_wide(first_mat, second_mat): + r""" + Return the 3-sum matrix constructed from the given matrices ``first_mat`` and + ``second_mat``. + + The first matrix is `M_1=\begin{bmatrix} A & a & a \\ c^T & 0 & \pm 1\end{bmatrix}` + and the second matrix is `M_2=\begin{bmatrix} \pm 1 & 0 & b^T \\ d & d & B\end{bmatrix}`. Then + the three sum is defined in [Sch1986]_, Ch. 19.4.:= + `M_1 \oplus_3 M_2 =\begin{bmatrix}A & ab^T\\ dc^T & B\end{bmatrix}`. + """ + pass + # m1 = first_mat.nrows() + # n1 = first_mat.ncols() + # m2 = second_mat.nrows() + # n2 = second_mat.ncols() + # first_subcol = first_mat.matrix_from_rows_and_columns(range(m1 - 1), [n1 - 1]) + # second_subcol = first_mat.delete_rows([second_row_index]).columns()[second_col_index1] + # first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) + # second_submat = second_mat.delete_columns([second_col_index1, second_col_index2]) + # first_row = first_submat.rows()[first_row_index] + # second_row = second_submat.rows()[second_row_index] + # first_submat = first_submat.delete_rows([first_row_index]) + # second_submat = second_submat.delete_rows([second_row_index]) + # first_subrows = first_submat.rows() + # second_subrows = second_submat.rows() + # upper_right_rows = first_subcol.tensor_product(second_row).rows() + # lower_left_rows = second_subcol.tensor_product(first_row).rows() + # n1 = len(first_submat.rows()) + # n2 = len(second_submat.rows()) + # row_list = [] + # for i in range(n1): + # r = list(first_subrows[i]) + # u = list(upper_right_rows[i]) + # r.extend(u) + # row_list.append(r) + # for i in range(n2): + # r = list(lower_left_rows[i]) + # u = list(second_subrows[i]) + # r.extend(u) + # row_list.append(r) + # return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and @@ -754,6 +796,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 0 0 0 1 1] [1 1 0 0 0 1] """ + print(first_mat) + print(second_mat) fc = len(first_mat.columns()) sc = len(second_mat.columns()) fr = len(first_mat.rows()) @@ -794,8 +838,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): break if not (valid1 and valid2): raise ValueError('indicated columns of Matrices are not of appropriate form for 3-sum') + print(first_row_index) + print(second_row_index) + print(first_mat) + test1 = first_mat.delete_rows([first_row_index]) + print(test1) + print(test1.columns()) first_subcol = first_mat.delete_rows([first_row_index]).columns()[first_col_index1] - second_subcol = first_mat.delete_rows([second_row_index]).columns()[second_col_index1] + second_subcol = second_mat.delete_rows([second_row_index]).columns()[second_col_index1] first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) second_submat = second_mat.delete_columns([second_col_index1, second_col_index2]) first_row = first_submat.rows()[first_row_index] @@ -804,8 +854,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): second_submat = second_submat.delete_rows([second_row_index]) first_subrows = first_submat.rows() second_subrows = second_submat.rows() + print(first_subcol) + print(second_subcol) + print(second_row) + print(first_row) upper_right_rows = first_subcol.tensor_product(second_row).rows() lower_left_rows = second_subcol.tensor_product(first_row).rows() + print(upper_right_rows) + print(lower_left_rows) n1 = len(first_submat.rows()) n2 = len(second_submat.rows()) row_list = [] @@ -823,22 +879,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def delete_rows(self, indices): rows = self.rows() - row_list = [] n = len(rows) - for i in indices: - if i >= n: - raise ValueError('Found index greater than matrix size') - rows.pop(i) - for r in rows: - x = [] - for i in range(len(r)): - x.append(r[i]) - row_list.append(x) + row_list = [rows[i] for i in range(n) if i not in indices] return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def delete_columns(self, indices): rows = self.rows() - n = len(rows) + n = self.ncols() row_list = [] for i in indices: if i >= n: diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 1ef9a4ca742..2d7d7e0f7d2 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -544,26 +544,26 @@ cdef class ThreeSumNode(SumNode): def is_distributed_ranks(self): r""" - EXAMPLES:: - - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) - sage: result, certificate = R12.is_totally_unimodular(certificate=True) - sage: C = certificate._children()[0]; C - ThreeSumNode (9×12) with 2 children - sage: C.is_distributed_ranks() - True - sage: C.is_concentrated_rank() - False + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12_large.is_totally_unimodular(certificate=True) + sage: C = certificate._children()[0]; C + ThreeSumNode (9×12) with 2 children + sage: C.is_distributed_ranks() + True + sage: C.is_concentrated_rank() + False """ return CMRmatroiddecThreeSumDistributedRanks(self._dec) @@ -571,9 +571,34 @@ cdef class ThreeSumNode(SumNode): return CMRmatroiddecThreeSumConcentratedRank(self._dec) def block_matrix_form(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: R12 + [ 1 0 1 1 0 0] + [ 0 1 1 1 0 0] + [ 1 0 1 0 1 1] + [ 0 -1 0 -1 1 1] + [ 1 0 1 0 1 0] + [ 0 -1 0 -1 0 1] + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: C = certificate._children()[0]; C + ThreeSumNode (6×6) with 2 children + sage: C.block_matrix_form() + [ 0 0 1 -1 1 0] + [ 1 1 1 0 0 0] + [ 0 1 0 1 -1 0] + [ 0 0 0 1 0 1] + [ 1 0 1 0 1 1] + [ 1 0 1 0 0 1] + """ M1, M2 = self.summand_matrices() - x, y= len(M1.columns()), len(M2.columns()) - return Matrix_cmr_chr_sparse.two_sum(M1, M2, x - 1, x-2, y - 1, y - 2) + x = M1.ncols() + return Matrix_cmr_chr_sparse.three_sum(M1, M2, x - 2, x - 1, 0, 1) cdef class BaseGraphicNode(DecompositionNode): From c876dd7a89fcfce05112ac03ff81ce90d6c9a009 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Mar 2024 12:04:49 -0800 Subject: [PATCH 129/262] WIP row/col mappings --- src/sage/matrix/seymour_decomposition.pxd | 2 + src/sage/matrix/seymour_decomposition.pyx | 63 ++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index e113270b04f..ccfdba4ac35 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -6,6 +6,8 @@ from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC *_dec + cdef object _row_keys + cdef object _column_keys cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef _set_dec(self, CMR_MATROID_DEC *dec, root) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 2d7d7e0f7d2..73017a28a12 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -59,6 +59,11 @@ cdef class DecompositionNode(SageObject): @cached_method def matrix(self): r""" + Return a :class:`Matrix`. + + Use :meth:`ancestor_rows_and_columns` for the embedding of it + into the matrix of ... + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -85,6 +90,26 @@ cdef class DecompositionNode(SageObject): result._root = self._root or self return result + def row_keys(self): + r""" + OUTPUT: a tuple or ``None`` + """ + return self._row_keys + + def column_keys(self): + r""" + OUTPUT: a tuple or ``None`` + """ + return self._column_keys + + @cached_method + def morphism(self): + r""" + + """ + return matrix(self.matrix(), row_keys=self.row_keys(), column_keys=self.column_keys()) + + @cached_method def _parent_rows_and_columns(self): cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) @@ -103,6 +128,22 @@ cdef class DecompositionNode(SageObject): return parent_rows_cmr_tuple, parent_columns_cmr_tuple + def ancestor_rows_and_columns(self, ancestor, use_keys=False): + r""" + + INPUT: + + - ``use_keys`` -- if ``True``, return the answer + + OUTPUT: tuple ``(row_keys, column_keys)`` + + + + """ + if ancestor is self: + + + @cached_method def parent_rows_and_columns(self, indices_label=False): r""" @@ -244,6 +285,22 @@ cdef class DecompositionNode(SageObject): """ return CMRmatroiddecNumChildren(self._dec) + def _create_child_node(self, index): + + row_keys = self.row_keys() + column_keys = self.column_keys() + if row_keys is not None and column_keys is not None: + cdef CMR_MATROID_DEC *child = CMRmatroiddecChild(self._dec, index) + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child) + child_row_keys = tuple(row_keys[parent_rows[.....]]) + + return create_DecompositionNode(, + self._root or self, + +) + + @cached_method def _children(self): r""" @@ -283,7 +340,7 @@ cdef class DecompositionNode(SageObject): sage: certificate._children() () """ - return tuple(create_DecompositionNode(CMRmatroiddecChild(self._dec, index), self._root or self) + return tuple(self._create_child_node(index) for index in range(self.nchildren())) def _repr_(self): @@ -817,7 +874,7 @@ cdef _class(CMR_MATROID_DEC *dec): assert NotImplementedError -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, column_keys=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. @@ -832,6 +889,8 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None): return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) + result._row_keys = row_keys + result._column_keys = column_keys return result From c4b827398351cd5859fbc0b228e07a6b5f0b7e5b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 8 Mar 2024 14:39:01 -0800 Subject: [PATCH 130/262] WIP --- src/sage/matrix/matrix_cmr_sparse.pyx | 14 ----- src/sage/matrix/seymour_decomposition.pyx | 73 ++++++++++++----------- 2 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 6280e7a35d5..a28c4480be3 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -796,8 +796,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 0 0 0 1 1] [1 1 0 0 0 1] """ - print(first_mat) - print(second_mat) fc = len(first_mat.columns()) sc = len(second_mat.columns()) fr = len(first_mat.rows()) @@ -838,12 +836,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): break if not (valid1 and valid2): raise ValueError('indicated columns of Matrices are not of appropriate form for 3-sum') - print(first_row_index) - print(second_row_index) - print(first_mat) - test1 = first_mat.delete_rows([first_row_index]) - print(test1) - print(test1.columns()) first_subcol = first_mat.delete_rows([first_row_index]).columns()[first_col_index1] second_subcol = second_mat.delete_rows([second_row_index]).columns()[second_col_index1] first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) @@ -854,14 +846,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): second_submat = second_submat.delete_rows([second_row_index]) first_subrows = first_submat.rows() second_subrows = second_submat.rows() - print(first_subcol) - print(second_subcol) - print(second_row) - print(first_row) upper_right_rows = first_subcol.tensor_product(second_row).rows() lower_left_rows = second_subcol.tensor_product(first_row).rows() - print(upper_right_rows) - print(lower_left_rows) n1 = len(first_submat.rows()) n2 = len(second_submat.rows()) row_list = [] diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 73017a28a12..38e65f49e74 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -90,24 +90,24 @@ cdef class DecompositionNode(SageObject): result._root = self._root or self return result - def row_keys(self): - r""" - OUTPUT: a tuple or ``None`` - """ - return self._row_keys + # def row_keys(self): + # r""" + # OUTPUT: a tuple or ``None`` + # """ + # return self._row_keys - def column_keys(self): - r""" - OUTPUT: a tuple or ``None`` - """ - return self._column_keys + # def column_keys(self): + # r""" + # OUTPUT: a tuple or ``None`` + # """ + # return self._column_keys - @cached_method - def morphism(self): - r""" + # @cached_method + # def morphism(self): + # r""" - """ - return matrix(self.matrix(), row_keys=self.row_keys(), column_keys=self.column_keys()) + # """ + # return matrix(self.matrix(), row_keys=self.row_keys(), column_keys=self.column_keys()) @cached_method @@ -128,21 +128,20 @@ cdef class DecompositionNode(SageObject): return parent_rows_cmr_tuple, parent_columns_cmr_tuple - def ancestor_rows_and_columns(self, ancestor, use_keys=False): - r""" - - INPUT: + # def ancestor_rows_and_columns(self, ancestor, use_keys=False): + # r""" - - ``use_keys`` -- if ``True``, return the answer + # INPUT: - OUTPUT: tuple ``(row_keys, column_keys)`` + # - ``use_keys`` -- if ``True``, return the answer + # OUTPUT: tuple ``(row_keys, column_keys)`` - """ - if ancestor is self: - + # """ + # if ancestor is self: + # pass @cached_method def parent_rows_and_columns(self, indices_label=False): @@ -287,18 +286,20 @@ cdef class DecompositionNode(SageObject): def _create_child_node(self, index): - row_keys = self.row_keys() - column_keys = self.column_keys() - if row_keys is not None and column_keys is not None: - cdef CMR_MATROID_DEC *child = CMRmatroiddecChild(self._dec, index) - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child) - child_row_keys = tuple(row_keys[parent_rows[.....]]) + return create_DecompositionNode(CMRmatroiddecChild(self._dec, index), + self._root or self) +# row_keys = self.row_keys() +# column_keys = self.column_keys() +# if row_keys is not None and column_keys is not None: +# cdef CMR_MATROID_DEC *child = CMRmatroiddecChild(self._dec, index) +# cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child) +# cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child) +# child_row_keys = tuple(row_keys[parent_rows[.....]]) - return create_DecompositionNode(, - self._root or self, +# return create_DecompositionNode(, +# self._root or self, -) +# ) @cached_method @@ -889,8 +890,8 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) - result._row_keys = row_keys - result._column_keys = column_keys + # result._row_keys = row_keys + # result._column_keys = column_keys return result From 9fc5d09791b4f5756491836107549dbd72a36758 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 8 Mar 2024 14:43:32 -0800 Subject: [PATCH 131/262] add more test examples --- src/sage/matrix/matrix_cmr_sparse.pyx | 3 ++- src/sage/matrix/seymour_decomposition.pyx | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index a28c4480be3..d89a02ef922 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -717,7 +717,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): # m2 = second_mat.nrows() # n2 = second_mat.ncols() # first_subcol = first_mat.matrix_from_rows_and_columns(range(m1 - 1), [n1 - 1]) - # second_subcol = first_mat.delete_rows([second_row_index]).columns()[second_col_index1] + # second_subcol = second_mat.matrix_from_rows_and_columns(range(1, m2), [0]) + # first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) # second_submat = second_mat.delete_columns([second_col_index1, second_col_index2]) # first_row = first_submat.rows()[first_row_index] diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 38e65f49e74..0c2bed53145 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -646,6 +646,20 @@ cdef class ThreeSumNode(SumNode): sage: result, certificate = R12.is_totally_unimodular(certificate=True) sage: C = certificate._children()[0]; C ThreeSumNode (6×6) with 2 children + sage: C.matrix() + [ 1 0 0 1 -1 0] + [ 0 1 1 1 0 0] + [ 1 0 0 0 0 1] + [ 0 -1 0 -1 1 1] + [-1 0 1 0 1 0] + [ 0 -1 0 -1 0 1] + sage: C.summand_matrices() + ( + [ 0 0 1 -1 -1] [ 1 0 1 -1 0] + [ 1 1 1 0 0] [ 0 0 1 0 1] + [ 0 1 0 1 1] [-1 -1 0 1 1] + [-1 0 -1 0 1], [-1 -1 0 0 1] + ) sage: C.block_matrix_form() [ 0 0 1 -1 1 0] [ 1 1 1 0 0 0] From 32a38a1801aa11160c2f729cba4fe44f602cc7f8 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Mar 2024 10:15:51 -0700 Subject: [PATCH 132/262] add sig_on sig_off to one_sum and two_sum --- src/sage/matrix/matrix_cmr_sparse.pyx | 29 ++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index d89a02ef922..326025d2110 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -466,11 +466,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum_mat = sum._mat row_subdivision = [] column_subdivision = [] - for s in summands: - row_subdivision.append(sum_mat.numRows) - column_subdivision.append(sum_mat.numColumns) - summand = Matrix_cmr_chr_sparse._from_data(s) - CMR_CALL(CMRoneSum(cmr, sum_mat, summand._mat, &sum_mat)) + + cdef CMR_CHRMAT *tmp_sum_mat = NULL + sig_on() + try: + for s in summands: + row_subdivision.append(sum_mat.numRows) + column_subdivision.append(sum_mat.numColumns) + summand = Matrix_cmr_chr_sparse._from_data(s) + CMR_CALL(CMRoneSum(cmr, sum_mat, summand._mat, &tmp_sum_mat)) + sum_mat = tmp_sum_mat + tmp_sum_mat = NULL + + finally: + sig_off() + if sum_mat != sum._mat: sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: @@ -585,7 +595,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 0| 0 1 0 0 1] """ cdef Matrix_cmr_chr_sparse sum, first, second - cdef CMR_CHRMAT *sum_mat + cdef CMR_CHRMAT *sum_mat = NULL first = Matrix_cmr_chr_sparse._from_data(first_mat) second = Matrix_cmr_chr_sparse._from_data(second_mat) @@ -624,7 +634,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if second_mat.parent().characteristic() != characteristic: raise ValueError("The characteristic of two matrices are different") - CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, first_marker, second_marker, characteristic, &sum_mat)) + sig_on() + try: + CMR_CALL(CMRtwoSum(cmr, first._mat, second._mat, first_marker, second_marker, characteristic, &sum_mat)) + finally: + sig_off() + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) if row_subdivision or column_subdivision: sum.subdivide(row_subdivision, column_subdivision) From 8dfd4fea19921b963fe083bd94c1676999b01e8e Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Mar 2024 10:31:13 -0700 Subject: [PATCH 133/262] add CMR_TU_PARAMS.directCamion --- src/sage/matrix/matrix_cmr_sparse.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 326025d2110..7b9a93e532e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1645,6 +1645,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): construct_graphs=construct_graphs) params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION + params.directCamion = False _set_cmr_regular_parameters(¶ms.regular, kwds) sig_on() try: From d2c5ab78c9c204f820e8c4b778f389f330f4769b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Mar 2024 10:45:54 -0700 Subject: [PATCH 134/262] three_sum_cmr add sig_on --- src/sage/matrix/matrix_cmr_sparse.pyx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 7b9a93e532e..637176654f2 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -665,7 +665,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-1 -2 -3] """ cdef Matrix_cmr_chr_sparse sum, first, second - cdef CMR_CHRMAT *sum_mat + cdef CMR_CHRMAT *sum_mat = NULL first = Matrix_cmr_chr_sparse._from_data(first_mat, immutable=False) second = Matrix_cmr_chr_sparse._from_data(second_mat, immutable=False) @@ -712,7 +712,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if second_mat.parent().characteristic() != characteristic: raise ValueError("The characteristic of two matrices are different") - CMR_CALL(CMRthreeSum(cmr, first._mat, second._mat, first_marker1, second_marker1, first_marker2, second_marker2, characteristic, &sum_mat)) + sig_on() + try: + CMR_CALL(CMRthreeSum(cmr, first._mat, second._mat, first_marker1, second_marker1, first_marker2, second_marker2, characteristic, &sum_mat)) + finally: + sig_off() + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat) return sum From 0c7bf24ca5cf701b0a13f4a0b5410b9e8fa250cc Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 11 Mar 2024 10:46:29 -0700 Subject: [PATCH 135/262] add three_sum_wide_wide --- src/sage/matrix/matrix_cmr_sparse.pyx | 62 +++++++++++------------ src/sage/matrix/seymour_decomposition.pyx | 3 +- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 637176654f2..218997143ef 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -731,38 +731,36 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): the three sum is defined in [Sch1986]_, Ch. 19.4.:= `M_1 \oplus_3 M_2 =\begin{bmatrix}A & ab^T\\ dc^T & B\end{bmatrix}`. """ - pass - # m1 = first_mat.nrows() - # n1 = first_mat.ncols() - # m2 = second_mat.nrows() - # n2 = second_mat.ncols() - # first_subcol = first_mat.matrix_from_rows_and_columns(range(m1 - 1), [n1 - 1]) - # second_subcol = second_mat.matrix_from_rows_and_columns(range(1, m2), [0]) - - # first_submat = first_mat.delete_columns([first_col_index1, first_col_index2]) - # second_submat = second_mat.delete_columns([second_col_index1, second_col_index2]) - # first_row = first_submat.rows()[first_row_index] - # second_row = second_submat.rows()[second_row_index] - # first_submat = first_submat.delete_rows([first_row_index]) - # second_submat = second_submat.delete_rows([second_row_index]) - # first_subrows = first_submat.rows() - # second_subrows = second_submat.rows() - # upper_right_rows = first_subcol.tensor_product(second_row).rows() - # lower_left_rows = second_subcol.tensor_product(first_row).rows() - # n1 = len(first_submat.rows()) - # n2 = len(second_submat.rows()) - # row_list = [] - # for i in range(n1): - # r = list(first_subrows[i]) - # u = list(upper_right_rows[i]) - # r.extend(u) - # row_list.append(r) - # for i in range(n2): - # r = list(lower_left_rows[i]) - # u = list(second_subrows[i]) - # r.extend(u) - # row_list.append(r) - # return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + m1 = first_mat.nrows() + n1 = first_mat.ncols() + m2 = second_mat.nrows() + n2 = second_mat.ncols() + first_subcol = first_mat.matrix_from_rows_and_columns(range(m1 - 1), [n1 - 1]) + second_subcol = second_mat.matrix_from_rows_and_columns(range(1, m2), [0]) + + first_row = first_mat.matrix_from_rows_and_columns([m1 - 1], range(n1 - 2)) + second_row = second_mat.matrix_from_rows_and_columns([0], range(2, n2)) + + first_submat = first_mat.matrix_from_rows_and_columns(range(m1 - 1), range(n1 - 2)) + second_submat = second_mat.matrix_from_rows_and_columns(range(1, m2), range(2, n2)) + + first_subrows = first_submat.rows() + second_subrows = second_submat.rows() + upper_right_rows = first_subcol.tensor_product(second_row).rows() + lower_left_rows = second_subcol.tensor_product(first_row).rows() + + row_list = [] + for i in range(m1 - 1): + r = list(first_subrows[i]) + u = list(upper_right_rows[i]) + r.extend(u) + row_list.append(r) + for i in range(m2 - 1): + r = list(lower_left_rows[i]) + u = list(second_subrows[i]) + r.extend(u) + row_list.append(r) + return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 0c2bed53145..1dd82332461 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -670,7 +670,8 @@ cdef class ThreeSumNode(SumNode): """ M1, M2 = self.summand_matrices() x = M1.ncols() - return Matrix_cmr_chr_sparse.three_sum(M1, M2, x - 2, x - 1, 0, 1) + # return Matrix_cmr_chr_sparse.three_sum(M1, M2, x - 2, x - 1, 0, 1) + return Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2) cdef class BaseGraphicNode(DecompositionNode): From 041df74c036721f15669cdded842f16c3a8c4361 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 12 Mar 2024 09:55:02 -0700 Subject: [PATCH 136/262] WIP row_keys and column_keys --- src/sage/matrix/seymour_decomposition.pxd | 5 +- src/sage/matrix/seymour_decomposition.pyx | 104 ++++++++++++++++------ 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index ccfdba4ac35..4088e1cbcf6 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_MATROID_DEC +from sage.libs.cmr.cmr cimport CMR_MATROID_DEC, CMR_ELEMENT from sage.structure.sage_object cimport SageObject @@ -11,6 +11,9 @@ cdef class DecompositionNode(SageObject): cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef _set_dec(self, CMR_MATROID_DEC *dec, root) + cdef _set_row_keys(self, row_keys): + + # cdef _CMRelement_to_key(self, CMR_ELEMENT element) cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 1dd82332461..9e5cf74a0ee 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -23,6 +23,7 @@ from sage.structure.sage_object cimport SageObject from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edge, _sage_graph from .matrix_space import MatrixSpace +from .args cimport MatrixArgs cdef class DecompositionNode(SageObject): @@ -40,6 +41,34 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRmatroiddecFree(cmr, &self._dec)) self._dec = dec self._root = root + self._row_keys = None + self._column_keys = None + + cdef _set_row_keys(self, row_keys): + # """ + # Set the row keys with consistency checking: if the + # value was previously set, it must remain the same. + # """ + # if self._row_keys is not None and self._row_keys != row_keys: + # raise ValueError(f"inconsistent row keys: should be {self._row_keys} " + # f"but got {row_keys}") + # if row_keys is not None and self.nrows() != len(row_keys): + # raise ValueError(f"inconsistent row keys: should be of cardinality {self.nrows()} " + # f"but got {row_keys}") + self._row_keys = row_keys + + # def _set_column_keys(self, column_keys): + # """ + # Set the column keys with consistency checking: if the + # value was previously set, it must remain the same. + # """ + # if self._column_keys is not None and self._column_keys != column_keys: + # raise ValueError(f"inconsistent column keys: should be {self._column_keys} " + # f"but got {column_keys}") + # if column_keys is not None and self.ncols() != len(column_keys): + # raise ValueError(f"inconsistent column keys: should be of cardinality {self.ncols()} " + # f"but got {column_keys}") + # self._column_keys = column_keys def __dealloc__(self): self._set_dec(NULL, None) @@ -90,24 +119,24 @@ cdef class DecompositionNode(SageObject): result._root = self._root or self return result - # def row_keys(self): - # r""" - # OUTPUT: a tuple or ``None`` - # """ - # return self._row_keys + def row_keys(self): + r""" + OUTPUT: a tuple or ``None`` + """ + return self._row_keys - # def column_keys(self): - # r""" - # OUTPUT: a tuple or ``None`` - # """ - # return self._column_keys + def column_keys(self): + r""" + OUTPUT: a tuple or ``None`` + """ + return self._column_keys - # @cached_method - # def morphism(self): - # r""" + @cached_method + def morphism(self): + r""" - # """ - # return matrix(self.matrix(), row_keys=self.row_keys(), column_keys=self.column_keys()) + """ + return MatrixArgs(self.matrix(), MatrixSpace(ZZ, self.row_keys(), self.column_keys())) @cached_method @@ -284,22 +313,33 @@ cdef class DecompositionNode(SageObject): """ return CMRmatroiddecNumChildren(self._dec) + # cdef _CMRelement_to_key(self, CMR_ELEMENT element): + # if not CMRelementIsValid(element): + # raise ValueError('CMRelement index not valid') + # if CMRelementIsRow(element): + # return self.row_keys[CMRelementToRowIndex(element)] + # else: + # return self.column_keys[CMRelementToColumnIndex(element)] + def _create_child_node(self, index): + return create_DecompositionNode(CMRmatroiddecChild(self._dec, index), root = self._root or self) + # row_keys = self.row_keys() + # column_keys = self.column_keys() + # cdef CMR_MATROID_DEC *child_dec = CMRmatroiddecChild(self._dec, index) + # cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child_dec) + # cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child_dec) - return create_DecompositionNode(CMRmatroiddecChild(self._dec, index), - self._root or self) -# row_keys = self.row_keys() -# column_keys = self.column_keys() -# if row_keys is not None and column_keys is not None: -# cdef CMR_MATROID_DEC *child = CMRmatroiddecChild(self._dec, index) -# cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child) -# cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child) -# child_row_keys = tuple(row_keys[parent_rows[.....]]) + # child = create_DecompositionNode(child_dec, root = self._root or self) -# return create_DecompositionNode(, -# self._root or self, + # if row_keys is None or column_keys is None: + # child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) + # for i in range(child.nrows())) + # child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) + # for i in range(child.ncols())) + # child._set_row_keys(child_row_keys) + # child._set_column_keys(child_column_keys) -# ) + # return child @cached_method @@ -600,6 +640,11 @@ cdef class TwoSumNode(SumNode): cdef class ThreeSumNode(SumNode): + @cached_method + def _children(self): + return tuple(self._create_child_node(index) + for index in range(self.nchildren())) + def is_distributed_ranks(self): r""" EXAMPLES:: @@ -825,6 +870,7 @@ cdef class SpecialLeafNode(DecompositionNode): cdef class PivotsNode(DecompositionNode): + def npivots(self): return CMRmatroiddecNumPivots(self._dec) @@ -905,8 +951,8 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) - # result._row_keys = row_keys - # result._column_keys = column_keys + result._set_row_keys(row_keys) + # result._set_column_keys(column_keys) return result From de5a1703ab4dc35cef9ba047459feee3b691d0b6 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 12 Mar 2024 10:15:59 -0700 Subject: [PATCH 137/262] WIP --- src/sage/matrix/seymour_decomposition.pxd | 2 +- src/sage/matrix/seymour_decomposition.pyx | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 4088e1cbcf6..bb1eedc37f0 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -11,7 +11,7 @@ cdef class DecompositionNode(SageObject): cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef _set_dec(self, CMR_MATROID_DEC *dec, root) - cdef _set_row_keys(self, row_keys): + cdef _set_row_keys(self, row_keys) # cdef _CMRelement_to_key(self, CMR_ELEMENT element) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 9e5cf74a0ee..6c42852900b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -41,10 +41,10 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRmatroiddecFree(cmr, &self._dec)) self._dec = dec self._root = root - self._row_keys = None - self._column_keys = None + # self._row_keys = None + # self._column_keys = None - cdef _set_row_keys(self, row_keys): + # cdef _set_row_keys(self, row_keys): # """ # Set the row keys with consistency checking: if the # value was previously set, it must remain the same. @@ -55,7 +55,7 @@ cdef class DecompositionNode(SageObject): # if row_keys is not None and self.nrows() != len(row_keys): # raise ValueError(f"inconsistent row keys: should be of cardinality {self.nrows()} " # f"but got {row_keys}") - self._row_keys = row_keys + # self._row_keys = row_keys # def _set_column_keys(self, column_keys): # """ @@ -951,7 +951,8 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) - result._set_row_keys(row_keys) + # result._set_row_keys(row_keys) + # result.row_keys = row_keys # result._set_column_keys(column_keys) return result From b902c383415d18468b4b75274284f97b2485cc00 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Mar 2024 10:36:01 -0700 Subject: [PATCH 138/262] Fixups --- src/sage/matrix/matrix_cmr_sparse.pyx | 41 ++++++++------- src/sage/matrix/seymour_decomposition.pxd | 3 +- src/sage/matrix/seymour_decomposition.pyx | 61 +++++++++++------------ 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 218997143ef..f2a269825d3 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -17,6 +17,7 @@ Sparse Matrices with CMR from libc.stdint cimport SIZE_MAX +from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off from sage.libs.cmr.cmr cimport * @@ -914,50 +915,52 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result def binary_pivots(self, rows, columns): - cdef Matrix_cmr_chr_sparse result - cdef size_t* pivot_rows - cdef size_t* pivot_columns - cdef CMR_CHRMAT *result_mat - npivots = len(rows) if len(columns) != npivots: raise ValueError("The pivot rows and columns must have the same length") + cdef size_t* pivot_rows = sig_malloc(sizeof(size_t)*npivots) + cdef size_t* pivot_columns = sig_malloc(sizeof(size_t)*npivots) + cdef CMR_CHRMAT *result_mat + for i in range(npivots): pivot_rows[i] = rows[i] pivot_columns[i] = columns[i] - CMR_CALL(CMRchrmatBinaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) - result = Matrix_cmr_chr_sparse._from_cmr(result_mat) - return result + try: + CMR_CALL(CMRchrmatBinaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) + return Matrix_cmr_chr_sparse._from_cmr(result_mat) + finally: + sig_free(pivot_rows) + sig_free(pivot_columns) def ternary_pivot(self, row, column): - cdef Matrix_cmr_chr_sparse result cdef size_t pivot_row = row cdef size_t pivot_column = column cdef CMR_CHRMAT *result_mat CMR_CALL(CMRchrmatTernaryPivot(cmr, self._mat, pivot_row, pivot_column, &result_mat)) - result = Matrix_cmr_chr_sparse._from_cmr(result_mat) - return result + return Matrix_cmr_chr_sparse._from_cmr(result_mat) def ternary_pivots(self, rows, columns): - cdef Matrix_cmr_chr_sparse result - cdef size_t* pivot_rows - cdef size_t* pivot_columns - cdef CMR_CHRMAT *result_mat - cdef size_t npivots = len(rows) if len(columns) != npivots: raise ValueError("The pivot rows and columns must have the same length") + cdef size_t* pivot_rows = sig_malloc(sizeof(size_t)*npivots) + cdef size_t* pivot_columns = sig_malloc(sizeof(size_t)*npivots) + cdef CMR_CHRMAT *result_mat + for i in range(npivots): pivot_rows[i] = rows[i] pivot_columns[i] = columns[i] - CMR_CALL(CMRchrmatTernaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) - result = Matrix_cmr_chr_sparse._from_cmr(result_mat) - return result + try: + CMR_CALL(CMRchrmatTernaryPivots(cmr, self._mat, npivots, pivot_rows, pivot_columns, &result_mat)) + return Matrix_cmr_chr_sparse._from_cmr(result_mat) + finally: + sig_free(pivot_rows) + sig_free(pivot_columns) def is_unimodular(self, time_limit=60.0): r""" diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index bb1eedc37f0..3d73475a920 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -12,8 +12,9 @@ cdef class DecompositionNode(SageObject): cdef _set_dec(self, CMR_MATROID_DEC *dec, root) cdef _set_row_keys(self, row_keys) + cdef _set_column_keys(self, column_keys) # cdef _CMRelement_to_key(self, CMR_ELEMENT element) -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?) +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?, row_keys=?, column_keys=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 6c42852900b..6f1f7902398 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -41,34 +41,32 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRmatroiddecFree(cmr, &self._dec)) self._dec = dec self._root = root - # self._row_keys = None - # self._column_keys = None - - # cdef _set_row_keys(self, row_keys): - # """ - # Set the row keys with consistency checking: if the - # value was previously set, it must remain the same. - # """ - # if self._row_keys is not None and self._row_keys != row_keys: - # raise ValueError(f"inconsistent row keys: should be {self._row_keys} " - # f"but got {row_keys}") - # if row_keys is not None and self.nrows() != len(row_keys): - # raise ValueError(f"inconsistent row keys: should be of cardinality {self.nrows()} " - # f"but got {row_keys}") - # self._row_keys = row_keys - - # def _set_column_keys(self, column_keys): - # """ - # Set the column keys with consistency checking: if the - # value was previously set, it must remain the same. - # """ - # if self._column_keys is not None and self._column_keys != column_keys: - # raise ValueError(f"inconsistent column keys: should be {self._column_keys} " - # f"but got {column_keys}") - # if column_keys is not None and self.ncols() != len(column_keys): - # raise ValueError(f"inconsistent column keys: should be of cardinality {self.ncols()} " - # f"but got {column_keys}") - # self._column_keys = column_keys + + cdef _set_row_keys(self, row_keys): + """ + Set the row keys with consistency checking: if the + value was previously set, it must remain the same. + """ + if self._row_keys is not None and self._row_keys != row_keys: + raise ValueError(f"inconsistent row keys: should be {self._row_keys} " + f"but got {row_keys}") + if row_keys is not None and self.nrows() != len(row_keys): + raise ValueError(f"inconsistent row keys: should be of cardinality {self.nrows()} " + f"but got {row_keys}") + self._row_keys = row_keys + + cdef _set_column_keys(self, column_keys): + """ + Set the column keys with consistency checking: if the + value was previously set, it must remain the same. + """ + if self._column_keys is not None and self._column_keys != column_keys: + raise ValueError(f"inconsistent column keys: should be {self._column_keys} " + f"but got {column_keys}") + if column_keys is not None and self.ncols() != len(column_keys): + raise ValueError(f"inconsistent column keys: should be of cardinality {self.ncols()} " + f"but got {column_keys}") + self._column_keys = column_keys def __dealloc__(self): self._set_dec(NULL, None) @@ -951,9 +949,8 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) - # result._set_row_keys(row_keys) - # result.row_keys = row_keys - # result._set_column_keys(column_keys) + result._set_row_keys(row_keys) + result._set_column_keys(column_keys) return result @@ -971,4 +968,4 @@ cdef CMRelement_to_label(CMR_ELEMENT element, indices_label=False): if indices_label: return ('c', CMRelementToColumnIndex(element)) else: - return CMRelementToColumnIndex(element) \ No newline at end of file + return CMRelementToColumnIndex(element) From 1edd9e73f6dc5cc7a124117ccfb4ee81eb2ae2d6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:24:33 -0700 Subject: [PATCH 139/262] WIP --- src/sage/matrix/matrix_cmr_sparse.pyx | 20 ++++++--- src/sage/matrix/seymour_decomposition.pxd | 2 +- src/sage/matrix/seymour_decomposition.pyx | 54 +++++++++++------------ 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index f2a269825d3..d86a1bd17ff 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1437,7 +1437,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): complete_tree='if_regular', three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False): + construct_graphs=False, + row_keys=None, + column_keys=None): r""" Return whether the linear matroid of ``self`` over `\GF{2}` is regular. @@ -1565,9 +1567,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result if result: - return True, create_DecompositionNode(dec) + return True, create_DecompositionNode(dec, None, row_keys, column_keys) - return False, (create_DecompositionNode(dec), + return False, (create_DecompositionNode(dec, None, row_keys, column_keys), NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, @@ -1577,7 +1579,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): complete_tree='if_regular', three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False): + construct_graphs=False, + row_keys=None, + column_keys=None): r""" Return whether ``self`` is a totally unimodular matrix. @@ -1664,7 +1668,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result if result: - return True, create_DecompositionNode(dec) + return True, create_DecompositionNode(dec, None, row_keys, column_keys) if submat == NULL: submat_tuple = None @@ -1672,7 +1676,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), tuple(submat.columns[i] for i in range(submat.numColumns))) - return False, (create_DecompositionNode(dec), + return False, (create_DecompositionNode(dec, None, row_keys, column_keys), submat_tuple) def is_complement_totally_unimodular(self, *, time_limit=60.0, certificate=False, @@ -1682,7 +1686,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): complete_tree='if_regular', construct_matrices=False, construct_transposes=False, - construct_graphs=False): + construct_graphs=False, + row_keys=None, + column_keys=None): raise NotImplementedError diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 3d73475a920..df1de870bee 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -14,7 +14,7 @@ cdef class DecompositionNode(SageObject): cdef _set_row_keys(self, row_keys) cdef _set_column_keys(self, column_keys) - # cdef _CMRelement_to_key(self, CMR_ELEMENT element) + cdef _CMRelement_to_key(self, CMR_ELEMENT element) cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?, row_keys=?, column_keys=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 6f1f7902398..b743b269289 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -134,8 +134,7 @@ cdef class DecompositionNode(SageObject): r""" """ - return MatrixArgs(self.matrix(), MatrixSpace(ZZ, self.row_keys(), self.column_keys())) - + return MatrixArgs(self.matrix(), MatrixSpace(ZZ, self.row_keys(), self.column_keys())).element() @cached_method def _parent_rows_and_columns(self): @@ -311,34 +310,32 @@ cdef class DecompositionNode(SageObject): """ return CMRmatroiddecNumChildren(self._dec) - # cdef _CMRelement_to_key(self, CMR_ELEMENT element): - # if not CMRelementIsValid(element): - # raise ValueError('CMRelement index not valid') - # if CMRelementIsRow(element): - # return self.row_keys[CMRelementToRowIndex(element)] - # else: - # return self.column_keys[CMRelementToColumnIndex(element)] + cdef _CMRelement_to_key(self, CMR_ELEMENT element): + if not CMRelementIsValid(element): + raise ValueError('CMRelement index not valid') + if CMRelementIsRow(element): + return self.row_keys()[CMRelementToRowIndex(element)] + else: + return self.column_keys()[CMRelementToColumnIndex(element)] def _create_child_node(self, index): - return create_DecompositionNode(CMRmatroiddecChild(self._dec, index), root = self._root or self) - # row_keys = self.row_keys() - # column_keys = self.column_keys() - # cdef CMR_MATROID_DEC *child_dec = CMRmatroiddecChild(self._dec, index) - # cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child_dec) - # cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child_dec) - - # child = create_DecompositionNode(child_dec, root = self._root or self) + row_keys = self.row_keys() + column_keys = self.column_keys() + cdef CMR_MATROID_DEC *child_dec = CMRmatroiddecChild(self._dec, index) + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child_dec) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child_dec) - # if row_keys is None or column_keys is None: - # child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) - # for i in range(child.nrows())) - # child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) - # for i in range(child.ncols())) - # child._set_row_keys(child_row_keys) - # child._set_column_keys(child_column_keys) + child = create_DecompositionNode(child_dec, root=self._root or self) - # return child + if row_keys is not None and column_keys is not None: + child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) + for i in range(child.nrows())) + child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) + for i in range(child.ncols())) + child._set_row_keys(child_row_keys) + child._set_column_keys(child_column_keys) + return child @cached_method def _children(self): @@ -640,6 +637,7 @@ cdef class ThreeSumNode(SumNode): @cached_method def _children(self): + # to be overridden return tuple(self._create_child_node(index) for index in range(self.nchildren())) @@ -949,8 +947,10 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co return None cdef DecompositionNode result = _class(dec)() result._set_dec(dec, root) - result._set_row_keys(row_keys) - result._set_column_keys(column_keys) + if row_keys is not None: + result._set_row_keys(row_keys) + if column_keys is not None: + result._set_column_keys(column_keys) return result From 05788a2f357f61111655448a44733d3e5cffa17a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:25:52 -0700 Subject: [PATCH 140/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Add MorphismMethods is_unimodular, is_totally_unimodular --- .../finite_dimensional_modules_with_basis.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index ee5b6490346..5ba287373e8 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -888,6 +888,82 @@ def image(self): return C.submodule(self.image_basis(), already_echelonized=True, category=self.category_for()) + @cached_method + def _matrix_cmr(self): + from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + from sage.matrix.matrix_space import MatrixSpace + M = self.matrix() + MS = MatrixSpace(self.base_ring(), M.nrows(), M.ncols(), sparse=True) + return Matrix_cmr_chr_sparse(MS, M) + + @lazy_attribute + def is_unimodular(self): + r""" + Return whether ``self`` is a unimodular morphism. + + This does not depend on the choice of bases for + domain and codomain. + + EXAMPLES:: + + sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]], + ....: column_keys=['a', 'b', 'c'], + ....: row_keys=['v', 'w']); M + sage: M.is_unimodular() # optional - sage.libs.cmr + True + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_unimodular + except AttributeError: + return NotImplemented + def is_unimodular(**kwds): + return matrix.is_unimodular(**kwds) + return is_unimodular + + @lazy_attribute + def is_totally_unimodular(self): + r""" + Return whether the matrix of ``self`` is totally unimodular. + + This depends on the choice of bases for domain and codomain. + + EXAMPLES:: + + sage: # optional - sage.libs.cmr + sage: M = matrix(ZZ, [[1, 0], [-1, 1], [0, 1]], + ....: column_keys=['a', 'b'], + ....: row_keys=['u', 'v', 'w']); M + sage: M.is_totally_unimodular() + True + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.graph() + FIXME + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_unimodular + except AttributeError: + return NotImplemented + def is_totally_unimodular(*, certificate=False, **kwds): + if not certificate: + return matrix.is_totally_unimodular(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix.is_totally_unimodular(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + return is_totally_unimodular + class Homsets(HomsetsCategory): class Endset(CategoryWithAxiom): From 581332f06e0ae3795d2464d6e5e6d8d3658a93ea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Mar 2024 20:26:21 -0700 Subject: [PATCH 141/262] src/sage/features/sagemath.py: sage.libs.cmr is optional --- src/sage/features/sagemath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 46d43e5bffc..40bc49bc97e 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -380,7 +380,7 @@ def __init__(self): """ JoinFeature.__init__(self, 'sage.libs.cmr', [PythonModule('sage.matrix.matrix_cmr_sparse')], - spkg='sagemath_cmr') + spkg='sagemath_cmr', type='optional') class sage__libs__ecl(PythonModule): From 1a94771c946e733ada994bda598d2960e63113e8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:27:00 -0700 Subject: [PATCH 142/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Use functools.wraps for is_totally_unimodular --- .../categories/finite_dimensional_modules_with_basis.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 5ba287373e8..8872e43169e 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -10,6 +10,7 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** +import functools import operator from sage.categories.category_with_axiom import CategoryWithAxiom, CategoryWithAxiom_over_base_ring from sage.categories.fields import Fields @@ -920,9 +921,7 @@ def is_unimodular(self): method = matrix.is_unimodular except AttributeError: return NotImplemented - def is_unimodular(**kwds): - return matrix.is_unimodular(**kwds) - return is_unimodular + return matrix.is_unimodular @lazy_attribute def is_totally_unimodular(self): @@ -953,6 +952,8 @@ def is_totally_unimodular(self): method = matrix.is_unimodular except AttributeError: return NotImplemented + + @functools.wraps(matrix.is_totally_unimodular) def is_totally_unimodular(*, certificate=False, **kwds): if not certificate: return matrix.is_totally_unimodular(**kwds) @@ -962,6 +963,7 @@ def is_totally_unimodular(*, certificate=False, **kwds): column_keys=column_keys, row_keys=row_keys, **kwds) + return is_totally_unimodular class Homsets(HomsetsCategory): From 22f33952069ed429e05fff6a30a9659e8a06debb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Mar 2024 21:01:58 -0700 Subject: [PATCH 143/262] src/sage/categories/finite_dimensional_modules_with_basis.py (is_*unimodular): Update doctests --- .../finite_dimensional_modules_with_basis.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 8872e43169e..43500048dfe 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -910,7 +910,10 @@ def is_unimodular(self): sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]], ....: column_keys=['a', 'b', 'c'], ....: row_keys=['v', 'w']); M - sage: M.is_unimodular() # optional - sage.libs.cmr + Generic morphism: + From: Free module generated by {'a', 'b', 'c'} over Integer Ring + To: Free module generated by {'v', 'w'} over Integer Ring + sage: M.is_unimodular() # needs sage.libs.cmr True """ try: @@ -932,17 +935,20 @@ def is_totally_unimodular(self): EXAMPLES:: - sage: # optional - sage.libs.cmr + sage: # needs sage.libs.cmr sage: M = matrix(ZZ, [[1, 0], [-1, 1], [0, 1]], ....: column_keys=['a', 'b'], ....: row_keys=['u', 'v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b'} over Integer Ring + To: Free module generated by {'u', 'v', 'w'} over Integer Ring sage: M.is_totally_unimodular() True sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate (True, GraphicNode (3×2)) sage: certificate.graph() - FIXME + Graph on 4 vertices """ try: matrix = self._matrix_cmr() From 7d580fb54d451176a1658f8566417564584826d5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Mar 2024 22:03:01 -0700 Subject: [PATCH 144/262] src/sage/matrix/matrix_cmr_sparse.pyx: Add row_keys=None, column_keys=None to all remaining methods with certificate --- src/sage/matrix/matrix_cmr_sparse.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index d86a1bd17ff..cd39f35f19b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1252,7 +1252,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return True if result else False - def is_graphic(self, *, time_limit=60.0, certificate=False): + def is_graphic(self, *, time_limit=60.0, certificate=False, + row_keys=None, column_keys=None): r""" EXAMPLES:: @@ -1313,7 +1314,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD - def is_cographic(self, *, time_limit=60.0, certificate=False): + def is_cographic(self, *, time_limit=60.0, certificate=False, + row_keys=None, column_keys=None): r""" EXAMPLES:: @@ -1361,7 +1363,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD - def is_network_matrix(self, *, time_limit=60.0, certificate=False): + def is_network_matrix(self, *, time_limit=60.0, certificate=False, + row_keys=None, column_keys=None): r""" EXAMPLES: @@ -1427,7 +1430,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD - def is_dual_network_matrix(self, *, time_limit=60.0, certificate=False): + def is_dual_network_matrix(self, *, time_limit=60.0, certificate=False, + row_keys=None, column_keys=None): raise NotImplementedError def _is_binary_linear_matroid_regular(self, *, time_limit=60.0, certificate=False, From b4d91dc7a6eb5c02c66dfcabfa3deb5018f15040 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Mar 2024 22:09:41 -0700 Subject: [PATCH 145/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Add more methods --- .../finite_dimensional_modules_with_basis.py | 178 +++++++++++++++++- 1 file changed, 176 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 43500048dfe..ae2eac71e79 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -921,10 +921,184 @@ def is_unimodular(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_unimodular + return matrix.is_unimodular + except AttributeError: + return NotImplemented + + @lazy_attribute + def is_strongly_unimodular(self): + r""" + Return whether ``self`` is a strongly unimodular morphism. + + This does not depend on the choice of bases for + domain and codomain. + + EXAMPLES:: + + sage: M = matrix(ZZ, [[1, 0, 1], [0, 1, 1], [1, 2, 3]], + ....: column_keys=['a', 'b', 'c'], + ....: row_keys=['u', 'v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c'} over Integer Ring + To: Free module generated by {'u', 'v', 'w'} over Integer Ring + sage: M.is_unimodular() # needs sage.libs.cmr + True + sage: M.is_strongly_unimodular() # needs sage.libs.cmr + False + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + return matrix.is_strongly_unimodular + except AttributeError: + return NotImplemented + + @lazy_attribute + def equimodulus(self): + r""" + Return the integer `k` such that ``self`` is equimodular with determinant gcd `k`. + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + return matrix.equimodulus + except AttributeError: + return NotImplemented + + @lazy_attribute + def strong_equimodulus(self): + r""" + Return the integer `k` such that ``self`` is strongly equimodular with determinant gcd `k`. + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + return matrix.strong_equimodulus + except AttributeError: + return NotImplemented + + @lazy_attribute + def is_k_equimodular(self): + r""" + Return whether ``self`` is an equimodular morphism with determinant gcd `k`. + + This does not depend on the choice of bases for + domain and codomain. + + EXAMPLES:: + + sage: M = matrix(ZZ, [[1, 0, 1], [0, 1, 1], [1, 2, 3]], + ....: column_keys=['a', 'b', 'c'], + ....: row_keys=['u', 'v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c'} over Integer Ring + To: Free module generated by {'u', 'v', 'w'} over Integer Ring + sage: M.is_k_equimodular(1) # needs sage.libs.cmr + True + sage: M.is_k_equimodular(2) + False + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + return matrix.is_k_equimodular + except AttributeError: + return NotImplemented + + @lazy_attribute + def is_strongly_k_equimodular(self): + r""" + Return whether ``self`` is a strongly equimodular morphism with determinant gcd `k`. + + This does not depend on the choice of bases for + domain and codomain. + + EXAMPLES:: + + sage: M = matrix(ZZ, [[1, 0, 1], [0, 1, 1], [1, 2, 3]], + ....: column_keys=['a', 'b', 'c'], + ....: row_keys=['u', 'v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c'} over Integer Ring + To: Free module generated by {'u', 'v', 'w'} over Integer Ring + sage: M.is_strongly_k_equimodular(1) # needs sage.libs.cmr + False + sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]], + ....: column_keys=['a', 'b', 'c'], + ....: row_keys=['v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c'} over Integer Ring + To: Free module generated by {'v', 'w'} over Integer Ring + sage: M.is_strongly_k_equimodular(1) # needs sage.libs.cmr + True + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + return matrix.is_strongly_k_equimodular except AttributeError: return NotImplemented - return matrix.is_unimodular + + @lazy_attribute + def is_graphic(self): + r""" + Return whether the matrix of ``self`` is totally unimodular. + + This depends on the choice of bases for domain and codomain. + + EXAMPLES:: + + sage: # needs sage.libs.cmr + sage: M = matrix(ZZ, [[1, 0], [-1, 1], [0, -1]], + ....: column_keys=['a', 'b'], + ....: row_keys=['u', 'v', 'w']); M + Generic morphism: + From: Free module generated by {'a', 'b'} over Integer Ring + To: Free module generated by {'u', 'v', 'w'} over Integer Ring + sage: M.is_graphic() + True + sage: result, certificate = M.is_graphic(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: graph.vertices(sort=True) # TODO: We should see keys + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] + sage: forest_edges # indexed by rows of M + ((1, 2), (7, 1), (12, 7)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (1, 12)) + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_graphic + except AttributeError: + return NotImplemented + + @functools.wraps(matrix.is_graphic) + def is_graphic(*, certificate=False, **kwds): + if not certificate: + return matrix.is_graphic(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix.is_graphic(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + + return is_graphic @lazy_attribute def is_totally_unimodular(self): From b84aba48e99b042d1f41d01789ddcd092449928a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:27:44 -0700 Subject: [PATCH 146/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Add remaining methods --- .../finite_dimensional_modules_with_basis.py | 144 +++++++++++++++++- 1 file changed, 137 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index ae2eac71e79..d10de117516 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -1052,9 +1052,6 @@ def is_strongly_k_equimodular(self): @lazy_attribute def is_graphic(self): r""" - Return whether the matrix of ``self`` is totally unimodular. - - This depends on the choice of bases for domain and codomain. EXAMPLES:: @@ -1094,12 +1091,119 @@ def is_graphic(*, certificate=False, **kwds): column_keys = self.domain().basis().keys() row_keys = self.codomain().basis().keys() return matrix.is_graphic(certificate=True, - column_keys=column_keys, - row_keys=row_keys, - **kwds) + column_keys=column_keys, + row_keys=row_keys, + **kwds) return is_graphic + @lazy_attribute + def is_cographic(self): + r""" + + EXAMPLES:: + + sage: # needs sage.libs.cmr + sage: M = matrix([[1, 0, 0, 0, 1, -1, 1, 0, 0], + ....: [0, 1, 0, 0, 0, 1, -1, 1, 0], + ....: [0, 0, 1, 0, 0, 0, 1, -1, 1], + ....: [0, 0, 0, 1, 1, 0, 0, 1, -1]], + ....: column_keys=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], + ....: row_keys=range(4)); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'} over Integer Ring + To: Free module generated by {0, 1, 2, 3} over Integer Ring + sage: M.is_cographic() + True + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_cographic + except AttributeError: + return NotImplemented + + @functools.wraps(matrix.is_cographic) + def is_cographic(*, certificate=False, **kwds): + if not certificate: + return matrix.is_cographic(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix.is_cographic(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + + return is_cographic + + @lazy_attribute + def is_network(self): + r""" + + EXAMPLES:: + + sage: # needs sage.libs.cmr + sage: M = matrix([[-1, 0, 0, 0, 1, -1, 0], + ....: [ 1, 0, 0, 1, -1, 1, 0], + ....: [ 0, -1, 0, -1, 1, -1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1, -1, 1, 0, 1], + ....: [ 0, 0, -1, 1, -1, 0, 0]], + ....: column_keys=['a', 'b', 'c', 'd', 'e', 'f', 'g'], + ....: row_keys=range(6)); M + Generic morphism: + From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g'} over Integer Ring + To: Free module generated by {0, 1, 2, 3, 4, 5} over Integer Ring + sage: M.is_network() + True + sage: result, certificate = M.is_network(certificate=True) + sage: result, certificate + (True, + (Digraph on 7 vertices, + ((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)), + ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) + sage: digraph, forest_arcs, coforest_arcs = certificate + sage: list(digraph.edges(sort=True)) + [(0, 6, None), + (0, 8, None), + (3, 4, None), + (3, 8, None), + (3, 9, None), + (4, 0, None), + (4, 6, None), + (4, 9, None), + (5, 3, None), + (5, 4, None), + (5, 6, None), + (9, 0, None), + (9, 8, None)] + sage: digraph.plot(edge_colors={'red': forest_arcs}) # needs sage.plot + Graphics object consisting of 21 graphics primitives + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_network_matrix + except AttributeError: + return NotImplemented + + @functools.wraps(matrix.is_network_matrix) + def is_network(*, certificate=False, **kwds): + if not certificate: + return matrix.is_network_matrix(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix.is_network_matrix(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + + return is_network + @lazy_attribute def is_totally_unimodular(self): r""" @@ -1129,7 +1233,7 @@ def is_totally_unimodular(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_unimodular + method = matrix.is_totally_unimodular except AttributeError: return NotImplemented @@ -1146,6 +1250,32 @@ def is_totally_unimodular(*, certificate=False, **kwds): return is_totally_unimodular + @lazy_attribute + def is_complement_totally_unimodular(self): + r""" + """ + try: + matrix = self._matrix_cmr() + except ImportError: + matrix = self.matrix() + try: + method = matrix.is_complement_totally_unimodular + except AttributeError: + return NotImplemented + + @functools.wraps(matrix.is_complement_totally_unimodular) + def is_complement_totally_unimodular(*, certificate=False, **kwds): + if not certificate: + return matrix.is_complement_totally_unimodular(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix.is_complement_totally_unimodular(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + + return is_complement_totally_unimodular + class Homsets(HomsetsCategory): class Endset(CategoryWithAxiom): From 43d7a6f850eeb537cf6e2b213d21d11d73e5c9e2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 May 2024 16:28:43 -0700 Subject: [PATCH 147/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Refactor through decorator _wrapped_method_with_certificate --- .../finite_dimensional_modules_with_basis.py | 79 +++++-------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index d10de117516..a8cc4ca90e5 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -1049,6 +1049,20 @@ def is_strongly_k_equimodular(self): except AttributeError: return NotImplemented + def _wrapped_method_with_certificate(self, matrix_method): + + @functools.wraps(matrix_method) + def wrapper(*, certificate=False, **kwds): + if not certificate: + return matrix_method(**kwds) + column_keys = self.domain().basis().keys() + row_keys = self.codomain().basis().keys() + return matrix_method(certificate=True, + column_keys=column_keys, + row_keys=row_keys, + **kwds) + return wrapper + @lazy_attribute def is_graphic(self): r""" @@ -1080,23 +1094,10 @@ def is_graphic(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_graphic + return self._wrapped_method_with_certificate(matrix.is_graphic) except AttributeError: return NotImplemented - @functools.wraps(matrix.is_graphic) - def is_graphic(*, certificate=False, **kwds): - if not certificate: - return matrix.is_graphic(**kwds) - column_keys = self.domain().basis().keys() - row_keys = self.codomain().basis().keys() - return matrix.is_graphic(certificate=True, - column_keys=column_keys, - row_keys=row_keys, - **kwds) - - return is_graphic - @lazy_attribute def is_cographic(self): r""" @@ -1111,7 +1112,8 @@ def is_cographic(self): ....: column_keys=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], ....: row_keys=range(4)); M Generic morphism: - From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'} over Integer Ring + From: Free module generated by {'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i'} over Integer Ring To: Free module generated by {0, 1, 2, 3} over Integer Ring sage: M.is_cographic() True @@ -1121,23 +1123,10 @@ def is_cographic(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_cographic + return self._wrapped_method_with_certificate(matrix.is_cographic) except AttributeError: return NotImplemented - @functools.wraps(matrix.is_cographic) - def is_cographic(*, certificate=False, **kwds): - if not certificate: - return matrix.is_cographic(**kwds) - column_keys = self.domain().basis().keys() - row_keys = self.codomain().basis().keys() - return matrix.is_cographic(certificate=True, - column_keys=column_keys, - row_keys=row_keys, - **kwds) - - return is_cographic - @lazy_attribute def is_network(self): r""" @@ -1187,23 +1176,10 @@ def is_network(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_network_matrix + return self._wrapped_method_with_certificate(matrix.is_network_matrix) except AttributeError: return NotImplemented - @functools.wraps(matrix.is_network_matrix) - def is_network(*, certificate=False, **kwds): - if not certificate: - return matrix.is_network_matrix(**kwds) - column_keys = self.domain().basis().keys() - row_keys = self.codomain().basis().keys() - return matrix.is_network_matrix(certificate=True, - column_keys=column_keys, - row_keys=row_keys, - **kwds) - - return is_network - @lazy_attribute def is_totally_unimodular(self): r""" @@ -1233,23 +1209,10 @@ def is_totally_unimodular(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_totally_unimodular + return self._wrapped_method_with_certificate(matrix.is_totally_unimodular) except AttributeError: return NotImplemented - @functools.wraps(matrix.is_totally_unimodular) - def is_totally_unimodular(*, certificate=False, **kwds): - if not certificate: - return matrix.is_totally_unimodular(**kwds) - column_keys = self.domain().basis().keys() - row_keys = self.codomain().basis().keys() - return matrix.is_totally_unimodular(certificate=True, - column_keys=column_keys, - row_keys=row_keys, - **kwds) - - return is_totally_unimodular - @lazy_attribute def is_complement_totally_unimodular(self): r""" @@ -1259,7 +1222,7 @@ def is_complement_totally_unimodular(self): except ImportError: matrix = self.matrix() try: - method = matrix.is_complement_totally_unimodular + return self._wrapped_method_with_certificate(matrix.is_complement_totally_unimodular) except AttributeError: return NotImplemented From 3cc19fb44f8a362a72e1dd507236b29a6b1166e9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 12 Mar 2024 17:53:58 -0700 Subject: [PATCH 148/262] fix a doctest in is_totally_unimodular() --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index cd39f35f19b..86fef169d32 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1627,17 +1627,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: MFR2cmr = Matrix_cmr_chr_sparse(MS2, MFR2) sage: MFR2cmr.is_totally_unimodular(certificate=True) - (False, (None, ((0, 1, 2), (3, 4, 5)))) + (False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3)))) sage: result, certificate = MFR2cmr.is_totally_unimodular(certificate=True, ....: complete_tree=True) sage: result, certificate - (False, (None, ((0, 1, 2), (3, 4, 5)))) + (False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3)))) sage: submatrix = MFR2.matrix_from_rows_and_columns(*certificate[1]); submatrix [0 1 1] [1 0 1] [1 1 0] sage: submatrix.determinant() 2 + sage: submatrix = MFR2cmr.matrix_from_rows_and_columns(*certificate[1]); submatrix + [0 1 1] + [1 0 1] + [1 1 0] """ cdef bool result cdef CMR_TU_PARAMS params From f9154f06bb00c71318422393cffeee9f510504f3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 13 Mar 2024 10:27:34 -0700 Subject: [PATCH 149/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Catch TypeError on _matrix_cmr --- .../finite_dimensional_modules_with_basis.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index a8cc4ca90e5..1909e8bf61c 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -918,7 +918,7 @@ def is_unimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.is_unimodular @@ -948,7 +948,7 @@ def is_strongly_unimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.is_strongly_unimodular @@ -962,7 +962,7 @@ def equimodulus(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.equimodulus @@ -976,7 +976,7 @@ def strong_equimodulus(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.strong_equimodulus @@ -1006,7 +1006,7 @@ def is_k_equimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.is_k_equimodular @@ -1042,7 +1042,7 @@ def is_strongly_k_equimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return matrix.is_strongly_k_equimodular @@ -1091,7 +1091,7 @@ def is_graphic(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return self._wrapped_method_with_certificate(matrix.is_graphic) @@ -1120,7 +1120,7 @@ def is_cographic(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return self._wrapped_method_with_certificate(matrix.is_cographic) @@ -1173,7 +1173,7 @@ def is_network(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return self._wrapped_method_with_certificate(matrix.is_network_matrix) @@ -1206,7 +1206,7 @@ def is_totally_unimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return self._wrapped_method_with_certificate(matrix.is_totally_unimodular) @@ -1219,7 +1219,7 @@ def is_complement_totally_unimodular(self): """ try: matrix = self._matrix_cmr() - except ImportError: + except (ImportError, TypeError): matrix = self.matrix() try: return self._wrapped_method_with_certificate(matrix.is_complement_totally_unimodular) From 3d7b27bcf70d30d9a0757f499ba0a67c2bee5111 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 12 Mar 2024 18:37:08 -0700 Subject: [PATCH 150/262] build/pkgs/cmr: Update to 95a2bb7f9343573643f88cd5f60b10a324ad95f3 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index c1705d3be2d..239117b5a66 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=f0849b3e0f3957542ef97cf5ebb9cd24d3689153 -md5=8cc9d68d12401474ca0487d33408694f -cksum=3197857397 +sha1=884bbca725d39df754af9452e23c56899b4ce044 +md5=2b279af48e7226edaa2359470825c6d6 +cksum=4085295301 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 32d48680fc2..59e66409042 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -7abbabe27e9a0a05e5c8f4ae19a2e7c5c8c07bc9 +95a2bb7f9343573643f88cd5f60b10a324ad95f3 From fe00be8d8fa648c604bd429fe2644d9572603647 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 12 Mar 2024 20:35:14 -0700 Subject: [PATCH 151/262] use row_keys and column_keys for PivotsNode --- src/sage/matrix/seymour_decomposition.pyx | 120 ++++++---------------- 1 file changed, 32 insertions(+), 88 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b743b269289..f16b367aacf 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -137,40 +137,7 @@ cdef class DecompositionNode(SageObject): return MatrixArgs(self.matrix(), MatrixSpace(ZZ, self.row_keys(), self.column_keys())).element() @cached_method - def _parent_rows_and_columns(self): - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) - - if parent_rows == NULL or parent_rows[0] == 0: - parent_rows_cmr_tuple = None - else: - parent_rows_cmr_tuple = tuple(parent_rows[i] - for i in range(self.nrows())) - if parent_columns == NULL or parent_columns[0] == 0: - parent_columns_cmr_tuple = None - else: - parent_columns_cmr_tuple = tuple(parent_columns[i] - for i in range(self.ncols())) - - return parent_rows_cmr_tuple, parent_columns_cmr_tuple - - # def ancestor_rows_and_columns(self, ancestor, use_keys=False): - # r""" - - # INPUT: - - # - ``use_keys`` -- if ``True``, return the answer - - # OUTPUT: tuple ``(row_keys, column_keys)`` - - - - # """ - # if ancestor is self: - # pass - - @cached_method - def parent_rows_and_columns(self, indices_label=False): + def parent_rows_and_columns(self): r""" EXAMPLES:: @@ -215,43 +182,35 @@ cdef class DecompositionNode(SageObject): ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) - sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: row_keys=['r1', 'r2', 'r3', 'r4', 'r5', + ....: 'r6', 'r7', 'r8', 'r9'], + ....: column_keys=['a','b','c','d','e','f', + ....: 'g','h','i','j','k','l']) sage: C = certificate._children()[0]; C ThreeSumNode (9×12) with 2 children - sage: C.parent_rows_and_columns(indices_label=True) - ((('r', 0), - ('c', 8), - ('r', 2), - ('r', 3), - ('r', 4), - ('r', 5), - ('r', 6), - ('r', 7), - ('r', 8)), - (('c', 0), - ('c', 1), - ('c', 2), - ('c', 3), - ('c', 4), - ('c', 5), - ('c', 6), - ('c', 7), - ('r', 1), - ('c', 9), - ('c', 10), - ('c', 11))) + sage: C.parent_rows_and_columns() + (('r1', 'i', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'), + ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'r2', 'j', 'k', 'l')) """ - parent_rows, parent_columns = self._parent_rows_and_columns() - if parent_rows is None: + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) + if parent_rows == NULL or parent_rows[0] == 0: parent_rows_tuple = None else: - parent_rows_tuple = tuple(CMRelement_to_label(parent_rows[i], indices_label) - for i in range(self.nrows())) - if parent_columns is None: + if self.row_keys() is not None: + parent_rows_tuple = tuple(self.row_keys()) + else: + parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) + for i in range(self.nrows())) + if parent_columns == NULL or parent_columns[0] == 0: parent_columns_tuple = None else: - parent_columns_tuple = tuple(CMRelement_to_label(parent_columns[i], indices_label) - for i in range(self.ncols())) + if self.column_keys() is not None: + parent_columns_tuple = tuple(self.column_keys()) + else: + parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) + for i in range(self.ncols())) return parent_rows_tuple, parent_columns_tuple @@ -313,6 +272,8 @@ cdef class DecompositionNode(SageObject): cdef _CMRelement_to_key(self, CMR_ELEMENT element): if not CMRelementIsValid(element): raise ValueError('CMRelement index not valid') + if self.row_keys() is None or self.column_keys() is None: + raise ValueError('row_keys and column_keys are required') if CMRelementIsRow(element): return self.row_keys()[CMRelementToRowIndex(element)] else: @@ -325,16 +286,16 @@ cdef class DecompositionNode(SageObject): cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child_dec) cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child_dec) - child = create_DecompositionNode(child_dec, root=self._root or self) - if row_keys is not None and column_keys is not None: child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) - for i in range(child.nrows())) + for i in range(CMRmatroiddecNumRows(child_dec))) child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) - for i in range(child.ncols())) - child._set_row_keys(child_row_keys) - child._set_column_keys(child_column_keys) - + for i in range(CMRmatroiddecNumColumns(child_dec))) + child = create_DecompositionNode(child_dec, root=self._root or self, + row_keys=child_row_keys, + column_keys=child_column_keys) + else: + child = create_DecompositionNode(child_dec, root=self._root or self) return child @cached_method @@ -952,20 +913,3 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, co if column_keys is not None: result._set_column_keys(column_keys) return result - - -cdef CMRelement_to_label(CMR_ELEMENT element, indices_label=False): - r""" - """ - if not CMRelementIsValid(element): - raise ValueError('CMRelement index not valid') - if CMRelementIsRow(element): - if indices_label: - return ('r',CMRelementToRowIndex(element)) - else: - return CMRelementToRowIndex(element) - else: - if indices_label: - return ('c', CMRelementToColumnIndex(element)) - else: - return CMRelementToColumnIndex(element) From e49d849459c81b38f91fee864ce059397685cf04 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Mar 2024 12:19:08 -0700 Subject: [PATCH 152/262] WIP add three_sum_strategy and keys for Mixed_Mixed --- src/sage/matrix/matrix_cmr_sparse.pyx | 7 +- src/sage/matrix/seymour_decomposition.pyx | 120 ++++++++++++++++++++-- 2 files changed, 120 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 86fef169d32..a340f115189 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1716,7 +1716,12 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): params.completeTree = kwds['complete_tree'] is True params.threeSumPivotChildren = kwds['three_sum_pivot_children'] if kwds['three_sum_strategy'] is not None: - params.threeSumStrategy = kwds['three_sum_strategy'] + if kwds['three_sum_strategy'] == 'Mixed_Mixed': + params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_CONCENTRATED_RANK | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_MIXED | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_MIXED + elif kwds['three_sum_strategy'] == 'Wide_Wide': + params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE + else: + params.threeSumStrategy = kwds['three_sum_strategy'] params.graphs = _cmr_dec_construct(kwds['construct_graphs']) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index f16b367aacf..b74b2dcebf4 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -195,7 +195,7 @@ cdef class DecompositionNode(SageObject): """ cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) - if parent_rows == NULL or parent_rows[0] == 0: + if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(self.nrows())): parent_rows_tuple = None else: if self.row_keys() is not None: @@ -203,7 +203,7 @@ cdef class DecompositionNode(SageObject): else: parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) for i in range(self.nrows())) - if parent_columns == NULL or parent_columns[0] == 0: + if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(self.ncols())): parent_columns_tuple = None else: if self.column_keys() is not None: @@ -271,7 +271,7 @@ cdef class DecompositionNode(SageObject): cdef _CMRelement_to_key(self, CMR_ELEMENT element): if not CMRelementIsValid(element): - raise ValueError('CMRelement index not valid') + raise ValueError('CMRelement index not valid. Extra row or column is detected.') if self.row_keys() is None or self.column_keys() is None: raise ValueError('row_keys and column_keys are required') if CMRelementIsRow(element): @@ -598,9 +598,117 @@ cdef class ThreeSumNode(SumNode): @cached_method def _children(self): - # to be overridden - return tuple(self._create_child_node(index) - for index in range(self.nchildren())) + r""" + TESTS: + + This is test ``WideWideR12`` and ``MixedMixedR12`` in CMR's ``test_tu.cpp``:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Wide_Wide") + sage: C = certificate._children()[0] + sage: C1, C2 = C._children() + sage: C1.matrix() + [ 0 0 1 -1 -1] + [ 1 1 1 0 0] + [ 0 1 0 1 1] + [-1 0 -1 0 1] + sage: C2.matrix() + [ 1 0 1 -1 0] + [ 0 0 1 0 1] + [-1 -1 0 1 1] + [-1 -1 0 0 1] + + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Mixed_Mixed", + ....: row_keys=range(6), + ....: column_keys='abcdef') + sage: C1, C2 = certificate._children() + sage: C1.matrix() + [ 1 0 1 1 0] + [ 0 1 1 1 0] + [ 1 0 1 0 1] + [ 0 -1 0 -1 1] + sage: C2.matrix() + [ 1 1 0 0] + [ 1 0 1 1] + [ 0 -1 1 1] + [ 1 0 1 0] + [ 0 -1 0 1] + sage: C1.parent_rows_and_columns() + (('r1', 'r2', 'r3', 'r4'), ('a', 'b', 'c', 'd', 'x')) + sage: C2.parent_rows_and_columns() + (('x', 'r3', 'r4', 'r5', 'r6'), ('a', 'd', 'e', 'f')) + + + sage: R12_pivot = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,0,1,-1,0],[0,1,1,1,0,0],[1,0,0,0,0,1], + ....: [0,-1,0,-1,1,1],[-1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: result, certificate = R12_pivot.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Mixed_Mixed", + ....: row_keys=["r1", "r2", "r3", "r4", "a", "r6"], + ....: column_keys=["r5", "b", "c", "d", "e", "f"]) + sage: C1, C2 = certificate._children()[0]._children() + sage: C1.matrix() + [ 1 0 1 1 0] + [ 0 1 1 1 0] + [ 1 0 1 0 1] + [ 0 -1 0 -1 1] + sage: C2.matrix() + [ 1 1 0 0] + [ 1 0 1 1] + [ 0 -1 1 1] + [ 1 0 1 0] + [ 0 -1 0 1] + sage: C1.parent_rows_and_columns() + (('r1', 'r2', 'r3', 'r4'), ('a', 'b', 'c', 'd', 'x')) + sage: C2.parent_rows_and_columns() + (('x', 'r3', 'r4', 'r5', 'r6'), ('a', 'd', 'e', 'f')) + """ + if self.nchildren() != 2: + raise ValueError("ThreeSumNode has exactly two children") + + cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) + cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecRowsParent(child1_dec) + cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecColumnsParent(child1_dec) + + cdef CMR_MATROID_DEC *child2_dec = CMRmatroiddecChild(self._dec, 1) + cdef CMR_ELEMENT *parent_rows2 = CMRmatroiddecRowsParent(child2_dec) + cdef CMR_ELEMENT *parent_columns2 = CMRmatroiddecColumnsParent(child2_dec) + + row_keys = self.row_keys() + column_keys = self.column_keys() + + if row_keys is not None and column_keys is not None: + child1_nrows = CMRmatroiddecNumRows(child1_dec) + child1_ncols = CMRmatroiddecNumColumns(child1_dec) + child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) + for i in range(child1_nrows)) + child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) + for i in range(child1_ncols - 1)) + + child1_column_keys += ((row_keys[child1_nrows-2], row_keys[child1_nrows-1]),) + child1 = create_DecompositionNode(child1_dec, root=self._root or self, + row_keys=child1_row_keys, + column_keys=child1_column_keys) + + child2_nrows = CMRmatroiddecNumRows(child2_dec) + child2_ncols = CMRmatroiddecNumColumns(child2_dec) + child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) + for i in range(1, child2_nrows)) + child2_row_keys = ((column_keys[0], column_keys[1]),) + child2_row_keys + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(child2_ncols)) + child2 = create_DecompositionNode(child2_dec, root=self._root or self, + row_keys=child2_row_keys, + column_keys=child2_column_keys) + else: + child1 = create_DecompositionNode(child1_dec, root=self._root or self) + child2 = create_DecompositionNode(child2_dec, root=self._root or self) + return (child1, child2) def is_distributed_ranks(self): r""" From 528a75a63d438eea01b40ca578147f6b550b4aa9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Mar 2024 16:42:30 -0700 Subject: [PATCH 153/262] add Wide_Wide and Mixed_Mixed label for extra row and column --- src/sage/matrix/seymour_decomposition.pyx | 143 ++++++++++++++++------ 1 file changed, 105 insertions(+), 38 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b74b2dcebf4..ea6efaeebc9 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -18,6 +18,7 @@ from libc.stdint cimport SIZE_MAX from sage.libs.cmr.cmr cimport * from sage.misc.cachefunc import cached_method +from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject @@ -608,8 +609,12 @@ cdef class ThreeSumNode(SumNode): ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True, - ....: three_sum_strategy="Wide_Wide") + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(6), + ....: column_keys='abcdef') sage: C = certificate._children()[0] + sage: C.parent_rows_and_columns() + ((0, 1, 2, 3, 'a', 5), (4, 'b', 'c', 'd', 'e', 'f')) sage: C1, C2 = C._children() sage: C1.matrix() [ 0 0 1 -1 -1] @@ -621,6 +626,10 @@ cdef class ThreeSumNode(SumNode): [ 0 0 1 0 1] [-1 -1 0 1 1] [-1 -1 0 0 1] + sage: C1.parent_rows_and_columns() + ((0, 1, 'a', 3), ('b', 'c', 'd', 'e', ('e', '+', 3))) + sage: C2.parent_rows_and_columns() + ((0, 2, 3, 5), (('b', '+', 0), 'd', 4, 'e', 'f')) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed", @@ -639,34 +648,9 @@ cdef class ThreeSumNode(SumNode): [ 1 0 1 0] [ 0 -1 0 1] sage: C1.parent_rows_and_columns() - (('r1', 'r2', 'r3', 'r4'), ('a', 'b', 'c', 'd', 'x')) + ((0, 1, 2, 3), ('a', 'b', 'c', 'd', (2, '+', 3))) sage: C2.parent_rows_and_columns() - (('x', 'r3', 'r4', 'r5', 'r6'), ('a', 'd', 'e', 'f')) - - - sage: R12_pivot = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), - ....: [[1,0,0,1,-1,0],[0,1,1,1,0,0],[1,0,0,0,0,1], - ....: [0,-1,0,-1,1,1],[-1,0,1,0,1,0],[0,-1,0,-1,0,1]]) - sage: result, certificate = R12_pivot.is_totally_unimodular(certificate=True, - ....: three_sum_strategy="Mixed_Mixed", - ....: row_keys=["r1", "r2", "r3", "r4", "a", "r6"], - ....: column_keys=["r5", "b", "c", "d", "e", "f"]) - sage: C1, C2 = certificate._children()[0]._children() - sage: C1.matrix() - [ 1 0 1 1 0] - [ 0 1 1 1 0] - [ 1 0 1 0 1] - [ 0 -1 0 -1 1] - sage: C2.matrix() - [ 1 1 0 0] - [ 1 0 1 1] - [ 0 -1 1 1] - [ 1 0 1 0] - [ 0 -1 0 1] - sage: C1.parent_rows_and_columns() - (('r1', 'r2', 'r3', 'r4'), ('a', 'b', 'c', 'd', 'x')) - sage: C2.parent_rows_and_columns() - (('x', 'r3', 'r4', 'r5', 'r6'), ('a', 'd', 'e', 'f')) + ((('a', '+', 'b'), 2, 3, 4, 5), ('a', 'd', 'e', 'f')) """ if self.nchildren() != 2: raise ValueError("ThreeSumNode has exactly two children") @@ -674,10 +658,14 @@ cdef class ThreeSumNode(SumNode): cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecRowsParent(child1_dec) cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecColumnsParent(child1_dec) + cdef CMR_CHRMAT *mat1 = CMRmatroiddecGetMatrix(child1_dec) cdef CMR_MATROID_DEC *child2_dec = CMRmatroiddecChild(self._dec, 1) cdef CMR_ELEMENT *parent_rows2 = CMRmatroiddecRowsParent(child2_dec) cdef CMR_ELEMENT *parent_columns2 = CMRmatroiddecColumnsParent(child2_dec) + cdef CMR_CHRMAT *mat2 = CMRmatroiddecGetMatrix(child2_dec) + + cdef size_t index1, index2 row_keys = self.row_keys() column_keys = self.column_keys() @@ -685,23 +673,102 @@ cdef class ThreeSumNode(SumNode): if row_keys is not None and column_keys is not None: child1_nrows = CMRmatroiddecNumRows(child1_dec) child1_ncols = CMRmatroiddecNumColumns(child1_dec) - child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) - for i in range(child1_nrows)) - child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) - for i in range(child1_ncols - 1)) - child1_column_keys += ((row_keys[child1_nrows-2], row_keys[child1_nrows-1]),) + if self.is_concentrated_rank(): # Mixed_Mixed + child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) + for i in range(child1_nrows)) + child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) + for i in range(child1_ncols - 1)) + + CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-2, child1_ncols-1, &index1)) + if index1 == SIZE_MAX: + epsilon1 = Integer(0) + else: + epsilon1 = Integer(mat1.entryValues[index1]) + + CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-1, child1_ncols-1, &index2)) + if index2 == SIZE_MAX: + epsilon2 = Integer(0) + else: + epsilon2 = Integer(mat1.entryValues[index2]) + + if epsilon1 * epsilon2 == 1: + label = '+' + else: + label = '-' + + child1_column_keys += ((row_keys[child1_nrows-2], label, + row_keys[child1_nrows-1]),) + else: # Wide_Wide + child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) + for i in range(child1_nrows)) + child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) + for i in range(child1_ncols - 1)) + + CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-1, child1_ncols-1, &index1)) + if index1 == SIZE_MAX: + epsilon1 = Integer(0) + else: + epsilon1 = Integer(mat1.entryValues[index1]) + + if epsilon1 == 1: + label = '+' + else: + label = '-' + + child1_column_keys += ((column_keys[child1_ncols-1], label, + row_keys[child1_nrows-1]),) + child1 = create_DecompositionNode(child1_dec, root=self._root or self, row_keys=child1_row_keys, column_keys=child1_column_keys) child2_nrows = CMRmatroiddecNumRows(child2_dec) child2_ncols = CMRmatroiddecNumColumns(child2_dec) - child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) - for i in range(1, child2_nrows)) - child2_row_keys = ((column_keys[0], column_keys[1]),) + child2_row_keys - child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) - for i in range(child2_ncols)) + + if self.is_concentrated_rank(): # Mixed_Mixed + child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) + for i in range(1, child2_nrows)) + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) + if index1 == SIZE_MAX: + epsilon1 = Integer(0) + else: + epsilon1 = Integer(mat1.entryValues[index1]) + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 1, &index2)) + if index2 == SIZE_MAX: + epsilon2 = Integer(0) + else: + epsilon2 = Integer(mat1.entryValues[index2]) + + if epsilon1 * epsilon2 == 1: + label = '+' + else: + label = '-' + + child2_row_keys = ((column_keys[0], label, column_keys[1]), ) + child2_row_keys + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(child2_ncols)) + else: # Wide_Wide + child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) + for i in range(child2_nrows)) + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) + if index1 == SIZE_MAX: + epsilon1 = Integer(0) + else: + epsilon1 = Integer(mat1.entryValues[index1]) + + if epsilon1 == 1: + label = '+' + else: + label = '-' + + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(1, child2_ncols)) + child2_column_keys = ((column_keys[1], label, row_keys[0]), ) + child2_column_keys + child2 = create_DecompositionNode(child2_dec, root=self._root or self, row_keys=child2_row_keys, column_keys=child2_column_keys) From ec921e7870a19c7c4006e7d207b7f63faa093c99 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 13 Mar 2024 16:45:27 -0700 Subject: [PATCH 154/262] build/pkgs/cmr: Update to ac12f7f929f89e6a7b465fa4d45439eab0d9009f --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 239117b5a66..a8c4e51315d 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=884bbca725d39df754af9452e23c56899b4ce044 -md5=2b279af48e7226edaa2359470825c6d6 -cksum=4085295301 +sha1=e56bd20e619de12f3606cd76753a9a80cf269a8f +md5=f1e8dd0fd20ba21242af89e075a2297c +cksum=1704628798 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 59e66409042..506146c075c 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -95a2bb7f9343573643f88cd5f60b10a324ad95f3 +ac12f7f929f89e6a7b465fa4d45439eab0d9009f From 79b479003b147f8f5c9ab4f73702ac8bfc4bb816 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sat, 16 Mar 2024 09:53:40 -0700 Subject: [PATCH 155/262] Add class DecompositionNodeIndexKey --- src/sage/matrix/seymour_decomposition.pyx | 73 ++++++++++++++--------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ea6efaeebc9..f00de72ff1b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -276,9 +276,9 @@ cdef class DecompositionNode(SageObject): if self.row_keys() is None or self.column_keys() is None: raise ValueError('row_keys and column_keys are required') if CMRelementIsRow(element): - return self.row_keys()[CMRelementToRowIndex(element)] + return DecompositionNodeIndexKey(self.row_keys()[CMRelementToRowIndex(element)]) else: - return self.column_keys()[CMRelementToColumnIndex(element)] + return DecompositionNodeIndexKey(self.column_keys()[CMRelementToColumnIndex(element)]) def _create_child_node(self, index): row_keys = self.row_keys() @@ -692,13 +692,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - if epsilon1 * epsilon2 == 1: - label = '+' - else: - label = '-' - - child1_column_keys += ((row_keys[child1_nrows-2], label, - row_keys[child1_nrows-1]),) + child1_column_keys += (DecompositionNodeIndexKey((epsilon1, row_keys[child1_nrows-2], epsilon2, row_keys[child1_nrows-1]), composition=True),) else: # Wide_Wide child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) for i in range(child1_nrows)) @@ -711,13 +705,8 @@ cdef class ThreeSumNode(SumNode): else: epsilon1 = Integer(mat1.entryValues[index1]) - if epsilon1 == 1: - label = '+' - else: - label = '-' - - child1_column_keys += ((column_keys[child1_ncols-1], label, - row_keys[child1_nrows-1]),) + child1_column_keys += (DecompositionNodeIndexKey((1, column_keys[child1_ncols-1], epsilon1, + row_keys[child1_nrows-1]), composition=True),) child1 = create_DecompositionNode(child1_dec, root=self._root or self, row_keys=child1_row_keys, @@ -742,12 +731,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - if epsilon1 * epsilon2 == 1: - label = '+' - else: - label = '-' - - child2_row_keys = ((column_keys[0], label, column_keys[1]), ) + child2_row_keys + child2_row_keys = (DecompositionNodeIndexKey((epsilon1, column_keys[0], epsilon2, column_keys[1]), composition=True), ) + child2_row_keys child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(child2_ncols)) else: # Wide_Wide @@ -760,14 +744,9 @@ cdef class ThreeSumNode(SumNode): else: epsilon1 = Integer(mat1.entryValues[index1]) - if epsilon1 == 1: - label = '+' - else: - label = '-' - child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(1, child2_ncols)) - child2_column_keys = ((column_keys[1], label, row_keys[0]), ) + child2_column_keys + child2_column_keys = (DecompositionNodeIndexKey((1, column_keys[1], epsilon1, row_keys[0]), composition=True),) + child2_column_keys child2 = create_DecompositionNode(child2_dec, root=self._root or self, row_keys=child2_row_keys, @@ -1038,6 +1017,44 @@ cdef class SubmatrixNode(DecompositionNode): pass +cdef class DecompositionNodeIndexKey: + + cdef frozenset _core + cdef bint _composition + + def __init__(self, keys, composition=False): + """ + Return the index key. + + frozenset((1,'a'), (-1,'7')) + """ + if composition: + sign1, key1, sign2, key2 = keys + self._core = frozenset([(sign1, key1), (sign2, key2)]) + self._composition = True + else: + self._core = frozenset((keys,)) + self._composition = False + + @property + def key(self): + return self._core + + def __hash__(self): + return hash(self._core) + + def __eq__(self, other): + if isinstance(other, DecompositionNodeIndexKey): + return self._core == other._core + return False + + def __repr__(self): + if self._composition: + return "".join(['+'+str(a[1]) if a[0] == 1 else '-'+str(a[1]) for a in self._core]) + else: + return "".join([str(a) for a in self._core]) + + cdef _class(CMR_MATROID_DEC *dec): cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(dec) From 1528349c438d295bf9eb843a7abc2a2af4552f26 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sat, 16 Mar 2024 09:54:31 -0700 Subject: [PATCH 156/262] fix doctests --- src/sage/matrix/seymour_decomposition.pyx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index f00de72ff1b..d483634d326 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -191,8 +191,7 @@ cdef class DecompositionNode(SageObject): sage: C = certificate._children()[0]; C ThreeSumNode (9×12) with 2 children sage: C.parent_rows_and_columns() - (('r1', 'i', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'), - ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'r2', 'j', 'k', 'l')) + ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) """ cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) @@ -614,7 +613,7 @@ cdef class ThreeSumNode(SumNode): ....: column_keys='abcdef') sage: C = certificate._children()[0] sage: C.parent_rows_and_columns() - ((0, 1, 2, 3, 'a', 5), (4, 'b', 'c', 'd', 'e', 'f')) + ((0, 1, 2, 3, a, 5), (4, b, c, d, e, f)) sage: C1, C2 = C._children() sage: C1.matrix() [ 0 0 1 -1 -1] @@ -627,9 +626,9 @@ cdef class ThreeSumNode(SumNode): [-1 -1 0 1 1] [-1 -1 0 0 1] sage: C1.parent_rows_and_columns() - ((0, 1, 'a', 3), ('b', 'c', 'd', 'e', ('e', '+', 3))) + ((0, 1, a, 3), (b, c, d, e, +3+e)) sage: C2.parent_rows_and_columns() - ((0, 2, 3, 5), (('b', '+', 0), 'd', 4, 'e', 'f')) + ((0, 2, 3, 5), (+b+0, d, 4, e, f)) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed", @@ -648,9 +647,9 @@ cdef class ThreeSumNode(SumNode): [ 1 0 1 0] [ 0 -1 0 1] sage: C1.parent_rows_and_columns() - ((0, 1, 2, 3), ('a', 'b', 'c', 'd', (2, '+', 3))) + ((0, 1, 2, 3), (a, b, c, d, +2+3)) sage: C2.parent_rows_and_columns() - ((('a', '+', 'b'), 2, 3, 4, 5), ('a', 'd', 'e', 'f')) + ((+a+b, 2, 3, 4, 5), (a, d, e, f)) """ if self.nchildren() != 2: raise ValueError("ThreeSumNode has exactly two children") From c1c469252cc7322bb1fc809ac69d806d070c28f9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sat, 16 Mar 2024 10:05:12 -0700 Subject: [PATCH 157/262] build/pkgs/cmr: Update to 5a8fc240b1c3c7807c246ec27bee5246db2e0e1e --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index a8c4e51315d..30afb273b14 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=e56bd20e619de12f3606cd76753a9a80cf269a8f -md5=f1e8dd0fd20ba21242af89e075a2297c -cksum=1704628798 +sha1=3927c05adb4a21122deb59df01707122df0ba7b2 +md5=ed2211ba7c06abed5579b6987f67974b +cksum=3326371555 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 506146c075c..809b3fa2a95 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -ac12f7f929f89e6a7b465fa4d45439eab0d9009f +5a8fc240b1c3c7807c246ec27bee5246db2e0e1e From 02d8b76bd400a3a98607887d45b636740d62804b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sat, 16 Mar 2024 20:53:16 -0700 Subject: [PATCH 158/262] Rename with ElementKey --- src/sage/matrix/seymour_decomposition.pyx | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d483634d326..cb0daba3e4c 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -275,9 +275,9 @@ cdef class DecompositionNode(SageObject): if self.row_keys() is None or self.column_keys() is None: raise ValueError('row_keys and column_keys are required') if CMRelementIsRow(element): - return DecompositionNodeIndexKey(self.row_keys()[CMRelementToRowIndex(element)]) + return ElementKey(self.row_keys()[CMRelementToRowIndex(element)]) else: - return DecompositionNodeIndexKey(self.column_keys()[CMRelementToColumnIndex(element)]) + return ElementKey(self.column_keys()[CMRelementToColumnIndex(element)]) def _create_child_node(self, index): row_keys = self.row_keys() @@ -691,7 +691,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - child1_column_keys += (DecompositionNodeIndexKey((epsilon1, row_keys[child1_nrows-2], epsilon2, row_keys[child1_nrows-1]), composition=True),) + child1_column_keys += (ElementKey((epsilon1, row_keys[child1_nrows-2], epsilon2, row_keys[child1_nrows-1]), composition=True),) else: # Wide_Wide child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) for i in range(child1_nrows)) @@ -704,7 +704,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon1 = Integer(mat1.entryValues[index1]) - child1_column_keys += (DecompositionNodeIndexKey((1, column_keys[child1_ncols-1], epsilon1, + child1_column_keys += (ElementKey((1, column_keys[child1_ncols-1], epsilon1, row_keys[child1_nrows-1]), composition=True),) child1 = create_DecompositionNode(child1_dec, root=self._root or self, @@ -730,7 +730,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - child2_row_keys = (DecompositionNodeIndexKey((epsilon1, column_keys[0], epsilon2, column_keys[1]), composition=True), ) + child2_row_keys + child2_row_keys = (ElementKey((epsilon1, column_keys[0], epsilon2, column_keys[1]), composition=True), ) + child2_row_keys child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(child2_ncols)) else: # Wide_Wide @@ -745,7 +745,7 @@ cdef class ThreeSumNode(SumNode): child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(1, child2_ncols)) - child2_column_keys = (DecompositionNodeIndexKey((1, column_keys[1], epsilon1, row_keys[0]), composition=True),) + child2_column_keys + child2_column_keys = (ElementKey((1, column_keys[1], epsilon1, row_keys[0]), composition=True),) + child2_column_keys child2 = create_DecompositionNode(child2_dec, root=self._root or self, row_keys=child2_row_keys, @@ -1016,9 +1016,9 @@ cdef class SubmatrixNode(DecompositionNode): pass -cdef class DecompositionNodeIndexKey: +cdef class ElementKey: - cdef frozenset _core + cdef frozenset _key cdef bint _composition def __init__(self, keys, composition=False): @@ -1029,29 +1029,29 @@ cdef class DecompositionNodeIndexKey: """ if composition: sign1, key1, sign2, key2 = keys - self._core = frozenset([(sign1, key1), (sign2, key2)]) + self._key = frozenset([(sign1, key1), (sign2, key2)]) self._composition = True else: - self._core = frozenset((keys,)) + self._key = frozenset((keys,)) self._composition = False @property def key(self): - return self._core + return self._key def __hash__(self): - return hash(self._core) + return hash(self._key) def __eq__(self, other): - if isinstance(other, DecompositionNodeIndexKey): - return self._core == other._core + if isinstance(other, ElementKey): + return self._key == other._key return False def __repr__(self): if self._composition: - return "".join(['+'+str(a[1]) if a[0] == 1 else '-'+str(a[1]) for a in self._core]) + return "".join(['+'+str(a[1]) if a[0] == 1 else '-'+str(a[1]) for a in self._key]) else: - return "".join([str(a) for a in self._core]) + return "".join([str(a) for a in self._key]) cdef _class(CMR_MATROID_DEC *dec): From 76a3707b2744ba05c9e0837045d336e158a1332c Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 17 Mar 2024 11:46:00 -0700 Subject: [PATCH 159/262] refactored row/column to parent element mapping --- src/sage/libs/cmr/cmr.pxd | 10 ++--- src/sage/matrix/seymour_decomposition.pyx | 55 +++++++++++------------ 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index e5cb9ca1f9b..60258789332 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -237,9 +237,9 @@ cdef extern from "cmr/matroid.h": int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecRowsParent(CMR_MATROID_DEC* dec) size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecColumnsParent(CMR_MATROID_DEC* dec) + CMR_ELEMENT* CMRmatroiddecChildRowsToParent(CMR_MATROID_DEC* dec, size_t childIndex) + CMR_ELEMENT* CMRmatroiddecChildColumnsToParent(CMR_MATROID_DEC* dec, size_t childIndex) CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) @@ -255,9 +255,9 @@ cdef extern from "cmr/matroid.h": size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) - # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, size_t indent, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) - CMR_ERROR CMRmatroiddecFree(CMR* cmr, CMR_MATROID_DEC** pdec) - CMR_ERROR CMRmatroiddecFreeNode(CMR* cmr, CMR_MATROID_DEC** pdec) + # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + CMR_ERROR CMRmatroiddecCapture(CMR* cmr, CMR_MATROID_DEC* dec) + CMR_ERROR CMRmatroiddecRelease(CMR* cmr, CMR_MATROID_DEC** pdec) cdef extern from "cmr/separation.h": diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index cb0daba3e4c..09d019f6df7 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -39,7 +39,7 @@ cdef class DecompositionNode(SageObject): if self._root is None or self._root is self: if self._dec != NULL: # We own it, so we have to free it. - CMR_CALL(CMRmatroiddecFree(cmr, &self._dec)) + CMR_CALL(CMRmatroiddecRelease(cmr, &self._dec)) self._dec = dec self._root = root @@ -193,26 +193,7 @@ cdef class DecompositionNode(SageObject): sage: C.parent_rows_and_columns() ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) """ - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(self._dec) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(self._dec) - if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(self.nrows())): - parent_rows_tuple = None - else: - if self.row_keys() is not None: - parent_rows_tuple = tuple(self.row_keys()) - else: - parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) - for i in range(self.nrows())) - if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(self.ncols())): - parent_columns_tuple = None - else: - if self.column_keys() is not None: - parent_columns_tuple = tuple(self.column_keys()) - else: - parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) - for i in range(self.ncols())) - - return parent_rows_tuple, parent_columns_tuple + return self.row_keys(), self.column_keys() def as_ordered_tree(self): r""" @@ -283,19 +264,33 @@ cdef class DecompositionNode(SageObject): row_keys = self.row_keys() column_keys = self.column_keys() cdef CMR_MATROID_DEC *child_dec = CMRmatroiddecChild(self._dec, index) - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecRowsParent(child_dec) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecColumnsParent(child_dec) + cdef CMR_ELEMENT *parent_rows = CMRmatroiddecChildRowsToParent(self._dec, index) + cdef CMR_ELEMENT *parent_columns = CMRmatroiddecChildColumnsToParent(self._dec, index) + child_nrows = CMRmatroiddecNumRows(child_dec) + child_ncols = CMRmatroiddecNumColumns(child_dec) if row_keys is not None and column_keys is not None: child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) - for i in range(CMRmatroiddecNumRows(child_dec))) + for i in range(child_nrows)) child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) - for i in range(CMRmatroiddecNumColumns(child_dec))) + for i in range(child_ncols)) child = create_DecompositionNode(child_dec, root=self._root or self, row_keys=child_row_keys, column_keys=child_column_keys) else: - child = create_DecompositionNode(child_dec, root=self._root or self) + if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(child_nrows)): + parent_rows_tuple = None + else: + parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) + for i in range(child_nrows)) + if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(child_ncols)): + parent_columns_tuple = None + else: + parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) + for i in range(child_ncols)) + child = create_DecompositionNode(child_dec, root=self._root or self, + row_keys=parent_rows_tuple, + column_keys=parent_columns_tuple) return child @cached_method @@ -655,13 +650,13 @@ cdef class ThreeSumNode(SumNode): raise ValueError("ThreeSumNode has exactly two children") cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) - cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecRowsParent(child1_dec) - cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecColumnsParent(child1_dec) + cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecChildRowsToParent(self._dec, 0) + cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecChildColumnsToParent(self._dec, 0) cdef CMR_CHRMAT *mat1 = CMRmatroiddecGetMatrix(child1_dec) cdef CMR_MATROID_DEC *child2_dec = CMRmatroiddecChild(self._dec, 1) - cdef CMR_ELEMENT *parent_rows2 = CMRmatroiddecRowsParent(child2_dec) - cdef CMR_ELEMENT *parent_columns2 = CMRmatroiddecColumnsParent(child2_dec) + cdef CMR_ELEMENT *parent_rows2 = CMRmatroiddecChildRowsToParent(self._dec, 1) + cdef CMR_ELEMENT *parent_columns2 = CMRmatroiddecChildColumnsToParent(self._dec, 1) cdef CMR_CHRMAT *mat2 = CMRmatroiddecGetMatrix(child2_dec) cdef size_t index1, index2 From 9040ebc77b8eafd356f9c6e0a78db988589b77b8 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 17 Mar 2024 12:10:10 -0700 Subject: [PATCH 160/262] fix child parent indices refactor --- src/sage/matrix/seymour_decomposition.pyx | 60 +++++++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 09d019f6df7..744366e4ed6 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -623,7 +623,47 @@ cdef class ThreeSumNode(SumNode): sage: C1.parent_rows_and_columns() ((0, 1, a, 3), (b, c, d, e, +3+e)) sage: C2.parent_rows_and_columns() - ((0, 2, 3, 5), (+b+0, d, 4, e, f)) + ((0, 2, 3, 5), (+d+0, d, 4, e, f)) + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12_large.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(9), + ....: column_keys='abcdefghijkl') + sage: C = certificate._children()[0]; C + ThreeSumNode (9×12) with 2 children + sage: C1, C2 = C._children() + sage: C1.matrix() + [ 0 0 1 1 1 1 1] + [ 1 1 0 0 0 -1 -1] + [ 1 0 -1 0 -1 -1 -1] + [ 0 1 1 0 1 0 0] + [ 0 0 0 -1 -1 0 -1] + sage: C2.matrix() + [ 1 0 0 0 0 1 -1 0 -1] + [ 0 0 1 -1 0 -1 1 0 1] + [-1 -1 1 0 1 -1 1 0 1] + [-1 -1 0 1 1 0 0 0 0] + [-1 -1 0 0 0 0 1 1 1] + [-1 -1 0 0 0 0 1 1 0] + sage: C.row_keys() + (0, i, 2, 3, 4, 5, 6, 7, 8) + sage: C.column_keys() + (a, b, c, d, e, f, g, h, 1, j, k, l) + sage: C1.parent_rows_and_columns() + ((i, 2, 7, 8, 3), (g, h, j, k, l, d, -3+d)) + sage: C2.parent_rows_and_columns() + ((i, 0, 3, 4, 5, 6), (+i+k, k, a, b, c, d, e, f, 1)) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed", @@ -642,9 +682,9 @@ cdef class ThreeSumNode(SumNode): [ 1 0 1 0] [ 0 -1 0 1] sage: C1.parent_rows_and_columns() - ((0, 1, 2, 3), (a, b, c, d, +2+3)) + ((0, 1, 2, 3), (a, b, c, d, +3+2)) sage: C2.parent_rows_and_columns() - ((+a+b, 2, 3, 4, 5), (a, d, e, f)) + ((+a+d, 2, 3, 4, 5), (a, d, e, f)) """ if self.nchildren() != 2: raise ValueError("ThreeSumNode has exactly two children") @@ -686,7 +726,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - child1_column_keys += (ElementKey((epsilon1, row_keys[child1_nrows-2], epsilon2, row_keys[child1_nrows-1]), composition=True),) + child1_column_keys += (ElementKey((epsilon1, child1_row_keys[child1_nrows-2], epsilon2, child1_row_keys[child1_nrows-1]), composition=True),) else: # Wide_Wide child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) for i in range(child1_nrows)) @@ -699,8 +739,8 @@ cdef class ThreeSumNode(SumNode): else: epsilon1 = Integer(mat1.entryValues[index1]) - child1_column_keys += (ElementKey((1, column_keys[child1_ncols-1], epsilon1, - row_keys[child1_nrows-1]), composition=True),) + child1_column_keys += (ElementKey((1, child1_column_keys[child1_ncols-2], epsilon1, + child1_row_keys[child1_nrows-1]), composition=True),) child1 = create_DecompositionNode(child1_dec, root=self._root or self, row_keys=child1_row_keys, @@ -712,6 +752,8 @@ cdef class ThreeSumNode(SumNode): if self.is_concentrated_rank(): # Mixed_Mixed child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) for i in range(1, child2_nrows)) + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(child2_ncols)) CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) if index1 == SIZE_MAX: @@ -725,9 +767,7 @@ cdef class ThreeSumNode(SumNode): else: epsilon2 = Integer(mat1.entryValues[index2]) - child2_row_keys = (ElementKey((epsilon1, column_keys[0], epsilon2, column_keys[1]), composition=True), ) + child2_row_keys - child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) - for i in range(child2_ncols)) + child2_row_keys = (ElementKey((epsilon1, child2_column_keys[0], epsilon2, child2_column_keys[1]), composition=True), ) + child2_row_keys else: # Wide_Wide child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) for i in range(child2_nrows)) @@ -740,7 +780,7 @@ cdef class ThreeSumNode(SumNode): child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(1, child2_ncols)) - child2_column_keys = (ElementKey((1, column_keys[1], epsilon1, row_keys[0]), composition=True),) + child2_column_keys + child2_column_keys = (ElementKey((1, child2_column_keys[0], epsilon1, child2_row_keys[0]), composition=True),) + child2_column_keys child2 = create_DecompositionNode(child2_dec, root=self._root or self, row_keys=child2_row_keys, From b238184536ddd35cf00bc620cb2fb0da89b28062 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 17 Mar 2024 14:16:47 -0700 Subject: [PATCH 161/262] sort keys in the frozenset and add raise ValueError --- src/sage/matrix/seymour_decomposition.pyx | 129 ++++++++++++++++------ 1 file changed, 95 insertions(+), 34 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 744366e4ed6..25fb9316ac6 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -279,12 +279,12 @@ cdef class DecompositionNode(SageObject): column_keys=child_column_keys) else: if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(child_nrows)): - parent_rows_tuple = None + raise ValueError(f"Child {index} does not have parents rows") else: parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) for i in range(child_nrows)) if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(child_ncols)): - parent_columns_tuple = None + raise ValueError(f"Child {index} does not have parents columns") else: parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) for i in range(child_ncols)) @@ -298,7 +298,8 @@ cdef class DecompositionNode(SageObject): r""" Return a tuple of the children. - The children are sorted by their :meth:`parent_rows_and_columns`. + The children are sorted by the inherited ordering from cmr, which + is their appreance in the parent. In the case of :class:`SumNode`, this is the same as :meth:`~SumNode.summands`. @@ -623,7 +624,7 @@ cdef class ThreeSumNode(SumNode): sage: C1.parent_rows_and_columns() ((0, 1, a, 3), (b, c, d, e, +3+e)) sage: C2.parent_rows_and_columns() - ((0, 2, 3, 5), (+d+0, d, 4, e, f)) + ((0, 2, 3, 5), (+0+d, d, 4, e, f)) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), @@ -682,12 +683,12 @@ cdef class ThreeSumNode(SumNode): [ 1 0 1 0] [ 0 -1 0 1] sage: C1.parent_rows_and_columns() - ((0, 1, 2, 3), (a, b, c, d, +3+2)) + ((0, 1, 2, 3), (a, b, c, d, +2+3)) sage: C2.parent_rows_and_columns() ((+a+d, 2, 3, 4, 5), (a, d, e, f)) """ if self.nchildren() != 2: - raise ValueError("ThreeSumNode has exactly two children") + raise ValueError(f"ThreeSumNode has exactly two children not {self.nchildren()}!") cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecChildRowsToParent(self._dec, 0) @@ -714,33 +715,57 @@ cdef class ThreeSumNode(SumNode): child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) for i in range(child1_ncols - 1)) - CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-2, child1_ncols-1, &index1)) + row1_index = child1_nrows - 2 + CMR_CALL(CMRchrmatFindEntry(mat1, row1_index, child1_ncols-1, &index1)) if index1 == SIZE_MAX: - epsilon1 = Integer(0) + eps1 = Integer(0) else: - epsilon1 = Integer(mat1.entryValues[index1]) - - CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-1, child1_ncols-1, &index2)) + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1: + raise ValueError(f"First child in the Mixed_Mixed Three Sum " + f"has 1 in the entry " + f"row {row1_index} and column {child1_ncols-1} " + f"but got {eps1}") + + row2_index = child1_nrows - 1 + CMR_CALL(CMRchrmatFindEntry(mat1, row2_index, child1_ncols-1, &index2)) if index2 == SIZE_MAX: - epsilon2 = Integer(0) + eps2 = Integer(0) else: - epsilon2 = Integer(mat1.entryValues[index2]) - - child1_column_keys += (ElementKey((epsilon1, child1_row_keys[child1_nrows-2], epsilon2, child1_row_keys[child1_nrows-1]), composition=True),) + eps2 = Integer(mat1.entryValues[index2]) + if eps2 != 1 and eps2 != -1: + raise ValueError(f"First child in the Mixed_Mixed Three Sum " + f"has 1 or -1 in the entry " + f"row {row2_index} and column {child1_ncols-1} " + f"but got {eps2}") + + extra_key = ElementKey((eps1, child1_row_keys[row1_index], + eps2, child1_row_keys[row2_index]), + composition=True) + child1_column_keys += (extra_key,) else: # Wide_Wide child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) for i in range(child1_nrows)) child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) for i in range(child1_ncols - 1)) - CMR_CALL(CMRchrmatFindEntry(mat1, child1_nrows-1, child1_ncols-1, &index1)) + row_index = child1_nrows - 1 + column_index = child1_ncols - 2 + CMR_CALL(CMRchrmatFindEntry(mat1, row_index, child1_ncols-1, &index1)) if index1 == SIZE_MAX: - epsilon1 = Integer(0) + eps1 = Integer(0) else: - epsilon1 = Integer(mat1.entryValues[index1]) - - child1_column_keys += (ElementKey((1, child1_column_keys[child1_ncols-2], epsilon1, - child1_row_keys[child1_nrows-1]), composition=True),) + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1 and eps1 != -1: + raise ValueError(f"First child in the Wide_Wide Three Sum " + f"has 1 or -1 in the entry " + f"row {row_index} and column {child1_ncols-1} " + f"but got {eps1}") + + extra_key = ElementKey((1, child1_column_keys[column_index], + eps1, child1_row_keys[row_index]), + composition=True) + child1_column_keys += (extra_key,) child1 = create_DecompositionNode(child1_dec, root=self._root or self, row_keys=child1_row_keys, @@ -757,30 +782,52 @@ cdef class ThreeSumNode(SumNode): CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) if index1 == SIZE_MAX: - epsilon1 = Integer(0) + eps1 = Integer(0) else: - epsilon1 = Integer(mat1.entryValues[index1]) + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1 and eps1 != -1: + raise ValueError(f"Second child in the Mixed_Mixed Three Sum " + f"has 1 or -1 in the entry " + f"row {0} and column {0} " + f"but got {eps1}") CMR_CALL(CMRchrmatFindEntry(mat2, 0, 1, &index2)) if index2 == SIZE_MAX: - epsilon2 = Integer(0) + eps2 = Integer(0) else: - epsilon2 = Integer(mat1.entryValues[index2]) - - child2_row_keys = (ElementKey((epsilon1, child2_column_keys[0], epsilon2, child2_column_keys[1]), composition=True), ) + child2_row_keys + eps2 = Integer(mat1.entryValues[index2]) + if eps2 != 1: + raise ValueError(f"Second child in the Mixed_Mixed Three Sum " + f"has 1 in the entry " + f"row {0} and column {1} " + f"but got {eps2}") + + extra_key = ElementKey((eps1, child2_column_keys[0], + eps2, child2_column_keys[1]), + composition=True) + child2_row_keys = (extra_key,) + child2_row_keys else: # Wide_Wide child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) for i in range(child2_nrows)) CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) if index1 == SIZE_MAX: - epsilon1 = Integer(0) + eps1 = Integer(0) else: - epsilon1 = Integer(mat1.entryValues[index1]) + eps1 = Integer(mat1.entryValues[index1]) + + if eps1 != 1 and eps1 != -1: + raise ValueError(f"Second child in the Wide_Wide Three Sum " + f"has 1 or -1 in the entry " + f"row {0} and column {0} " + f"but got {eps1}") child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) for i in range(1, child2_ncols)) - child2_column_keys = (ElementKey((1, child2_column_keys[0], epsilon1, child2_row_keys[0]), composition=True),) + child2_column_keys + extra_key = ElementKey((1, child2_column_keys[0], + eps1, child2_row_keys[0]), + composition=True) + child2_column_keys = (extra_key,) + child2_column_keys child2 = create_DecompositionNode(child2_dec, root=self._root or self, row_keys=child2_row_keys, @@ -1058,9 +1105,19 @@ cdef class ElementKey: def __init__(self, keys, composition=False): """ - Return the index key. - - frozenset((1,'a'), (-1,'7')) + Create the element key for a row or column index + of :class:`DecompositionNode`. + + INPUT: + + - ``keys`` -- a row/column key or a tuple + (`\pm 1`, row/column key, `\pm 1`, row/column key). + - ``composition`` -- ``True`` or ``False`` (default). + whether the key is a composition key or not. + If ``False``, ``self._key`` is a frozenset with a row/column key. + If ``True``, ``self._key`` is a frozenset with two tuples, + where each tuple has a sign value and a row/column key. + For example, ``frozenset((1,'a'), (-1,'7'))``. """ if composition: sign1, key1, sign2, key2 = keys @@ -1083,8 +1140,12 @@ cdef class ElementKey: return False def __repr__(self): + """ + The composition key is sorted by the string of keys. + """ if self._composition: - return "".join(['+'+str(a[1]) if a[0] == 1 else '-'+str(a[1]) for a in self._key]) + sorted_key = sorted(self._key, key=lambda x: (str(x[1]), x[0])) + return "".join(['+'+str(a[1]) if a[0] == 1 else '-'+str(a[1]) for a in sorted_key]) else: return "".join([str(a) for a in self._key]) From 63272cf1612d73e7a551f1a07dab3e5ff41f1c70 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 17 Mar 2024 15:25:14 -0700 Subject: [PATCH 162/262] change _set_row/column_keys from cdef to def --- src/sage/matrix/seymour_decomposition.pxd | 2 -- src/sage/matrix/seymour_decomposition.pyx | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index df1de870bee..82335dfe0ce 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -11,8 +11,6 @@ cdef class DecompositionNode(SageObject): cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef _set_dec(self, CMR_MATROID_DEC *dec, root) - cdef _set_row_keys(self, row_keys) - cdef _set_column_keys(self, column_keys) cdef _CMRelement_to_key(self, CMR_ELEMENT element) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 25fb9316ac6..5a860ce6a33 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -43,7 +43,7 @@ cdef class DecompositionNode(SageObject): self._dec = dec self._root = root - cdef _set_row_keys(self, row_keys): + def _set_row_keys(self, row_keys): """ Set the row keys with consistency checking: if the value was previously set, it must remain the same. @@ -56,7 +56,7 @@ cdef class DecompositionNode(SageObject): f"but got {row_keys}") self._row_keys = row_keys - cdef _set_column_keys(self, column_keys): + def _set_column_keys(self, column_keys): """ Set the column keys with consistency checking: if the value was previously set, it must remain the same. From 1854a1de74cc1d98b149d0dd40129c58cf34cce4 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 17 Mar 2024 18:13:32 -0700 Subject: [PATCH 163/262] add extra parent_indices besides the parent keys --- src/sage/matrix/seymour_decomposition.pxd | 1 + src/sage/matrix/seymour_decomposition.pyx | 377 +++++++++++++--------- 2 files changed, 227 insertions(+), 151 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 82335dfe0ce..66144e8f365 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -8,6 +8,7 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC *_dec cdef object _row_keys cdef object _column_keys + cdef public object _parent_indices cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef _set_dec(self, CMR_MATROID_DEC *dec, root) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 5a860ce6a33..ac852128861 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -130,6 +130,23 @@ cdef class DecompositionNode(SageObject): """ return self._column_keys + def parent_indices(self): + r""" + """ + return self._parent_indices + + def set_default_keys(self): + row_keys = self.row_keys() + column_keys = self.column_keys() + if row_keys is None or column_keys is None: + row_keys = tuple(ElementKey(f"r{i}") for i in range(self.nrows())) + column_keys = tuple(ElementKey(f"c{i}") for i in range(self.ncols())) + elif not isinstance(row_keys[0], ElementKey): + row_keys = tuple(ElementKey(key) for key in row_keys) + column_keys = tuple(ElementKey(key) for key in column_keys) + self._row_keys = row_keys + self._column_keys = column_keys + @cached_method def morphism(self): r""" @@ -150,7 +167,9 @@ cdef class DecompositionNode(SageObject): [ 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: certificate.parent_rows_and_columns() - (None, None) + Traceback (most recent call last): + ... + ValueError: This is probably a root node. No keys or indices stored. sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) @@ -193,6 +212,15 @@ cdef class DecompositionNode(SageObject): sage: C.parent_rows_and_columns() ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) """ + if self._row_keys is None or self._column_keys is None: + raise ValueError("This is probably a root node. No keys or indices stored.") + if isinstance(self.row_keys()[0], ElementKey): + return self.ancestor_rows_and_columns() + else: + return self.parent_indices() + + @cached_method + def ancestor_rows_and_columns(self): return self.row_keys(), self.column_keys() def as_ordered_tree(self): @@ -256,9 +284,9 @@ cdef class DecompositionNode(SageObject): if self.row_keys() is None or self.column_keys() is None: raise ValueError('row_keys and column_keys are required') if CMRelementIsRow(element): - return ElementKey(self.row_keys()[CMRelementToRowIndex(element)]) + return self.row_keys()[CMRelementToRowIndex(element)] else: - return ElementKey(self.column_keys()[CMRelementToColumnIndex(element)]) + return self.column_keys()[CMRelementToColumnIndex(element)] def _create_child_node(self, index): row_keys = self.row_keys() @@ -269,28 +297,36 @@ cdef class DecompositionNode(SageObject): child_nrows = CMRmatroiddecNumRows(child_dec) child_ncols = CMRmatroiddecNumColumns(child_dec) + if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(child_nrows)): + raise ValueError(f"Child {index} does not have parents rows") + parent_rows_tuple = tuple(parent_rows[i] for i in range(child_nrows)) + + if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(child_ncols)): + raise ValueError(f"Child {index} does not have parents columns") + parent_columns_tuple = tuple(parent_columns[i] for i in range(child_ncols)) + if row_keys is not None and column_keys is not None: - child_row_keys = tuple(self._CMRelement_to_key(parent_rows[i]) - for i in range(child_nrows)) - child_column_keys = tuple(self._CMRelement_to_key(parent_columns[i]) - for i in range(child_ncols)) + child_row_keys = tuple(self._CMRelement_to_key(element) + for element in parent_rows_tuple) + child_column_keys = tuple(self._CMRelement_to_key(element) + for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, root=self._root or self, row_keys=child_row_keys, column_keys=child_column_keys) + parent_row_indices = tuple(CMRelementToRowIndex(element) + for element in parent_rows_tuple) + parent_column_indices = tuple(CMRelementToColumnIndex(element) + for element in parent_columns_tuple) + child._parent_indices = parent_row_indices, parent_column_indices else: - if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(child_nrows)): - raise ValueError(f"Child {index} does not have parents rows") - else: - parent_rows_tuple = tuple(CMRelementToRowIndex(parent_rows[i]) - for i in range(child_nrows)) - if parent_columns == NULL or all(parent_columns[i] == 0 for i in range(child_ncols)): - raise ValueError(f"Child {index} does not have parents columns") - else: - parent_columns_tuple = tuple(CMRelementToColumnIndex(parent_columns[i]) - for i in range(child_ncols)) + child_row_keys = tuple(CMRelementToRowIndex(element) + for element in parent_rows_tuple) + child_column_keys = tuple(CMRelementToColumnIndex(element) + for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, root=self._root or self, - row_keys=parent_rows_tuple, - column_keys=parent_columns_tuple) + row_keys=child_row_keys, + column_keys=child_column_keys) + child._parent_indices = child_row_keys, child_column_keys return child @cached_method @@ -623,8 +659,12 @@ cdef class ThreeSumNode(SumNode): [-1 -1 0 0 1] sage: C1.parent_rows_and_columns() ((0, 1, a, 3), (b, c, d, e, +3+e)) + sage: C1.parent_indices() + ((0, 1, 4, 3), (1, 2, 3, 4, 4)) sage: C2.parent_rows_and_columns() ((0, 2, 3, 5), (+0+d, d, 4, e, f)) + sage: C2.parent_indices() + ((0, 2, 3, 5), (3, 3, 0, 4, 5)) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), @@ -666,6 +706,25 @@ cdef class ThreeSumNode(SumNode): sage: C2.parent_rows_and_columns() ((i, 0, 3, 4, 5, 6), (+i+k, k, a, b, c, d, e, f, 1)) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Mixed_Mixed") + sage: C1, C2 = certificate._children() + sage: C1.matrix() + [ 1 0 1 1 0] + [ 0 1 1 1 0] + [ 1 0 1 0 1] + [ 0 -1 0 -1 1] + sage: C2.matrix() + [ 1 1 0 0] + [ 1 0 1 1] + [ 0 -1 1 1] + [ 1 0 1 0] + [ 0 -1 0 1] + sage: C1.parent_rows_and_columns() + ((r0, r1, r2, r3), (c0, c1, c2, c3, +r2+r3)) + sage: C2.parent_rows_and_columns() + ((+c0+c3, r2, r3, r4, r5), (c0, c3, c4, c5)) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed", ....: row_keys=range(6), @@ -690,6 +749,8 @@ cdef class ThreeSumNode(SumNode): if self.nchildren() != 2: raise ValueError(f"ThreeSumNode has exactly two children not {self.nchildren()}!") + self.set_default_keys() + cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecChildRowsToParent(self._dec, 0) cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecChildColumnsToParent(self._dec, 0) @@ -702,139 +763,144 @@ cdef class ThreeSumNode(SumNode): cdef size_t index1, index2 - row_keys = self.row_keys() - column_keys = self.column_keys() + child1_nrows = CMRmatroiddecNumRows(child1_dec) + child1_ncols = CMRmatroiddecNumColumns(child1_dec) - if row_keys is not None and column_keys is not None: - child1_nrows = CMRmatroiddecNumRows(child1_dec) - child1_ncols = CMRmatroiddecNumColumns(child1_dec) - - if self.is_concentrated_rank(): # Mixed_Mixed - child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) - for i in range(child1_nrows)) - child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) - for i in range(child1_ncols - 1)) - - row1_index = child1_nrows - 2 - CMR_CALL(CMRchrmatFindEntry(mat1, row1_index, child1_ncols-1, &index1)) - if index1 == SIZE_MAX: - eps1 = Integer(0) - else: - eps1 = Integer(mat1.entryValues[index1]) - if eps1 != 1: - raise ValueError(f"First child in the Mixed_Mixed Three Sum " - f"has 1 in the entry " - f"row {row1_index} and column {child1_ncols-1} " - f"but got {eps1}") - - row2_index = child1_nrows - 1 - CMR_CALL(CMRchrmatFindEntry(mat1, row2_index, child1_ncols-1, &index2)) - if index2 == SIZE_MAX: - eps2 = Integer(0) - else: - eps2 = Integer(mat1.entryValues[index2]) - if eps2 != 1 and eps2 != -1: - raise ValueError(f"First child in the Mixed_Mixed Three Sum " - f"has 1 or -1 in the entry " - f"row {row2_index} and column {child1_ncols-1} " - f"but got {eps2}") - - extra_key = ElementKey((eps1, child1_row_keys[row1_index], - eps2, child1_row_keys[row2_index]), - composition=True) - child1_column_keys += (extra_key,) - else: # Wide_Wide - child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) - for i in range(child1_nrows)) - child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) - for i in range(child1_ncols - 1)) - - row_index = child1_nrows - 1 - column_index = child1_ncols - 2 - CMR_CALL(CMRchrmatFindEntry(mat1, row_index, child1_ncols-1, &index1)) - if index1 == SIZE_MAX: - eps1 = Integer(0) - else: - eps1 = Integer(mat1.entryValues[index1]) - if eps1 != 1 and eps1 != -1: - raise ValueError(f"First child in the Wide_Wide Three Sum " - f"has 1 or -1 in the entry " - f"row {row_index} and column {child1_ncols-1} " - f"but got {eps1}") - - extra_key = ElementKey((1, child1_column_keys[column_index], - eps1, child1_row_keys[row_index]), - composition=True) - child1_column_keys += (extra_key,) - - child1 = create_DecompositionNode(child1_dec, root=self._root or self, - row_keys=child1_row_keys, - column_keys=child1_column_keys) - - child2_nrows = CMRmatroiddecNumRows(child2_dec) - child2_ncols = CMRmatroiddecNumColumns(child2_dec) - - if self.is_concentrated_rank(): # Mixed_Mixed - child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) - for i in range(1, child2_nrows)) - child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) - for i in range(child2_ncols)) - - CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) - if index1 == SIZE_MAX: - eps1 = Integer(0) - else: - eps1 = Integer(mat1.entryValues[index1]) - if eps1 != 1 and eps1 != -1: - raise ValueError(f"Second child in the Mixed_Mixed Three Sum " - f"has 1 or -1 in the entry " - f"row {0} and column {0} " - f"but got {eps1}") - - CMR_CALL(CMRchrmatFindEntry(mat2, 0, 1, &index2)) - if index2 == SIZE_MAX: - eps2 = Integer(0) - else: - eps2 = Integer(mat1.entryValues[index2]) - if eps2 != 1: - raise ValueError(f"Second child in the Mixed_Mixed Three Sum " - f"has 1 in the entry " - f"row {0} and column {1} " - f"but got {eps2}") - - extra_key = ElementKey((eps1, child2_column_keys[0], - eps2, child2_column_keys[1]), - composition=True) - child2_row_keys = (extra_key,) + child2_row_keys - else: # Wide_Wide - child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) - for i in range(child2_nrows)) - - CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) - if index1 == SIZE_MAX: - eps1 = Integer(0) - else: - eps1 = Integer(mat1.entryValues[index1]) - - if eps1 != 1 and eps1 != -1: - raise ValueError(f"Second child in the Wide_Wide Three Sum " - f"has 1 or -1 in the entry " - f"row {0} and column {0} " - f"but got {eps1}") - - child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) - for i in range(1, child2_ncols)) - extra_key = ElementKey((1, child2_column_keys[0], - eps1, child2_row_keys[0]), - composition=True) - child2_column_keys = (extra_key,) + child2_column_keys - - child2 = create_DecompositionNode(child2_dec, root=self._root or self, - row_keys=child2_row_keys, - column_keys=child2_column_keys) - else: - child1 = create_DecompositionNode(child1_dec, root=self._root or self) - child2 = create_DecompositionNode(child2_dec, root=self._root or self) + if self.is_concentrated_rank(): # Mixed_Mixed + child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) + for i in range(child1_nrows)) + child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) + for i in range(child1_ncols - 1)) + + row1_index = child1_nrows - 2 + CMR_CALL(CMRchrmatFindEntry(mat1, row1_index, child1_ncols-1, &index1)) + if index1 == SIZE_MAX: + eps1 = Integer(0) + else: + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1: + raise ValueError(f"First child in the Mixed_Mixed Three Sum " + f"has 1 in the entry " + f"row {row1_index} and column {child1_ncols-1} " + f"but got {eps1}") + + row2_index = child1_nrows - 1 + CMR_CALL(CMRchrmatFindEntry(mat1, row2_index, child1_ncols-1, &index2)) + if index2 == SIZE_MAX: + eps2 = Integer(0) + else: + eps2 = Integer(mat1.entryValues[index2]) + if eps2 != 1 and eps2 != -1: + raise ValueError(f"First child in the Mixed_Mixed Three Sum " + f"has 1 or -1 in the entry " + f"row {row2_index} and column {child1_ncols-1} " + f"but got {eps2}") + + extra_key = ElementKey((eps1, child1_row_keys[row1_index], + eps2, child1_row_keys[row2_index]), + composition=True) + child1_column_keys += (extra_key,) + else: # Wide_Wide + child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) + for i in range(child1_nrows)) + child1_column_keys = tuple(self._CMRelement_to_key(parent_columns1[i]) + for i in range(child1_ncols - 1)) + + row_index = child1_nrows - 1 + column_index = child1_ncols - 2 + CMR_CALL(CMRchrmatFindEntry(mat1, row_index, child1_ncols-1, &index1)) + if index1 == SIZE_MAX: + eps1 = Integer(0) + else: + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1 and eps1 != -1: + raise ValueError(f"First child in the Wide_Wide Three Sum " + f"has 1 or -1 in the entry " + f"row {row_index} and column {child1_ncols-1} " + f"but got {eps1}") + + extra_key = ElementKey((1, child1_column_keys[column_index], + eps1, child1_row_keys[row_index]), + composition=True) + child1_column_keys += (extra_key,) + + child1 = create_DecompositionNode(child1_dec, root=self._root or self, + row_keys=child1_row_keys, + column_keys=child1_column_keys) + + child2_nrows = CMRmatroiddecNumRows(child2_dec) + child2_ncols = CMRmatroiddecNumColumns(child2_dec) + + if self.is_concentrated_rank(): # Mixed_Mixed + child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) + for i in range(1, child2_nrows)) + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(child2_ncols)) + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) + if index1 == SIZE_MAX: + eps1 = Integer(0) + else: + eps1 = Integer(mat1.entryValues[index1]) + if eps1 != 1 and eps1 != -1: + raise ValueError(f"Second child in the Mixed_Mixed Three Sum " + f"has 1 or -1 in the entry " + f"row {0} and column {0} " + f"but got {eps1}") + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 1, &index2)) + if index2 == SIZE_MAX: + eps2 = Integer(0) + else: + eps2 = Integer(mat1.entryValues[index2]) + if eps2 != 1: + raise ValueError(f"Second child in the Mixed_Mixed Three Sum " + f"has 1 in the entry " + f"row {0} and column {1} " + f"but got {eps2}") + + extra_key = ElementKey((eps1, child2_column_keys[0], + eps2, child2_column_keys[1]), + composition=True) + child2_row_keys = (extra_key,) + child2_row_keys + else: # Wide_Wide + child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) + for i in range(child2_nrows)) + + CMR_CALL(CMRchrmatFindEntry(mat2, 0, 0, &index1)) + if index1 == SIZE_MAX: + eps1 = Integer(0) + else: + eps1 = Integer(mat1.entryValues[index1]) + + if eps1 != 1 and eps1 != -1: + raise ValueError(f"Second child in the Wide_Wide Three Sum " + f"has 1 or -1 in the entry " + f"row {0} and column {0} " + f"but got {eps1}") + + child2_column_keys = tuple(self._CMRelement_to_key(parent_columns2[i]) + for i in range(1, child2_ncols)) + extra_key = ElementKey((1, child2_column_keys[0], + eps1, child2_row_keys[0]), + composition=True) + child2_column_keys = (extra_key,) + child2_column_keys + + child2 = create_DecompositionNode(child2_dec, root=self._root or self, + row_keys=child2_row_keys, + column_keys=child2_column_keys) + + parent_row1_indices = tuple(CMRelementToRowIndex(parent_rows1[i]) + for i in range(child1_nrows)) + parent_column1_indices = tuple(CMRelementToColumnIndex(parent_columns1[i]) + for i in range(child1_ncols)) + child1._parent_indices = parent_row1_indices, parent_column1_indices + + parent_row2_indices = tuple(CMRelementToRowIndex(parent_rows2[i]) + for i in range(child2_nrows)) + parent_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) + for i in range(child2_ncols)) + child2._parent_indices = parent_row2_indices, parent_column2_indices return (child1, child2) def is_distributed_ranks(self): @@ -1093,6 +1159,15 @@ cdef class PivotsNode(DecompositionNode): return tuple((pivot_rows[i], pivot_columns[i]) for i in range(self.npivots())) + @cached_method + def _children(self): + r""" + """ + self.set_default_keys() + + return tuple(self._create_child_node(index) + for index in range(self.nchildren())) + cdef class SubmatrixNode(DecompositionNode): pass From fe70c27a4ca8347920e16820b36cf9c0295c7214 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 12:26:49 -0700 Subject: [PATCH 164/262] WIP SymbolicNode, DecompositionNode.one_sum --- src/sage/matrix/seymour_decomposition.pxd | 6 ++ src/sage/matrix/seymour_decomposition.pyx | 121 ++++++++++++++++++++-- 2 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 66144e8f365..e27d14fc097 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -10,10 +10,16 @@ cdef class DecompositionNode(SageObject): cdef object _column_keys cdef public object _parent_indices cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this + cdef object _child_nodes cdef _set_dec(self, CMR_MATROID_DEC *dec, root) cdef _CMRelement_to_key(self, CMR_ELEMENT element) +cdef class SymbolicNode(DecompositionNode): + + cdef object _symbol + + cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?, row_keys=?, column_keys=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ac852128861..0f003341db6 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -48,6 +48,8 @@ cdef class DecompositionNode(SageObject): Set the row keys with consistency checking: if the value was previously set, it must remain the same. """ + if row_keys is not None: + row_keys = tuple(row_keys) if self._row_keys is not None and self._row_keys != row_keys: raise ValueError(f"inconsistent row keys: should be {self._row_keys} " f"but got {row_keys}") @@ -61,6 +63,8 @@ cdef class DecompositionNode(SageObject): Set the column keys with consistency checking: if the value was previously set, it must remain the same. """ + if column_keys is not None: + column_keys = tuple(column_keys) if self._column_keys is not None and self._column_keys != column_keys: raise ValueError(f"inconsistent column keys: should be {self._column_keys} " f"but got {column_keys}") @@ -76,9 +80,13 @@ cdef class DecompositionNode(SageObject): return self._dec def nrows(self): + if self._row_keys is not None: + return len(self._row_keys) return CMRmatroiddecNumRows(self._dec) def ncols(self): + if self._column_keys is not None: + return len(self._column_keys) return CMRmatroiddecNumColumns(self._dec) def dimensions(self): @@ -329,7 +337,6 @@ cdef class DecompositionNode(SageObject): child._parent_indices = child_row_keys, child_column_keys return child - @cached_method def _children(self): r""" Return a tuple of the children. @@ -369,8 +376,11 @@ cdef class DecompositionNode(SageObject): sage: certificate._children() () """ - return tuple(self._create_child_node(index) - for index in range(self.nchildren())) + if self._child_nodes is not None: + return self._child_nodes + self._child_nodes = tuple(self._create_child_node(index) + for index in range(self.nchildren())) + return self._child_nodes def _repr_(self): nrows, ncols = self.dimensions() @@ -382,6 +392,62 @@ cdef class DecompositionNode(SageObject): def _ascii_art_(self): return self.as_ordered_tree()._ascii_art_() + def one_sum(*summands, summand_ids=None, row_keys=None, column_keys=None): + r""" + """ + result = OneSumNode() + summands = tuple(summands) + if summand_ids is not None: + summand_ids = tuple(summand_ids) + else: + summand_ids = tuple(None for summand in summands) + # TODO: Make summands DecompositionNodes if not already + # Check row_keys, column_keys of summands are disjoint. Otherwise error + summands_row_keys = [] + summands_column_keys = [] + row_key_list = [] + column_key_list = [] + key_set = set() + for summand, id in zip(summands, summand_ids): + summand_row_keys = summand.row_keys() + summand_column_keys = summand.column_keys() + if id is not None: + summand_row_keys = tuple((id, key) for key in summand_row_keys) + summand_column_keys = tuple((id, key) for key in summand_column_keys) + + old_num_keys = len(key_set) + row_key_list.extend(summand_row_keys) + column_key_list.extend(summand_column_keys) + key_set.update(summand_row_keys) + key_set.update(summand_column_keys) + if old_num_keys + len(summand_row_keys) + len(summand_column_keys) != len(key_set): + raise ValueError(f'keys must be disjoint, ' + f'got {summand_row_keys=}, {summand_column_keys=}') + summands_row_keys.append(summand_row_keys) + summands_column_keys.append(summand_column_keys) + + if row_keys is not None: + row_keys = tuple(row_keys) + if set(row_keys) != set(row_key_list) or len(row_keys) != len(row_key_list): + raise ValueError(f'inconsistent row_keys, ' + f'got {row_keys=}, should be a permutation of {row_key_list}') + else: + row_keys = tuple(row_key_list) + if column_keys is not None: + column_keys = tuple(column_keys) + if set(column_keys) != set(column_key_list) or len(column_keys) != len(column_key_list): + raise ValueError(f'inconsistent column_keys, ' + f'got {column_keys=}, should be a permutation of {column_key_list}') + else: + column_keys = tuple(column_key_list) + + result._child_nodes = summands + result._child_row_keys = tuple(summands_row_keys) + result._child_column_keys = tuple(summands_column_keys) + result._row_keys = row_keys + result._column_keys = column_keys + return result + cdef class ThreeConnectedIrregularNode(DecompositionNode): @@ -394,7 +460,7 @@ cdef class UnknownNode(DecompositionNode): cdef class SumNode(DecompositionNode): r""" - Base class for 1-sum, 2-sum, and 3-sum nodes in Seympur's decomposition + Base class for 1-sum, 2-sum, and 3-sum nodes in Seymour's decomposition """ def _repr_(self): @@ -628,7 +694,6 @@ cdef class TwoSumNode(SumNode): cdef class ThreeSumNode(SumNode): - @cached_method def _children(self): r""" TESTS: @@ -746,6 +811,9 @@ cdef class ThreeSumNode(SumNode): sage: C2.parent_rows_and_columns() ((+a+d, 2, 3, 4, 5), (a, d, e, f)) """ + if self._child_nodes is not None: + return self._child_nodes + if self.nchildren() != 2: raise ValueError(f"ThreeSumNode has exactly two children not {self.nchildren()}!") @@ -901,7 +969,9 @@ cdef class ThreeSumNode(SumNode): parent_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) for i in range(child2_ncols)) child2._parent_indices = parent_row2_indices, parent_column2_indices - return (child1, child2) + + self._child_nodes = (child1, child2) + return self._child_nodes def is_distributed_ranks(self): r""" @@ -1159,20 +1229,53 @@ cdef class PivotsNode(DecompositionNode): return tuple((pivot_rows[i], pivot_columns[i]) for i in range(self.npivots())) - @cached_method def _children(self): r""" """ + if self._child_nodes is not None: + return self._child_nodes + self.set_default_keys() - return tuple(self._create_child_node(index) - for index in range(self.nchildren())) + self._child_nodes = tuple(self._create_child_node(index) + for index in range(self.nchildren())) + return self._child_nodes cdef class SubmatrixNode(DecompositionNode): pass +cdef class SymbolicNode(DecompositionNode): + + def __init__(self, symbol, *, row_keys=None, column_keys=None): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import SymbolicNode + sage: X = SymbolicNode('X', row_keys='abc', column_keys=range(6)); X + sage: XX = X.one_sum(X) # error - not disjoint + sage: XX = X.one_sum(X, summands_ids=(0, 1)) + sage: XX = X.one_sum(X, summands_ids=(None, 'other')) + sage: T = XX.as_ordered_tree(); T + sage: unicode_art(T) + """ + self._symbol = symbol + self._set_row_keys(row_keys) + self._set_column_keys(column_keys) + + def _repr_(self): + nrows, ncols = self.dimensions() + symbol = self.symbol() + return f'{self.__class__.__name__} {symbol} ({nrows}×{ncols})' + + def matrix(self): + raise ValueError('symbolic nodes are not backed by CMR matrices') + + def symbol(self): + return self._symbol + + cdef class ElementKey: cdef frozenset _key From cd2b7794f324893c52921823a84efe2bebd25313 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 13:22:46 -0700 Subject: [PATCH 165/262] WIP SymbolicNode, DecompositionNode.one_sum - it builds --- src/sage/matrix/seymour_decomposition.pxd | 2 ++ src/sage/matrix/seymour_decomposition.pyx | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index e27d14fc097..f7a491908f6 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -11,6 +11,8 @@ cdef class DecompositionNode(SageObject): cdef public object _parent_indices cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef object _child_nodes + cdef object _child_row_keys + cdef object _child_column_keys cdef _set_dec(self, CMR_MATROID_DEC *dec, root) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 0f003341db6..52bbf74ff79 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -392,9 +392,15 @@ cdef class DecompositionNode(SageObject): def _ascii_art_(self): return self.as_ordered_tree()._ascii_art_() - def one_sum(*summands, summand_ids=None, row_keys=None, column_keys=None): + def one_sum(*summands, **kwds): r""" """ + summand_ids = kwds.pop('summand_ids', None) + row_keys = kwds.pop('row_keys', None) + column_keys = kwds.pop('column_keys', None) + if kwds: + raise ValueError(f'unknown keywords: {sorted(kwds)}') + result = OneSumNode() summands = tuple(summands) if summand_ids is not None: From b63b00f3b47ac46faa5402da8f0193a698419cb9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 14:01:33 -0700 Subject: [PATCH 166/262] Make _set_{row,column}_keys cdef --- src/sage/matrix/seymour_decomposition.pxd | 2 ++ src/sage/matrix/seymour_decomposition.pyx | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index f7a491908f6..99ca74ed39b 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -15,6 +15,8 @@ cdef class DecompositionNode(SageObject): cdef object _child_column_keys cdef _set_dec(self, CMR_MATROID_DEC *dec, root) + cdef _set_row_keys(self, row_keys) + cdef _set_column_keys(self, column_keys) cdef _CMRelement_to_key(self, CMR_ELEMENT element) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 52bbf74ff79..19be266b633 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -43,7 +43,7 @@ cdef class DecompositionNode(SageObject): self._dec = dec self._root = root - def _set_row_keys(self, row_keys): + cdef _set_row_keys(self, row_keys): """ Set the row keys with consistency checking: if the value was previously set, it must remain the same. @@ -53,12 +53,12 @@ cdef class DecompositionNode(SageObject): if self._row_keys is not None and self._row_keys != row_keys: raise ValueError(f"inconsistent row keys: should be {self._row_keys} " f"but got {row_keys}") - if row_keys is not None and self.nrows() != len(row_keys): + if row_keys is not None and self._dec != NULL and self.nrows() != len(row_keys): raise ValueError(f"inconsistent row keys: should be of cardinality {self.nrows()} " f"but got {row_keys}") self._row_keys = row_keys - def _set_column_keys(self, column_keys): + cdef _set_column_keys(self, column_keys): """ Set the column keys with consistency checking: if the value was previously set, it must remain the same. @@ -68,7 +68,7 @@ cdef class DecompositionNode(SageObject): if self._column_keys is not None and self._column_keys != column_keys: raise ValueError(f"inconsistent column keys: should be {self._column_keys} " f"but got {column_keys}") - if column_keys is not None and self.ncols() != len(column_keys): + if column_keys is not None and self._dec != NULL and self.ncols() != len(column_keys): raise ValueError(f"inconsistent column keys: should be of cardinality {self.ncols()} " f"but got {column_keys}") self._column_keys = column_keys @@ -82,12 +82,16 @@ cdef class DecompositionNode(SageObject): def nrows(self): if self._row_keys is not None: return len(self._row_keys) - return CMRmatroiddecNumRows(self._dec) + if self._dec != NULL: + return CMRmatroiddecNumRows(self._dec) + raise RuntimeError('nrows undefined') def ncols(self): if self._column_keys is not None: return len(self._column_keys) - return CMRmatroiddecNumColumns(self._dec) + if self._dec != NULL: + return CMRmatroiddecNumColumns(self._dec) + raise RuntimeError('ncols undefined') def dimensions(self): return self.nrows(), self.ncols() From 4eae56f5c7592bcd7b9736c063ea290abbfefa63 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 16:38:53 -0700 Subject: [PATCH 167/262] src/sage/matrix/matrix_cmr_sparse.pyx: Handle row/column keys for is_graphic etc. --- src/sage/matrix/matrix_cmr_sparse.pyx | 65 +++++++++++++++++++++------ 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index a340f115189..9c57e9e41e6 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1267,7 +1267,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): True sage: result, certificate = M.is_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate - sage: graph.vertices(sort=True) # what is the meaning of the numbers? + sage: graph.vertices(sort=True) # the numbers have no meaning [1, 2, 7, 12] sage: graph.edges(sort=True, labels=False) [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] @@ -1276,6 +1276,16 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: coforest_edges # indexed by cols of M ((2, 7), (1, 12)) + With keys:: + + sage: result, certificate = M.is_graphic(certificate=True, + ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) + sage: graph, forest_edges, coforest_edges = certificate + sage: forest_edges + {'a': (1, 2), 'b': (7, 1), 'c': (12, 7)} + sage: coforest_edges + {'v': (2, 7), 'w': (1, 12)} + TESTS:: sage: M.is_graphic(time_limit=0.0) @@ -1306,10 +1316,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_graph = _sage_graph(graph) - sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) - for row in range(self.nrows())) - sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) - for column in range(self.ncols())) + if row_keys is None: + sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) + for row in range(self.nrows())) + else: + sage_forest_edges = {row_key: _sage_edge(graph, forest_edges[row]) + for row, row_key in enumerate(row_keys)} + if column_keys is None: + sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) + for column in range(self.ncols())) + else: + sage_coforest_edges = {column_key: _sage_edge(graph, coforest_edges[column]) + for column, column_key in enumerate(column_keys)} return True, (sage_graph, sage_forest_edges, sage_coforest_edges) return False, NotImplemented # submatrix TBD @@ -1355,10 +1373,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_graph = _sage_graph(graph) - sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) - for row in range(self.nrows())) - sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) - for column in range(self.ncols())) + if row_keys is None: + sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) + for row in range(self.nrows())) + else: + sage_forest_edges = {row_key: _sage_edge(graph, forest_edges[row]) + for row, row_key in enumerate(row_keys)} + if column_keys is None: + sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) + for column in range(self.ncols())) + else: + sage_coforest_edges = {column_key: _sage_edge(graph, coforest_edges[column]) + for column, column_key in enumerate(column_keys)} return True, (sage_graph, sage_forest_edges, sage_coforest_edges) return False, NotImplemented # submatrix TBD @@ -1422,10 +1448,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_digraph = _sage_digraph(digraph, arcs_reversed) - sage_forest_arcs = tuple(_sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) - for row in range(self.nrows())) - sage_coforest_arcs = tuple(_sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) - for column in range(self.ncols())) + if row_keys is None: + sage_forest_arcs = tuple(_sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) + for row in range(self.nrows())) + else: + sage_forest_arcs = {row_key: _sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) + for row, row_key in enumerate(row_keys)} + if column_keys is None: + sage_coforest_arcs = tuple(_sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) + for column in range(self.ncols())) + else: + sage_coforest_arcs = {column_key: _sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) + for column, column_key in enumerate(column_keys)} return True, (sage_digraph, sage_forest_arcs, sage_coforest_arcs) return False, NotImplemented # submatrix TBD @@ -1730,6 +1764,11 @@ cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e): cdef _sage_graph(CMR_GRAPH *graph): + # + + # The indices of the vertices have no meaning. + # TODO: Can we label them canonically based on the edges? + # Until we have a proper CMR Graph backend, we just create a Sage graph with whatever backend from sage.graphs.graph import Graph From 591962f7965b91c358a03ca3fb05882cba6f551c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 16:43:54 -0700 Subject: [PATCH 168/262] src/sage/matrix/seymour_decomposition.pyx: Add prototype for methods as_node_with_... --- src/sage/matrix/seymour_decomposition.pyx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 19be266b633..7d9034a878d 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -458,6 +458,26 @@ cdef class DecompositionNode(SageObject): result._column_keys = column_keys return result + def as_node_with_graphicness(self): + r""" + + """ + + cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) + if graphicness: + return self, graphicness == +1 + + # compute it... wait for CMR functions + raise NotImplementedError + + def as_node_with_graph(self): + r""" + OUTPUT: + + a pair (DecompositionNode, Graph|None) + """ + raise NotImplementedError + cdef class ThreeConnectedIrregularNode(DecompositionNode): @@ -1292,7 +1312,7 @@ cdef class ElementKey: cdef bint _composition def __init__(self, keys, composition=False): - """ + r""" Create the element key for a row or column index of :class:`DecompositionNode`. From ff90524c2a2c4e3e99696dffadbab76886c8beaf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 17:01:35 -0700 Subject: [PATCH 169/262] Fixes --- src/sage/matrix/seymour_decomposition.pyx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 7d9034a878d..d615767863c 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -286,8 +286,10 @@ cdef class DecompositionNode(SageObject): def nchildren(self): r""" - Returns the number of children of the node. + Return the number of children of the node. """ + if self._dec == NULL: + return 0 return CMRmatroiddecNumChildren(self._dec) cdef _CMRelement_to_key(self, CMR_ELEMENT element): @@ -1284,11 +1286,21 @@ cdef class SymbolicNode(DecompositionNode): sage: from sage.matrix.seymour_decomposition import SymbolicNode sage: X = SymbolicNode('X', row_keys='abc', column_keys=range(6)); X - sage: XX = X.one_sum(X) # error - not disjoint - sage: XX = X.one_sum(X, summands_ids=(0, 1)) - sage: XX = X.one_sum(X, summands_ids=(None, 'other')) + SymbolicNode X (3×6) + sage: XX = X.one_sum(X) + Traceback (most recent call last): + ... + ValueError: keys must be disjoint... + sage: XX = X.one_sum(X, summand_ids=(0, 1)); XX + OneSumNode (6×12) with 2 children + sage: XX.row_keys() + ((0, 'a'), (0, 'b'), (0, 'c'), (1, 'a'), (1, 'b'), (1, 'c')) sage: T = XX.as_ordered_tree(); T + OneSumNode (6×12) with 2 children[SymbolicNode X (3×6)[], SymbolicNode X (3×6)[]] sage: unicode_art(T) + ╭────────────────OneSumNode (6×12) with 2 children + │ │ + SymbolicNode X (3×6) SymbolicNode X (3×6) """ self._symbol = symbol self._set_row_keys(row_keys) From 3f80e5b359df5c05194fa1ac4eb46ac33edcfe9c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 17:04:03 -0700 Subject: [PATCH 170/262] Another symbolic example --- src/sage/matrix/seymour_decomposition.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d615767863c..b67e173d458 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1301,6 +1301,10 @@ cdef class SymbolicNode(DecompositionNode): ╭────────────────OneSumNode (6×12) with 2 children │ │ SymbolicNode X (3×6) SymbolicNode X (3×6) + sage: Y = SymbolicNode('Y', row_keys='de', column_keys='fg'); Y + SymbolicNode Y (2×2) + sage: XY = X.one_sum(Y); XY + OneSumNode (5×8) with 2 children """ self._symbol = symbol self._set_row_keys(row_keys) From 83f8bb0dc7a36b6c8e24b4e7f9b1cb6a2a59ba48 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 17:37:44 -0700 Subject: [PATCH 171/262] Get rid of roots --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 +++--- src/sage/matrix/seymour_decomposition.pxd | 5 ++-- src/sage/matrix/seymour_decomposition.pyx | 31 ++++++++++------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 9c57e9e41e6..9bf143ab66b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1605,9 +1605,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result if result: - return True, create_DecompositionNode(dec, None, row_keys, column_keys) + return True, create_DecompositionNode(dec, row_keys, column_keys) - return False, (create_DecompositionNode(dec, None, row_keys, column_keys), + return False, (create_DecompositionNode(dec, row_keys, column_keys), NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, @@ -1710,7 +1710,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result if result: - return True, create_DecompositionNode(dec, None, row_keys, column_keys) + return True, create_DecompositionNode(dec, row_keys, column_keys) if submat == NULL: submat_tuple = None @@ -1718,7 +1718,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), tuple(submat.columns[i] for i in range(submat.numColumns))) - return False, (create_DecompositionNode(dec, None, row_keys, column_keys), + return False, (create_DecompositionNode(dec, row_keys, column_keys), submat_tuple) def is_complement_totally_unimodular(self, *, time_limit=60.0, certificate=False, diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 99ca74ed39b..714726ae5cd 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -9,12 +9,11 @@ cdef class DecompositionNode(SageObject): cdef object _row_keys cdef object _column_keys cdef public object _parent_indices - cdef DecompositionNode _root # my CMR_MATROID_DEC is owned by this cdef object _child_nodes cdef object _child_row_keys cdef object _child_column_keys - cdef _set_dec(self, CMR_MATROID_DEC *dec, root) + cdef _set_dec(self, CMR_MATROID_DEC *dec) cdef _set_row_keys(self, row_keys) cdef _set_column_keys(self, column_keys) @@ -26,4 +25,4 @@ cdef class SymbolicNode(DecompositionNode): cdef object _symbol -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=?, row_keys=?, column_keys=?) +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=?, column_keys=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b67e173d458..d380724b3f5 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -35,13 +35,13 @@ cdef class DecompositionNode(SageObject): def __cinit__(self): self._dec = NULL - cdef _set_dec(self, CMR_MATROID_DEC *dec, root): - if self._root is None or self._root is self: - if self._dec != NULL: - # We own it, so we have to free it. - CMR_CALL(CMRmatroiddecRelease(cmr, &self._dec)) + cdef _set_dec(self, CMR_MATROID_DEC *dec): + if self._dec != NULL: + # We own it, so we have to free it. + CMR_CALL(CMRmatroiddecRelease(cmr, &self._dec)) + if dec != NULL: + CMR_CALL(CMRmatroiddecCapture(cmr, dec)) self._dec = dec - self._root = root cdef _set_row_keys(self, row_keys): """ @@ -74,7 +74,7 @@ cdef class DecompositionNode(SageObject): self._column_keys = column_keys def __dealloc__(self): - self._set_dec(NULL, None) + self._set_dec(NULL) def __hash__(self): return self._dec @@ -127,7 +127,7 @@ cdef class DecompositionNode(SageObject): ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms) result._mat = mat - result._root = self._root or self + result._root = self # Matrix is owned by us return result def row_keys(self): @@ -324,7 +324,7 @@ cdef class DecompositionNode(SageObject): for element in parent_rows_tuple) child_column_keys = tuple(self._CMRelement_to_key(element) for element in parent_columns_tuple) - child = create_DecompositionNode(child_dec, root=self._root or self, + child = create_DecompositionNode(child_dec, row_keys=child_row_keys, column_keys=child_column_keys) parent_row_indices = tuple(CMRelementToRowIndex(element) @@ -337,7 +337,7 @@ cdef class DecompositionNode(SageObject): for element in parent_rows_tuple) child_column_keys = tuple(CMRelementToColumnIndex(element) for element in parent_columns_tuple) - child = create_DecompositionNode(child_dec, root=self._root or self, + child = create_DecompositionNode(child_dec, row_keys=child_row_keys, column_keys=child_column_keys) child._parent_indices = child_row_keys, child_column_keys @@ -924,7 +924,7 @@ cdef class ThreeSumNode(SumNode): composition=True) child1_column_keys += (extra_key,) - child1 = create_DecompositionNode(child1_dec, root=self._root or self, + child1 = create_DecompositionNode(child1_dec, row_keys=child1_row_keys, column_keys=child1_column_keys) @@ -986,7 +986,7 @@ cdef class ThreeSumNode(SumNode): composition=True) child2_column_keys = (extra_key,) + child2_column_keys - child2 = create_DecompositionNode(child2_dec, root=self._root or self, + child2 = create_DecompositionNode(child2_dec, row_keys=child2_row_keys, column_keys=child2_column_keys) @@ -1404,21 +1404,18 @@ cdef _class(CMR_MATROID_DEC *dec): assert NotImplementedError -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, root=None, row_keys=None, column_keys=None): +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. INPUT: - ``dec`` -- a ``CMR_MATROID_DEC`` - - ``root`` -- a :class:`DecompositionNode` or ``None``. - If ``None``, ``dec`` will be owned by the returned instance. - If non-``None``, ``dec`` is owned by that instance. """ if dec == NULL: return None cdef DecompositionNode result = _class(dec)() - result._set_dec(dec, root) + result._set_dec(dec) if row_keys is not None: result._set_row_keys(row_keys) if column_keys is not None: From 4f26d1d9f3f504b8d247429a5fe0a87cffca5b29 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 18:27:48 -0700 Subject: [PATCH 172/262] src/sage/categories/finite_dimensional_modules_with_basis.py: Update doctests for graphs with labels --- .../finite_dimensional_modules_with_basis.py | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 1909e8bf61c..262c4886d5d 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -1085,9 +1085,9 @@ def is_graphic(self): sage: graph.edges(sort=True, labels=False) [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] sage: forest_edges # indexed by rows of M - ((1, 2), (7, 1), (12, 7)) + {'u': (1, 2), 'v': (7, 1), 'w': (12, 7)} sage: coforest_edges # indexed by cols of M - ((2, 7), (1, 12)) + {'a': (2, 7), 'b': (1, 12)} """ try: matrix = self._matrix_cmr() @@ -1150,25 +1150,12 @@ def is_network(self): sage: result, certificate = M.is_network(certificate=True) sage: result, certificate (True, - (Digraph on 7 vertices, - ((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)), - ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) + (Digraph on 7 vertices, + {0: (9, 8), 1: (3, 8), 2: (3, 4), 3: (5, 4), 4: (4, 6), 5: (0, 6)}, + {'a': (3, 9), 'b': (5, 3), 'c': (4, 0), 'd': (0, 8), + 'e': (9, 0), 'f': (4, 9), 'g': (5, 6)})) sage: digraph, forest_arcs, coforest_arcs = certificate - sage: list(digraph.edges(sort=True)) - [(0, 6, None), - (0, 8, None), - (3, 4, None), - (3, 8, None), - (3, 9, None), - (4, 0, None), - (4, 6, None), - (4, 9, None), - (5, 3, None), - (5, 4, None), - (5, 6, None), - (9, 0, None), - (9, 8, None)] - sage: digraph.plot(edge_colors={'red': forest_arcs}) # needs sage.plot + sage: digraph.plot(edge_colors={'red': forest_arcs.values()}) # needs sage.plot Graphics object consisting of 21 graphics primitives """ try: From a29aed2673db0c6a7e8a2c36dc24c8595866973b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 19:23:14 -0700 Subject: [PATCH 173/262] src/sage/matrix/seymour_decomposition.pyx: Cache matrix explicitly --- src/sage/matrix/seymour_decomposition.pxd | 2 +- src/sage/matrix/seymour_decomposition.pyx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 714726ae5cd..5b6c0069178 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -4,7 +4,7 @@ from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): - + cdef object _matrix cdef CMR_MATROID_DEC *_dec cdef object _row_keys cdef object _column_keys diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d380724b3f5..ea778dd648c 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -96,7 +96,6 @@ cdef class DecompositionNode(SageObject): def dimensions(self): return self.nrows(), self.ncols() - @cached_method def matrix(self): r""" Return a :class:`Matrix`. @@ -120,6 +119,8 @@ cdef class DecompositionNode(SageObject): [-1 1] [ 0 1] """ + if self._matrix is not None: + return self._matrix cdef Matrix_cmr_chr_sparse result cdef CMR_CHRMAT *mat = CMRmatroiddecGetMatrix(self._dec) if mat == NULL: @@ -128,6 +129,7 @@ cdef class DecompositionNode(SageObject): result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms) result._mat = mat result._root = self # Matrix is owned by us + self._matrix = result return result def row_keys(self): From 29f2469ffc0ed66ca46f53f024271384a8d94f6f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 21:36:37 -0700 Subject: [PATCH 174/262] Set up UnknownNode from a matrix/morphism, replace as_node_with_graphicness by is_graphic --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- src/sage/matrix/seymour_decomposition.pyx | 121 +++++++++++++++++++--- 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 9bf143ab66b..c6683e25887 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1263,7 +1263,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 1 0] [-1 1] [ 0 -1] - sage: M.is_graphic() # ?? should it not check 0/1-ness? + sage: M.is_graphic() True sage: result, certificate = M.is_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ea778dd648c..3ffdc20e5ee 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -22,9 +22,9 @@ from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject +from .constructor import Matrix from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edge, _sage_graph from .matrix_space import MatrixSpace -from .args cimport MatrixArgs cdef class DecompositionNode(SageObject): @@ -84,6 +84,8 @@ cdef class DecompositionNode(SageObject): return len(self._row_keys) if self._dec != NULL: return CMRmatroiddecNumRows(self._dec) + if self._matrix is not None: + return self._matrix.nrows() raise RuntimeError('nrows undefined') def ncols(self): @@ -91,6 +93,8 @@ cdef class DecompositionNode(SageObject): return len(self._column_keys) if self._dec != NULL: return CMRmatroiddecNumColumns(self._dec) + if self._matrix is not None: + return self._matrix.ncols() raise RuntimeError('ncols undefined') def dimensions(self): @@ -166,7 +170,9 @@ cdef class DecompositionNode(SageObject): r""" """ - return MatrixArgs(self.matrix(), MatrixSpace(ZZ, self.row_keys(), self.column_keys())).element() + return Matrix(self.matrix(), + row_keys=self.row_keys(), + column_keys=self.column_keys()) @cached_method def parent_rows_and_columns(self): @@ -462,34 +468,119 @@ cdef class DecompositionNode(SageObject): result._column_keys = column_keys return result - def as_node_with_graphicness(self): + def is_graphic(self, *, decomposition=False, **kwds): r""" """ - + certificate = kwds.get('certificate', False) cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) if graphicness: - return self, graphicness == +1 - + result = graphicness == +1 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result # compute it... wait for CMR functions raise NotImplementedError - def as_node_with_graph(self): - r""" - OUTPUT: - - a pair (DecompositionNode, Graph|None) - """ - raise NotImplementedError - cdef class ThreeConnectedIrregularNode(DecompositionNode): pass + cdef class UnknownNode(DecompositionNode): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + sage: node.matrix() + [1 1] + [0 1] + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]])); node + UnknownNode (2×3) + sage: node.matrix() + [1 0 1] + [0 1 1] + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node.matrix() + [1 0 1] + [0 1 1] + sage: node.morphism()._unicode_art_matrix() + 0 1 2 + a⎛1 0 1⎞ + b⎝0 1 1⎠ + + From a module morphism:: + + sage: phi = matrix(ZZ, [[1, 0, 1], [0, 1, 1]], + ....: row_keys='ab', column_keys=range(3)); phi + Generic morphism: + From: Free module generated by {0, 1, 2} over Integer Ring + To: Free module generated by {'a', 'b'} over Integer Ring + sage: node = UnknownNode(phi); node + UnknownNode (2×3) + sage: node.matrix() + [1 0 1] + [0 1 1] + """ - pass + def __init__(self, matrix=None, row_keys=None, column_keys=None): + if matrix is None: + self._matrix = None + elif isinstance(matrix, Matrix_cmr_chr_sparse): + self._matrix = matrix + else: + try: + self._matrix = matrix._matrix_cmr() + except (AttributeError, ImportError, TypeError): + matrix = Matrix(matrix) + self._matrix = Matrix_cmr_chr_sparse(matrix.parent(), matrix) + else: + if row_keys is None: + row_keys = matrix.codomain().basis().keys() + if column_keys is None: + column_keys = matrix.domain().basis().keys() + self._row_keys = row_keys + self._column_keys = column_keys + + def is_graphic(self, *, decomposition=False, certificate=False, **kwds): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 0], [-1, 1], [0, -1]]); node + UnknownNode (3×2) + sage: node.matrix() + [ 1 0] + [-1 1] + [ 0 -1] + sage: node.is_graphic() + True + sage: result, certificate = node.is_graphic(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: forest_edges + ((1, 2), (7, 1), (12, 7)) + """ + if not decomposition and not certificate: + return self.matrix().is_graphic(**kwds) + result, certificate = self.matrix().is_graphic(certificate=True, + row_keys=self.row_keys(), column_keys=self.column_keys(), **kwds) + result = [result] + if decomposition: + raise NotImplementedError + if certificate: + result.append(certificate) + return result cdef class SumNode(DecompositionNode): From 468218f11cf81b80100cb58b7b65b7459ff6388c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 21:56:50 -0700 Subject: [PATCH 175/262] src/sage/matrix/seymour_decomposition.pyx: Explicit caching in BaseGraphicNode --- src/sage/matrix/seymour_decomposition.pxd | 6 ++++++ src/sage/matrix/seymour_decomposition.pyx | 21 ++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 5b6c0069178..09abd6eb443 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -20,6 +20,12 @@ cdef class DecompositionNode(SageObject): cdef _CMRelement_to_key(self, CMR_ELEMENT element) +cdef class BaseGraphicNode(DecompositionNode): + cdef object _graph + cdef object _forest_edges + cdef object _coforest_edges + + cdef class SymbolicNode(DecompositionNode): cdef object _symbol diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 3ffdc20e5ee..e7ac86127de 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1174,7 +1174,6 @@ cdef class ThreeSumNode(SumNode): cdef class BaseGraphicNode(DecompositionNode): - @cached_method def graph(self): r""" EXAMPLES:: @@ -1195,9 +1194,11 @@ cdef class BaseGraphicNode(DecompositionNode): sage: G.edges(sort=True) [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] """ - return _sage_graph(CMRmatroiddecGraph(self._dec)) + if self._graph is not None: + return self._graph + self._graph = _sage_graph(CMRmatroiddecGraph(self._dec)) + return self._graph - @cached_method def forest_edges(self): r""" EXAMPLES:: @@ -1214,17 +1215,22 @@ cdef class BaseGraphicNode(DecompositionNode): sage: certificate.forest_edges() ((1, 2), (7, 1), (12, 7)) """ + if self._forest_edges is not None: + return self._forest_edges cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) - return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + self._forest_edges = tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + return self._forest_edges - @cached_method def coforest_edges(self): + if self._coforest_edges is not None: + return self._coforest_edges cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) - return tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + self._coforest_edges = tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + return self._coforest_edges cdef class GraphicNode(BaseGraphicNode): @@ -1389,7 +1395,8 @@ cdef class SymbolicNode(DecompositionNode): sage: XX.row_keys() ((0, 'a'), (0, 'b'), (0, 'c'), (1, 'a'), (1, 'b'), (1, 'c')) sage: T = XX.as_ordered_tree(); T - OneSumNode (6×12) with 2 children[SymbolicNode X (3×6)[], SymbolicNode X (3×6)[]] + OneSumNode (6×12) with 2 children[SymbolicNode X (3×6)[], + SymbolicNode X (3×6)[]] sage: unicode_art(T) ╭────────────────OneSumNode (6×12) with 2 children │ │ From b0038fbdeb83c23e7c26f37d6ecab99cc59b32ff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 22:21:31 -0700 Subject: [PATCH 176/262] Refactor with new helper function _sage_edges --- src/sage/matrix/matrix_cmr_sparse.pxd | 1 + src/sage/matrix/matrix_cmr_sparse.pyx | 36 ++++++++--------------- src/sage/matrix/seymour_decomposition.pyx | 6 ++-- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index b2664aeefd1..ec3d0b4a9bf 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -23,6 +23,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?) cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) +cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys) cdef _sage_graph(CMR_GRAPH *graph) cdef _sage_arc(CMR_GRAPH *graph, CMR_GRAPH_EDGE e, bint reversed) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index c6683e25887..e27bac5796b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1316,18 +1316,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_graph = _sage_graph(graph) - if row_keys is None: - sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) - for row in range(self.nrows())) - else: - sage_forest_edges = {row_key: _sage_edge(graph, forest_edges[row]) - for row, row_key in enumerate(row_keys)} - if column_keys is None: - sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) - for column in range(self.ncols())) - else: - sage_coforest_edges = {column_key: _sage_edge(graph, coforest_edges[column]) - for column, column_key in enumerate(column_keys)} + sage_forest_edges = _sage_edges(graph, forest_edges, self.nrows(), row_keys) + sage_coforest_edges = _sage_edges(graph, coforest_edges, self.ncols(), column_keys) return True, (sage_graph, sage_forest_edges, sage_coforest_edges) return False, NotImplemented # submatrix TBD @@ -1373,18 +1363,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_graph = _sage_graph(graph) - if row_keys is None: - sage_forest_edges = tuple(_sage_edge(graph, forest_edges[row]) - for row in range(self.nrows())) - else: - sage_forest_edges = {row_key: _sage_edge(graph, forest_edges[row]) - for row, row_key in enumerate(row_keys)} - if column_keys is None: - sage_coforest_edges = tuple(_sage_edge(graph, coforest_edges[column]) - for column in range(self.ncols())) - else: - sage_coforest_edges = {column_key: _sage_edge(graph, coforest_edges[column]) - for column, column_key in enumerate(column_keys)} + sage_forest_edges = _sage_edges(graph, forest_edges, self.nrows(), row_keys) + sage_coforest_edges = _sage_edges(graph, coforest_edges, self.ncols(), column_keys) return True, (sage_graph, sage_forest_edges, sage_coforest_edges) return False, NotImplemented # submatrix TBD @@ -1763,6 +1743,14 @@ cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e): return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) +cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys): + if keys is None: + return tuple(_sage_edge(graph, edges[i]) + for i in range(n)) + return {key: _sage_edge(graph, edges[i]) + for i, key in enumerate(keys)} + + cdef _sage_graph(CMR_GRAPH *graph): # diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index e7ac86127de..7e186aa6ff7 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -23,7 +23,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject from .constructor import Matrix -from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edge, _sage_graph +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph from .matrix_space import MatrixSpace @@ -1220,7 +1220,7 @@ cdef class BaseGraphicNode(DecompositionNode): cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) - self._forest_edges = tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + self._forest_edges = _sage_edges(graph, edges, num_edges, None) return self._forest_edges def coforest_edges(self): @@ -1229,7 +1229,7 @@ cdef class BaseGraphicNode(DecompositionNode): cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) - self._coforest_edges = tuple(_sage_edge(graph, edges[i]) for i in range(num_edges)) + self._coforest_edges = _sage_edges(graph, edges, num_edges, None) return self._coforest_edges From 8af3aa20e63edfc66b6553b8f13c48a9d2524e29 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 22:42:16 -0700 Subject: [PATCH 177/262] Refactor with new helper function _sage_arcs --- src/sage/matrix/matrix_cmr_sparse.pxd | 1 + src/sage/matrix/matrix_cmr_sparse.pyx | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index ec3d0b4a9bf..14bc2909edb 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -27,4 +27,5 @@ cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys) cdef _sage_graph(CMR_GRAPH *graph) cdef _sage_arc(CMR_GRAPH *graph, CMR_GRAPH_EDGE e, bint reversed) +cdef _sage_arcs(CMR_GRAPH *graph, CMR_GRAPH_EDGE *arcs, bool *arcs_reversed, n, keys) cdef _sage_digraph(CMR_GRAPH *graph, bool *arcs_reversed) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e27bac5796b..5b69b39de5b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1428,18 +1428,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if result: sage_digraph = _sage_digraph(digraph, arcs_reversed) - if row_keys is None: - sage_forest_arcs = tuple(_sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) - for row in range(self.nrows())) - else: - sage_forest_arcs = {row_key: _sage_arc(digraph, forest_arcs[row], arcs_reversed[forest_arcs[row]]) - for row, row_key in enumerate(row_keys)} - if column_keys is None: - sage_coforest_arcs = tuple(_sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) - for column in range(self.ncols())) - else: - sage_coforest_arcs = {column_key: _sage_arc(digraph, coforest_arcs[column], arcs_reversed[coforest_arcs[column]]) - for column, column_key in enumerate(column_keys)} + sage_forest_arcs = _sage_arcs(digraph, forest_arcs, arcs_reversed, self.nrows(), row_keys) + sage_coforest_arcs = _sage_arcs(digraph, coforest_arcs, arcs_reversed, self.ncols(), column_keys) return True, (sage_digraph, sage_forest_arcs, sage_coforest_arcs) return False, NotImplemented # submatrix TBD @@ -1782,6 +1772,14 @@ cdef _sage_arc(CMR_GRAPH *graph, CMR_GRAPH_EDGE e, bint reversed): return Integer(CMRgraphEdgeU(graph, e)), Integer(CMRgraphEdgeV(graph, e)) +cdef _sage_arcs(CMR_GRAPH *graph, CMR_GRAPH_EDGE *arcs, bool *arcs_reversed, n, keys): + if keys is None: + return tuple(_sage_arc(graph, arcs[i], arcs_reversed[arcs[i]]) + for i in range(n)) + return {key: _sage_arc(graph, arcs[i], arcs_reversed[arcs[i]]) + for i, key in enumerate(keys)} + + cdef _sage_digraph(CMR_GRAPH *graph, bool *arcs_reversed): from sage.graphs.digraph import DiGraph From 111265e1c3ee4f62c391a12bb6700ebdc09d5917 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 22:55:44 -0700 Subject: [PATCH 178/262] src/sage/matrix/seymour_decomposition.pyx: Fix _class for planar --- src/sage/matrix/seymour_decomposition.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 7e186aa6ff7..01774bc3720 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1484,11 +1484,11 @@ cdef _class(CMR_MATROID_DEC *dec): if typ == CMR_MATROID_DEC_TYPE_THREE_SUM: return ThreeSumNode if typ == CMR_MATROID_DEC_TYPE_GRAPH: - if typ == CMR_MATROID_DEC_TYPE_COGRAPH: - return PlanarNode return GraphicNode if typ == CMR_MATROID_DEC_TYPE_COGRAPH: return CographicNode + if typ == CMR_MATROID_DEC_TYPE_PLANAR: + return PlanarNode if typ < -1: return SpecialLeafNode if typ == CMR_MATROID_DEC_TYPE_SERIES_PARALLEL: @@ -1501,7 +1501,7 @@ cdef _class(CMR_MATROID_DEC *dec): return ThreeConnectedIrregularNode if typ == CMR_MATROID_DEC_TYPE_UNKNOWN: return UnknownNode - assert NotImplementedError + raise NotImplementedError cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=None): From 5add4102303aeb3126d20ce9b8219fc958d2ac2c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 18 Mar 2024 23:25:12 -0700 Subject: [PATCH 179/262] Small edits --- src/sage/matrix/matrix_cmr_sparse.pyx | 6 +++--- src/sage/matrix/seymour_decomposition.pyx | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 5b69b39de5b..54c8ba2d979 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -4,9 +4,9 @@ Sparse Matrices with CMR """ # **************************************************************************** -# Copyright (C) 2023 Matthias Koeppe -# 2023 Luze Xu -# 2023 Javier Santillan +# Copyright (C) 2023 Javier Santillan +# 2023-2024 Matthias Koeppe +# 2023-2024 Luze Xu # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 01774bc3720..7302b737834 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -4,8 +4,9 @@ Seymour's decomposition of totally unimodular matrices and regular matroids """ # **************************************************************************** -# Copyright (C) 2023 Matthias Koeppe -# 2023 Javier Santillan +# Copyright (C) 2023 Javier Santillan +# 2023-2024 Matthias Koeppe +# 2023-2024 Luze Xu # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -296,6 +297,8 @@ cdef class DecompositionNode(SageObject): r""" Return the number of children of the node. """ + if self._children is not None: + return len(self._children) if self._dec == NULL: return 0 return CMRmatroiddecNumChildren(self._dec) @@ -1435,13 +1438,14 @@ cdef class ElementKey: INPUT: - ``keys`` -- a row/column key or a tuple - (`\pm 1`, row/column key, `\pm 1`, row/column key). + (`\pm 1`, row/column key, `\pm 1`, row/column key). + - ``composition`` -- ``True`` or ``False`` (default). - whether the key is a composition key or not. - If ``False``, ``self._key`` is a frozenset with a row/column key. - If ``True``, ``self._key`` is a frozenset with two tuples, - where each tuple has a sign value and a row/column key. - For example, ``frozenset((1,'a'), (-1,'7'))``. + whether the key is a composition key or not. + If ``False``, ``self._key`` is a frozenset with a row/column key. + If ``True``, ``self._key`` is a frozenset with two tuples, + where each tuple has a sign value and a row/column key. + For example, ``frozenset((1,'a'), (-1,'7'))``. """ if composition: sign1, key1, sign2, key2 = keys From 3e6d9fcc4a6060c2eee9389e08cbfd4085c23d5e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Mar 2024 14:06:07 -0700 Subject: [PATCH 180/262] Small edits (fixup) --- src/sage/matrix/seymour_decomposition.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 7302b737834..282cb7b43f3 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -297,8 +297,8 @@ cdef class DecompositionNode(SageObject): r""" Return the number of children of the node. """ - if self._children is not None: - return len(self._children) + if self._child_nodes is not None: + return len(self._child_nodes) if self._dec == NULL: return 0 return CMRmatroiddecNumChildren(self._dec) From d7956774d61405b29a9580748efd36008f1ddb54 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Mar 2024 14:24:19 -0700 Subject: [PATCH 181/262] Matrix_cmr_chr_sparse.is_graphic(decomposition=True) --- src/sage/matrix/matrix_cmr_sparse.pyx | 43 ++++++++++++++++------- src/sage/matrix/seymour_decomposition.pxd | 12 +++++++ src/sage/matrix/seymour_decomposition.pyx | 14 +++++++- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 54c8ba2d979..91b43b9f24f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -28,7 +28,7 @@ from sage.structure.element cimport Matrix from .args cimport MatrixArgs_init from .constructor import matrix from .matrix_space import MatrixSpace -from .seymour_decomposition cimport create_DecompositionNode +from .seymour_decomposition cimport create_DecompositionNode, GraphicNode cdef class Matrix_cmr_sparse(Matrix_sparse): @@ -1252,7 +1252,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return True if result else False - def is_graphic(self, *, time_limit=60.0, certificate=False, + def is_graphic(self, *, time_limit=60.0, decomposition=False, certificate=False, row_keys=None, column_keys=None): r""" EXAMPLES:: @@ -1286,6 +1286,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: coforest_edges {'v': (2, 7), 'w': (1, 12)} + Creating a decomposition node:: + + sage: result, node = M.is_graphic(decomposition=True, + ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) + sage: result, node + (True, GraphicNode (3×2)) + TESTS:: sage: M.is_graphic(time_limit=0.0) @@ -1293,7 +1300,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ... RuntimeError: Time limit exceeded """ - cdef bool result + cdef bool result_bool cdef CMR_GRAPH *graph = NULL cdef CMR_GRAPH_EDGE* forest_edges = NULL cdef CMR_GRAPH_EDGE* coforest_edges = NULL @@ -1302,25 +1309,37 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_on() try: - if certificate: - CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result, &graph, &forest_edges, + if decomposition or certificate: + CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result_bool, &graph, &forest_edges, &coforest_edges, &submatrix, &stats, time_limit)) else: - CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result, NULL, NULL, + CMR_CALL(CMRgraphicTestMatrix(cmr, self._mat, &result_bool, NULL, NULL, NULL, NULL, &stats, time_limit)) finally: sig_off() - if not certificate: - return result + result = result_bool - if result: + if not decomposition and not certificate: + return result + + if result: + result = [result] sage_graph = _sage_graph(graph) sage_forest_edges = _sage_edges(graph, forest_edges, self.nrows(), row_keys) sage_coforest_edges = _sage_edges(graph, coforest_edges, self.ncols(), column_keys) - return True, (sage_graph, sage_forest_edges, sage_coforest_edges) - - return False, NotImplemented # submatrix TBD + if decomposition: + result.append(GraphicNode(self, sage_graph, sage_forest_edges, sage_coforest_edges, + row_keys=row_keys, column_keys=column_keys)) + if certificate: + result.append((sage_graph, sage_forest_edges, sage_coforest_edges)) + else: + result = [result] + if decomposition: + raise NotImplementedError + if certificate: + result.append(NotImplemented) # submatrix TBD + return result def is_cographic(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 09abd6eb443..7662c29921a 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -26,6 +26,18 @@ cdef class BaseGraphicNode(DecompositionNode): cdef object _coforest_edges +cdef class GraphicNode(BaseGraphicNode): + pass + + +cdef class CographicNode(BaseGraphicNode): + pass + + +cdef class PlanarNode(BaseGraphicNode): + pass + + cdef class SymbolicNode(DecompositionNode): cdef object _symbol diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 282cb7b43f3..9d2483d01f3 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -580,7 +580,9 @@ cdef class UnknownNode(DecompositionNode): row_keys=self.row_keys(), column_keys=self.column_keys(), **kwds) result = [result] if decomposition: - raise NotImplementedError + graph, forest_edges, coforest_edges = certificate + node = GraphicNode(graph, forest_edges, coforest_edges) + result.append(node) if certificate: result.append(certificate) return result @@ -1177,6 +1179,16 @@ cdef class ThreeSumNode(SumNode): cdef class BaseGraphicNode(DecompositionNode): + def __init__(self, matrix=None, graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None): + self._matrix = matrix + self._graph = graph + self._forest_edges = forest_edges + self._coforest_edges = coforest_edges + if row_keys is not None: + self._set_row_keys(row_keys) + if column_keys is not None: + self._set_column_keys(column_keys) + def graph(self): r""" EXAMPLES:: From e6e999ff9c5be9b8df260ef710c83aa8da2a7e25 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 19 Mar 2024 15:37:46 -0700 Subject: [PATCH 182/262] WIP refactor child indices to parent node --- src/sage/matrix/seymour_decomposition.pyx | 100 +++++++++++----------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 9d2483d01f3..d96d06fefff 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -228,7 +228,7 @@ cdef class DecompositionNode(SageObject): ....: 'r6', 'r7', 'r8', 'r9'], ....: column_keys=['a','b','c','d','e','f', ....: 'g','h','i','j','k','l']) - sage: C = certificate._children()[0]; C + sage: C = certificate.child_nodes()[0]; C ThreeSumNode (9×12) with 2 children sage: C.parent_rows_and_columns() ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) @@ -267,7 +267,7 @@ cdef class DecompositionNode(SageObject): GraphicNode (3×2) GraphicNode (3×2) """ from sage.combinat.ordered_tree import LabelledOrderedTree - return LabelledOrderedTree([child.as_ordered_tree() for child in self._children()], + return LabelledOrderedTree([child.as_ordered_tree() for child in self.child_nodes()], label=self) def plot(self, **kwds): @@ -330,6 +330,11 @@ cdef class DecompositionNode(SageObject): raise ValueError(f"Child {index} does not have parents columns") parent_columns_tuple = tuple(parent_columns[i] for i in range(child_ncols)) + child_row_indices = tuple(CMRelementToRowIndex(element) + for element in parent_rows_tuple) + child_column_indices = tuple(CMRelementToColumnIndex(element) + for element in parent_columns_tuple) + if row_keys is not None and column_keys is not None: child_row_keys = tuple(self._CMRelement_to_key(element) for element in parent_rows_tuple) @@ -338,23 +343,22 @@ cdef class DecompositionNode(SageObject): child = create_DecompositionNode(child_dec, row_keys=child_row_keys, column_keys=child_column_keys) - parent_row_indices = tuple(CMRelementToRowIndex(element) - for element in parent_rows_tuple) - parent_column_indices = tuple(CMRelementToColumnIndex(element) - for element in parent_columns_tuple) - child._parent_indices = parent_row_indices, parent_column_indices else: - child_row_keys = tuple(CMRelementToRowIndex(element) - for element in parent_rows_tuple) - child_column_keys = tuple(CMRelementToColumnIndex(element) - for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, - row_keys=child_row_keys, - column_keys=child_column_keys) - child._parent_indices = child_row_keys, child_column_keys - return child + row_keys=child_row_indices, + column_keys=child_column_indices) + child._parent_indices = child_row_indices, child_column_indices + return child, (child_row_indices, child_column_indices) def _children(self): + if self._child_nodes is not None: + return self._child_nodes + children_tuple = tuple(self._create_child_node(index) + for index in range(self.nchildren())) + self._child_nodes = children_tuple + return self._child_nodes + + def child_nodes(self): r""" Return a tuple of the children. @@ -381,7 +385,7 @@ cdef class DecompositionNode(SageObject): [ 0 0| 0 0| 0 1] sage: result, certificate = M.is_totally_unimodular(certificate=True); certificate OneSumNode (6×6) with 4 children - sage: certificate._children() + sage: certificate.child_nodes() (GraphicNode (2×2), GraphicNode (2×2), GraphicNode (1×1), GraphicNode (1×1)) sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 2, sparse=True), @@ -390,14 +394,13 @@ cdef class DecompositionNode(SageObject): [-1 0] sage: result, certificate = M2.is_totally_unimodular(certificate=True); certificate GraphicNode (2×2) - sage: certificate._children() + sage: certificate.child_nodes() () """ - if self._child_nodes is not None: - return self._child_nodes - self._child_nodes = tuple(self._create_child_node(index) - for index in range(self.nchildren())) - return self._child_nodes + return tuple(child[0] for child in self._children()) + + def child_indices(self): + return tuple((child[1], child[2]) for child in self._children()) def _repr_(self): nrows, ncols = self.dimensions() @@ -464,9 +467,7 @@ cdef class DecompositionNode(SageObject): else: column_keys = tuple(column_key_list) - result._child_nodes = summands - result._child_row_keys = tuple(summands_row_keys) - result._child_column_keys = tuple(summands_column_keys) + result._child_nodes = tuple(zip(summands, summands_row_keys, summands_column_keys)) result._row_keys = row_keys result._column_keys = column_keys return result @@ -595,15 +596,14 @@ cdef class SumNode(DecompositionNode): def _repr_(self): result = super()._repr_() - children = self._children() - result += f' with {len(children)} children' + result += f' with {self.nchildren()} children' return result def permuted_block_matrix(self): r"Return (Prow, BlockMatrix, Pcolumn) so that self.matrix() == Prow * BlockMatrix * Pcolumn ????" raise NotImplementedError - summands = DecompositionNode._children + summands = DecompositionNode.child_nodes def summand_matrices(self): return tuple(s.matrix() for s in self.summands()) @@ -785,7 +785,7 @@ cdef class TwoSumNode(SumNode): [ 1 1 0 0| 1 0 1 0] [ 0 0 0 0| 1 0 1 1] [ 0 0 0 0| 0 -1 1 1] - sage: [M.parent_rows_and_columns() for M in certificate1._children()] + sage: [M.parent_rows_and_columns() for M in certificate1.child_nodes()] [((0, 1, 2, 3, 4), (0, 1, 2, 3)), ((4, 5, 6, 7), (0, 4, 5, 6, 7))] sage: M_perm = M.matrix_from_rows_and_columns([4, 6, 5, 7, 0, 1, 2, 3], range(M.ncols())) sage: M_perm @@ -816,7 +816,7 @@ cdef class TwoSumNode(SumNode): [ 0 0 0 0| 1 0 1 1] [ 1 1 0 0| 1 0 1 0] [ 0 0 0 0| 0 -1 1 1] - sage: [M.parent_rows_and_columns() for M in certificate2._children()] + sage: [M.parent_rows_and_columns() for M in certificate2.child_nodes()] [((4, 5, 6, 7, 0), (0, 1, 2, 3)), ((0, 1, 2, 3), (0, 4, 5, 6, 7))] """ M1, M2 = self.summand_matrices() @@ -838,10 +838,10 @@ cdef class ThreeSumNode(SumNode): ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(6), ....: column_keys='abcdef') - sage: C = certificate._children()[0] + sage: C = certificate.child_nodes()[0] sage: C.parent_rows_and_columns() ((0, 1, 2, 3, a, 5), (4, b, c, d, e, f)) - sage: C1, C2 = C._children() + sage: C1, C2 = C.child_nodes() sage: C1.matrix() [ 0 0 1 -1 -1] [ 1 1 1 0 0] @@ -876,9 +876,9 @@ cdef class ThreeSumNode(SumNode): ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(9), ....: column_keys='abcdefghijkl') - sage: C = certificate._children()[0]; C + sage: C = certificate.child_nodes()[0]; C ThreeSumNode (9×12) with 2 children - sage: C1, C2 = C._children() + sage: C1, C2 = C.child_nodes() sage: C1.matrix() [ 0 0 1 1 1 1 1] [ 1 1 0 0 0 -1 -1] @@ -903,7 +903,7 @@ cdef class ThreeSumNode(SumNode): sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed") - sage: C1, C2 = certificate._children() + sage: C1, C2 = certificate.child_nodes() sage: C1.matrix() [ 1 0 1 1 0] [ 0 1 1 1 0] @@ -924,7 +924,7 @@ cdef class ThreeSumNode(SumNode): ....: three_sum_strategy="Mixed_Mixed", ....: row_keys=range(6), ....: column_keys='abcdef') - sage: C1, C2 = certificate._children() + sage: C1, C2 = certificate.child_nodes() sage: C1.matrix() [ 1 0 1 1 0] [ 0 1 1 1 0] @@ -1088,19 +1088,20 @@ cdef class ThreeSumNode(SumNode): row_keys=child2_row_keys, column_keys=child2_column_keys) - parent_row1_indices = tuple(CMRelementToRowIndex(parent_rows1[i]) + child_row1_indices = tuple(CMRelementToRowIndex(parent_rows1[i]) for i in range(child1_nrows)) - parent_column1_indices = tuple(CMRelementToColumnIndex(parent_columns1[i]) + child_column1_indices = tuple(CMRelementToColumnIndex(parent_columns1[i]) for i in range(child1_ncols)) - child1._parent_indices = parent_row1_indices, parent_column1_indices + child1._parent_indices = child_row1_indices, child_column1_indices - parent_row2_indices = tuple(CMRelementToRowIndex(parent_rows2[i]) + child_row2_indices = tuple(CMRelementToRowIndex(parent_rows2[i]) for i in range(child2_nrows)) - parent_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) + child_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) for i in range(child2_ncols)) - child2._parent_indices = parent_row2_indices, parent_column2_indices + child2._parent_indices = child_row2_indices, child_column2_indices - self._child_nodes = (child1, child2) + self._child_nodes = ((child1, child_row1_indices, child_column1_indices), + (child2, child_row2_indices, child_column2_indices)) return self._child_nodes def is_distributed_ranks(self): @@ -1119,7 +1120,7 @@ cdef class ThreeSumNode(SumNode): ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12_large.is_totally_unimodular(certificate=True) - sage: C = certificate._children()[0]; C + sage: C = certificate.child_nodes()[0]; C ThreeSumNode (9×12) with 2 children sage: C.is_distributed_ranks() True @@ -1147,7 +1148,7 @@ cdef class ThreeSumNode(SumNode): [ 1 0 1 0 1 0] [ 0 -1 0 -1 0 1] sage: result, certificate = R12.is_totally_unimodular(certificate=True) - sage: C = certificate._children()[0]; C + sage: C = certificate.child_nodes()[0]; C ThreeSumNode (6×6) with 2 children sage: C.matrix() [ 1 0 0 1 -1 0] @@ -1294,7 +1295,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): [1 0 0 1 1] [1 1 0 0 1] """ - return self._children()[0].matrix() + return self.child_nodes()[0].matrix() cdef class SpecialLeafNode(DecompositionNode): @@ -1380,11 +1381,10 @@ cdef class PivotsNode(DecompositionNode): """ if self._child_nodes is not None: return self._child_nodes - self.set_default_keys() - - self._child_nodes = tuple(self._create_child_node(index) - for index in range(self.nchildren())) + children_tuple = tuple(self._create_child_node(index) + for index in range(self.nchildren())) + self._child_nodes = children_tuple return self._child_nodes From 336140f141588fb57a5cbef1944d29e0e7568dca Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 19 Mar 2024 15:49:42 -0700 Subject: [PATCH 183/262] Remove _parent_indices and fix doctests to use child_indices --- src/sage/matrix/matrix_cmr_sparse.pyx | 6 ++--- src/sage/matrix/seymour_decomposition.pxd | 3 --- src/sage/matrix/seymour_decomposition.pyx | 33 ++++++++--------------- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 91b43b9f24f..0e8c30ac1a1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1510,10 +1510,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: certificate=True) sage: result, certificate (False, (OneSumNode (6×14) with 2 children, NotImplemented)) - sage: certificate[0].summands()[0].parent_rows_and_columns() - ((0, 1, 2), (0, 4, 5, 6, 2, 3, 1)) - sage: certificate[0].summands()[1].parent_rows_and_columns() - ((3, 4, 5), (7, 11, 12, 13, 9, 10, 8)) + sage: certificate[0].child_indices() + (((0, 1, 2), (0, 4, 5, 6, 2, 3, 1)), ((3, 4, 5), (7, 11, 12, 13, 9, 10, 8))) sage: unicode_art(certificate[0]) # random (whether the left or the right branch has been followed) ╭OneSumNode (6×14) with 2 children╮ │ │ diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 7662c29921a..c19f0efcb88 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -8,10 +8,7 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC *_dec cdef object _row_keys cdef object _column_keys - cdef public object _parent_indices cdef object _child_nodes - cdef object _child_row_keys - cdef object _child_column_keys cdef _set_dec(self, CMR_MATROID_DEC *dec) cdef _set_row_keys(self, row_keys) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d96d06fefff..b1beddc9104 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -149,11 +149,6 @@ cdef class DecompositionNode(SageObject): """ return self._column_keys - def parent_indices(self): - r""" - """ - return self._parent_indices - def set_default_keys(self): row_keys = self.row_keys() column_keys = self.column_keys() @@ -207,9 +202,9 @@ cdef class DecompositionNode(SageObject): (True, OneSumNode (6×4) with 2 children) sage: C = certificate.summands(); C (GraphicNode (3×2), GraphicNode (3×2)) - sage: C[0].parent_rows_and_columns() + sage: certificate.child_indices()[0] ((0, 1, 2), (0, 1)) - sage: C[1].parent_rows_and_columns() + sage: certificate.child_indices()[1] ((3, 4, 5), (2, 3)) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -238,7 +233,7 @@ cdef class DecompositionNode(SageObject): if isinstance(self.row_keys()[0], ElementKey): return self.ancestor_rows_and_columns() else: - return self.parent_indices() + raise ValueError("The child indices can be accessed in the parent node.") @cached_method def ancestor_rows_and_columns(self): @@ -347,8 +342,7 @@ cdef class DecompositionNode(SageObject): child = create_DecompositionNode(child_dec, row_keys=child_row_indices, column_keys=child_column_indices) - child._parent_indices = child_row_indices, child_column_indices - return child, (child_row_indices, child_column_indices) + return child, child_row_indices, child_column_indices def _children(self): if self._child_nodes is not None: @@ -678,8 +672,7 @@ cdef class OneSumNode(SumNode): OneSumNode (4×4) with 2 children sage: OneSumNode.check(M2, ....: certificate.summand_matrices(), - ....: [summand.parent_rows_and_columns() - ....: for summand in certificate.summands()]) + ....: certificate.child_indices()) Symbolic identities:: @@ -785,8 +778,8 @@ cdef class TwoSumNode(SumNode): [ 1 1 0 0| 1 0 1 0] [ 0 0 0 0| 1 0 1 1] [ 0 0 0 0| 0 -1 1 1] - sage: [M.parent_rows_and_columns() for M in certificate1.child_nodes()] - [((0, 1, 2, 3, 4), (0, 1, 2, 3)), ((4, 5, 6, 7), (0, 4, 5, 6, 7))] + sage: certificate1.child_indices() + (((0, 1, 2, 3, 4), (0, 1, 2, 3)), ((4, 5, 6, 7), (0, 4, 5, 6, 7))) sage: M_perm = M.matrix_from_rows_and_columns([4, 6, 5, 7, 0, 1, 2, 3], range(M.ncols())) sage: M_perm [ 1 1 0 0 1 1 0 0] @@ -816,8 +809,8 @@ cdef class TwoSumNode(SumNode): [ 0 0 0 0| 1 0 1 1] [ 1 1 0 0| 1 0 1 0] [ 0 0 0 0| 0 -1 1 1] - sage: [M.parent_rows_and_columns() for M in certificate2.child_nodes()] - [((4, 5, 6, 7, 0), (0, 1, 2, 3)), ((0, 1, 2, 3), (0, 4, 5, 6, 7))] + sage: certificate2.child_indices() + (((4, 5, 6, 7, 0), (0, 1, 2, 3)), ((0, 1, 2, 3), (0, 4, 5, 6, 7))) """ M1, M2 = self.summand_matrices() return Matrix_cmr_chr_sparse.two_sum(M1, M2, M1.nrows() - 1, 0, "bottom_left") @@ -854,12 +847,10 @@ cdef class ThreeSumNode(SumNode): [-1 -1 0 0 1] sage: C1.parent_rows_and_columns() ((0, 1, a, 3), (b, c, d, e, +3+e)) - sage: C1.parent_indices() - ((0, 1, 4, 3), (1, 2, 3, 4, 4)) sage: C2.parent_rows_and_columns() ((0, 2, 3, 5), (+0+d, d, 4, e, f)) - sage: C2.parent_indices() - ((0, 2, 3, 5), (3, 3, 0, 4, 5)) + sage: C.child_indices() + (((0, 1, 4, 3), (1, 2, 3, 4, 4)), ((0, 2, 3, 5), (3, 3, 0, 4, 5))) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), @@ -1092,13 +1083,11 @@ cdef class ThreeSumNode(SumNode): for i in range(child1_nrows)) child_column1_indices = tuple(CMRelementToColumnIndex(parent_columns1[i]) for i in range(child1_ncols)) - child1._parent_indices = child_row1_indices, child_column1_indices child_row2_indices = tuple(CMRelementToRowIndex(parent_rows2[i]) for i in range(child2_nrows)) child_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) for i in range(child2_ncols)) - child2._parent_indices = child_row2_indices, child_column2_indices self._child_nodes = ((child1, child_row1_indices, child_column1_indices), (child2, child_row2_indices, child_column2_indices)) From f316e060c01cd5fdc852c2598769730a14486a92 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 19 Mar 2024 18:19:18 -0700 Subject: [PATCH 184/262] remove parent_rows_and_columns --- src/sage/matrix/seymour_decomposition.pyx | 170 +++++++++------------- 1 file changed, 72 insertions(+), 98 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b1beddc9104..3c2af0b2579 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -170,71 +170,6 @@ cdef class DecompositionNode(SageObject): row_keys=self.row_keys(), column_keys=self.column_keys()) - @cached_method - def parent_rows_and_columns(self): - r""" - EXAMPLES:: - - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), - ....: [[1, 0], [-1, 1], [0, 1]]); M - [ 1 0] - [-1 1] - [ 0 1] - sage: result, certificate = M.is_totally_unimodular(certificate=True) - sage: certificate.parent_rows_and_columns() - Traceback (most recent call last): - ... - ValueError: This is probably a root node. No keys or indices stored. - - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) - sage: M2 = block_diagonal_matrix([M, M], sparse=True) - sage: M2cmr = Matrix_cmr_chr_sparse(M2.parent(), M2); M2cmr - [ 1 0 0 0] - [-1 1 0 0] - [ 0 1 0 0] - [ 0 0 1 0] - [ 0 0 -1 1] - [ 0 0 0 1] - sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True) - sage: result, certificate - (True, OneSumNode (6×4) with 2 children) - sage: C = certificate.summands(); C - (GraphicNode (3×2), GraphicNode (3×2)) - sage: certificate.child_indices()[0] - ((0, 1, 2), (0, 1)) - sage: certificate.child_indices()[1] - ((3, 4, 5), (2, 3)) - - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) - sage: result, certificate = R12.is_totally_unimodular(certificate=True, - ....: row_keys=['r1', 'r2', 'r3', 'r4', 'r5', - ....: 'r6', 'r7', 'r8', 'r9'], - ....: column_keys=['a','b','c','d','e','f', - ....: 'g','h','i','j','k','l']) - sage: C = certificate.child_nodes()[0]; C - ThreeSumNode (9×12) with 2 children - sage: C.parent_rows_and_columns() - ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) - """ - if self._row_keys is None or self._column_keys is None: - raise ValueError("This is probably a root node. No keys or indices stored.") - if isinstance(self.row_keys()[0], ElementKey): - return self.ancestor_rows_and_columns() - else: - raise ValueError("The child indices can be accessed in the parent node.") - @cached_method def ancestor_rows_and_columns(self): return self.row_keys(), self.column_keys() @@ -325,11 +260,6 @@ cdef class DecompositionNode(SageObject): raise ValueError(f"Child {index} does not have parents columns") parent_columns_tuple = tuple(parent_columns[i] for i in range(child_ncols)) - child_row_indices = tuple(CMRelementToRowIndex(element) - for element in parent_rows_tuple) - child_column_indices = tuple(CMRelementToColumnIndex(element) - for element in parent_columns_tuple) - if row_keys is not None and column_keys is not None: child_row_keys = tuple(self._CMRelement_to_key(element) for element in parent_rows_tuple) @@ -339,10 +269,14 @@ cdef class DecompositionNode(SageObject): row_keys=child_row_keys, column_keys=child_column_keys) else: + child_row_keys = tuple(CMRelementToRowIndex(element) + for element in parent_rows_tuple) + child_column_keys = tuple(CMRelementToColumnIndex(element) + for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, - row_keys=child_row_indices, - column_keys=child_column_indices) - return child, child_row_indices, child_column_indices + row_keys=child_row_keys, + column_keys=child_column_keys) + return child, child_row_keys, child_column_keys def _children(self): if self._child_nodes is not None: @@ -394,6 +328,60 @@ cdef class DecompositionNode(SageObject): return tuple(child[0] for child in self._children()) def child_indices(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: certificate.child_indices() + () + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = matrix([[1, 0], [-1, 1], [0, 1]], sparse=True) + sage: M2 = block_diagonal_matrix([M, M], sparse=True) + sage: M2cmr = Matrix_cmr_chr_sparse(M2.parent(), M2); M2cmr + [ 1 0 0 0] + [-1 1 0 0] + [ 0 1 0 0] + [ 0 0 1 0] + [ 0 0 -1 1] + [ 0 0 0 1] + sage: result, certificate = M2cmr.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, OneSumNode (6×4) with 2 children) + sage: C = certificate.summands(); C + (GraphicNode (3×2), GraphicNode (3×2)) + sage: certificate.child_indices()[0] + ((0, 1, 2), (0, 1)) + sage: certificate.child_indices()[1] + ((3, 4, 5), (2, 3)) + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: row_keys=['r1', 'r2', 'r3', 'r4', 'r5', + ....: 'r6', 'r7', 'r8', 'r9'], + ....: column_keys=['a','b','c','d','e','f', + ....: 'g','h','i','j','k','l']) + sage: C = certificate.child_nodes()[0]; C + ThreeSumNode (9×12) with 2 children + sage: certificate.child_indices() + ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) + """ return tuple((child[1], child[2]) for child in self._children()) def _repr_(self): @@ -831,9 +819,9 @@ cdef class ThreeSumNode(SumNode): ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(6), ....: column_keys='abcdef') - sage: C = certificate.child_nodes()[0] - sage: C.parent_rows_and_columns() + sage: certificate.child_indices() ((0, 1, 2, 3, a, 5), (4, b, c, d, e, f)) + sage: C = certificate.child_nodes()[0] sage: C1, C2 = C.child_nodes() sage: C1.matrix() [ 0 0 1 -1 -1] @@ -845,12 +833,8 @@ cdef class ThreeSumNode(SumNode): [ 0 0 1 0 1] [-1 -1 0 1 1] [-1 -1 0 0 1] - sage: C1.parent_rows_and_columns() - ((0, 1, a, 3), (b, c, d, e, +3+e)) - sage: C2.parent_rows_and_columns() - ((0, 2, 3, 5), (+0+d, d, 4, e, f)) sage: C.child_indices() - (((0, 1, 4, 3), (1, 2, 3, 4, 4)), ((0, 2, 3, 5), (3, 3, 0, 4, 5))) + (((0, 1, a, 3), (b, c, d, e, +3+e)), ((0, 2, 3, 5), (+0+d, d, 4, e, f))) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), @@ -887,9 +871,9 @@ cdef class ThreeSumNode(SumNode): (0, i, 2, 3, 4, 5, 6, 7, 8) sage: C.column_keys() (a, b, c, d, e, f, g, h, 1, j, k, l) - sage: C1.parent_rows_and_columns() + sage: C.child_indices()[0] ((i, 2, 7, 8, 3), (g, h, j, k, l, d, -3+d)) - sage: C2.parent_rows_and_columns() + sage: C.child_indices()[1] ((i, 0, 3, 4, 5, 6), (+i+k, k, a, b, c, d, e, f, 1)) sage: result, certificate = R12.is_totally_unimodular(certificate=True, @@ -906,9 +890,9 @@ cdef class ThreeSumNode(SumNode): [ 0 -1 1 1] [ 1 0 1 0] [ 0 -1 0 1] - sage: C1.parent_rows_and_columns() + sage: certificate.child_indices()[0] ((r0, r1, r2, r3), (c0, c1, c2, c3, +r2+r3)) - sage: C2.parent_rows_and_columns() + sage: certificate.child_indices()[1] ((+c0+c3, r2, r3, r4, r5), (c0, c3, c4, c5)) sage: result, certificate = R12.is_totally_unimodular(certificate=True, @@ -927,9 +911,9 @@ cdef class ThreeSumNode(SumNode): [ 0 -1 1 1] [ 1 0 1 0] [ 0 -1 0 1] - sage: C1.parent_rows_and_columns() + sage: certificate.child_indices()[0] ((0, 1, 2, 3), (a, b, c, d, +2+3)) - sage: C2.parent_rows_and_columns() + sage: certificate.child_indices()[1] ((+a+d, 2, 3, 4, 5), (a, d, e, f)) """ if self._child_nodes is not None: @@ -1079,18 +1063,8 @@ cdef class ThreeSumNode(SumNode): row_keys=child2_row_keys, column_keys=child2_column_keys) - child_row1_indices = tuple(CMRelementToRowIndex(parent_rows1[i]) - for i in range(child1_nrows)) - child_column1_indices = tuple(CMRelementToColumnIndex(parent_columns1[i]) - for i in range(child1_ncols)) - - child_row2_indices = tuple(CMRelementToRowIndex(parent_rows2[i]) - for i in range(child2_nrows)) - child_column2_indices = tuple(CMRelementToColumnIndex(parent_columns2[i]) - for i in range(child2_ncols)) - - self._child_nodes = ((child1, child_row1_indices, child_column1_indices), - (child2, child_row2_indices, child_column2_indices)) + self._child_nodes = ((child1, child1_row_keys, child1_column_keys), + (child2, child2_row_keys, child2_column_keys)) return self._child_nodes def is_distributed_ranks(self): From 59924e3ac361dff14777bf7e0772c3052149fcfb Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 19 Mar 2024 18:45:27 -0700 Subject: [PATCH 185/262] simplify single child indice output --- src/sage/matrix/seymour_decomposition.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 3c2af0b2579..b3033b335f6 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -382,6 +382,9 @@ cdef class DecompositionNode(SageObject): sage: certificate.child_indices() ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) """ + if self.nchildren() == 1: + child = self._children()[0] + return (child[1], child[2]) return tuple((child[1], child[2]) for child in self._children()) def _repr_(self): From e519f596f3e83c0daeab64894126ad98cffda072 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Mar 2024 23:16:18 -0700 Subject: [PATCH 186/262] src/sage/matrix/seymour_decomposition.pyx: Fix up is_graphic --- src/sage/matrix/seymour_decomposition.pyx | 40 ++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b3033b335f6..cc3c2f2384a 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -560,17 +560,19 @@ cdef class UnknownNode(DecompositionNode): sage: forest_edges ((1, 2), (7, 1), (12, 7)) """ + matrix = self.matrix() if not decomposition and not certificate: - return self.matrix().is_graphic(**kwds) - result, certificate = self.matrix().is_graphic(certificate=True, - row_keys=self.row_keys(), column_keys=self.column_keys(), **kwds) + return matrix.is_graphic(**kwds) + result, cert = matrix.is_graphic(certificate=True, + row_keys=self.row_keys(), + column_keys=self.column_keys(), **kwds) result = [result] if decomposition: - graph, forest_edges, coforest_edges = certificate - node = GraphicNode(graph, forest_edges, coforest_edges) + graph, forest_edges, coforest_edges = cert + node = GraphicNode(matrix, graph, forest_edges, coforest_edges) result.append(node) if certificate: - result.append(certificate) + result.append(cert) return result @@ -1196,13 +1198,35 @@ cdef class BaseGraphicNode(DecompositionNode): (True, GraphicNode (3×2)) sage: certificate.forest_edges() ((1, 2), (7, 1), (12, 7)) + + Starting with a morphism:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: phi = matrix(ZZ, [[1, 0], [-1, 1], [0, 1]], + ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) + sage: phi; phi._unicode_art_matrix() + Generic morphism: + From: Free module generated by {'v', 'w'} over Integer Ring + To: Free module generated by {'a', 'b', 'c'} over Integer Ring + v w + a⎛ 1 0⎞ + b⎜-1 1⎟ + c⎝ 0 1⎠ + sage: phi_node = UnknownNode(phi) + sage: is_graphic, rephined_node = phi_node.is_graphic(decomposition=True) + sage: is_graphic, rephined_node + (True, GraphicNode (3×2)) + sage: rephined_node.forest_edges() + {'a': (1, 2), 'b': (7, 1), 'c': (12, 7)} + sage: phi_node # still in the dark about graphicness + UnknownNode (3×2) """ if self._forest_edges is not None: return self._forest_edges cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) - self._forest_edges = _sage_edges(graph, edges, num_edges, None) + self._forest_edges = _sage_edges(graph, edges, num_edges, self.row_keys()) return self._forest_edges def coforest_edges(self): @@ -1211,7 +1235,7 @@ cdef class BaseGraphicNode(DecompositionNode): cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) - self._coforest_edges = _sage_edges(graph, edges, num_edges, None) + self._coforest_edges = _sage_edges(graph, edges, num_edges, self.column_keys()) return self._coforest_edges From ccb94430b0b6b42a355d22e976e8c4aac8c257d3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Mar 2024 12:07:48 -0700 Subject: [PATCH 187/262] base ring checks --- src/sage/matrix/matrix_cmr_sparse.pyx | 59 +++++++++++++++++++++-- src/sage/matrix/seymour_decomposition.pxd | 5 +- src/sage/matrix/seymour_decomposition.pyx | 26 +++++++--- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 0e8c30ac1a1..4359b5b9f7e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -997,6 +997,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_unimodular() False """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef CMR_INTMAT *int_mat = NULL cdef bool result @@ -1037,6 +1041,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_strongly_unimodular() True """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef CMR_INTMAT *int_mat = NULL cdef bool result @@ -1197,6 +1205,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_k_equimodular(1) False """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef CMR_INTMAT *int_mat = NULL cdef bool result cdef int64_t gcd_det = k @@ -1238,6 +1250,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_strongly_k_equimodular(1) True """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef CMR_INTMAT *int_mat = NULL cdef bool result cdef int64_t gcd_det = k @@ -1300,6 +1316,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ... RuntimeError: Time limit exceeded """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef bool result_bool cdef CMR_GRAPH *graph = NULL cdef CMR_GRAPH_EDGE* forest_edges = NULL @@ -1359,6 +1379,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_cographic() True """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef bool result cdef CMR_GRAPH *graph = NULL cdef CMR_GRAPH_EDGE* forest_edges = NULL @@ -1421,6 +1445,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: digraph.plot(edge_colors={'red': forest_arcs}) # needs sage.plot Graphics object consisting of 21 graphics primitives """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef bool result cdef bool support_result cdef CMR_GRAPH *digraph = NULL @@ -1562,7 +1590,26 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): GraphicNode (7×8) SeriesParallelReductionNode (5×4) │ GraphicNode (4×4) + + Base ring check:: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(5), 3, 2, sparse=True), + ....: [[1, 0], [6, 11], [0, 1]]); M + [1 0] + [1 1] + [0 1] + sage: M._is_binary_linear_matroid_regular() + Traceback (most recent call last): + ... + ValueError: not well-defined + """ + base_ring = self.parent().base_ring() + from sage.rings.finite_rings.finite_field_constructor import GF + GF2 = GF(2) + if not GF2.has_coerce_map_from(base_ring): + raise ValueError('not well-defined') + cdef bool result cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats @@ -1591,11 +1638,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result - if result: - return True, create_DecompositionNode(dec, row_keys, column_keys) + node = create_DecompositionNode(dec, row_keys, column_keys, base_ring=GF2) - return False, (create_DecompositionNode(dec, row_keys, column_keys), - NotImplemented) + if result: + return True, node + return False, (node, NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, @@ -1664,6 +1711,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [1 1 0] """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + cdef bool result cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index c19f0efcb88..3029f33b1d8 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -4,6 +4,7 @@ from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): + cdef object _base_ring cdef object _matrix cdef CMR_MATROID_DEC *_dec cdef object _row_keys @@ -40,4 +41,6 @@ cdef class SymbolicNode(DecompositionNode): cdef object _symbol -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=?, column_keys=?) +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, + row_keys=?, column_keys=?, + base_ring=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index cc3c2f2384a..958b5e3e77c 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -101,6 +101,9 @@ cdef class DecompositionNode(SageObject): def dimensions(self): return self.nrows(), self.ncols() + def base_ring(self): + return self._base_ring + def matrix(self): r""" Return a :class:`Matrix`. @@ -130,7 +133,7 @@ cdef class DecompositionNode(SageObject): cdef CMR_CHRMAT *mat = CMRmatroiddecGetMatrix(self._dec) if mat == NULL: return None - ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) + ms = MatrixSpace(self.base_ring(), mat.numRows, mat.numColumns, sparse=True) result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms) result._mat = mat result._root = self # Matrix is owned by us @@ -267,7 +270,8 @@ cdef class DecompositionNode(SageObject): for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, row_keys=child_row_keys, - column_keys=child_column_keys) + column_keys=child_column_keys, + base_ring=self.base_ring()) else: child_row_keys = tuple(CMRelementToRowIndex(element) for element in parent_rows_tuple) @@ -275,7 +279,8 @@ cdef class DecompositionNode(SageObject): for element in parent_columns_tuple) child = create_DecompositionNode(child_dec, row_keys=child_row_keys, - column_keys=child_column_keys) + column_keys=child_column_keys, + base_ring=self.base_ring()) return child, child_row_keys, child_column_keys def _children(self): @@ -1004,7 +1009,8 @@ cdef class ThreeSumNode(SumNode): child1 = create_DecompositionNode(child1_dec, row_keys=child1_row_keys, - column_keys=child1_column_keys) + column_keys=child1_column_keys, + base_ring=self.base_ring()) child2_nrows = CMRmatroiddecNumRows(child2_dec) child2_ncols = CMRmatroiddecNumColumns(child2_dec) @@ -1066,7 +1072,8 @@ cdef class ThreeSumNode(SumNode): child2 = create_DecompositionNode(child2_dec, row_keys=child2_row_keys, - column_keys=child2_column_keys) + column_keys=child2_column_keys, + base_ring=self.base_ring()) self._child_nodes = ((child1, child1_row_keys, child1_column_keys), (child2, child2_row_keys, child2_column_keys)) @@ -1148,7 +1155,11 @@ cdef class ThreeSumNode(SumNode): cdef class BaseGraphicNode(DecompositionNode): - def __init__(self, matrix=None, graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None): + def __init__(self, matrix=None, graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None, base_ring=None): + if base_ring is None: + if matrix is not None: + base_ring = matrix.parent().base_ring() + self._base_ring = base_ring self._matrix = matrix self._graph = graph self._forest_edges = forest_edges @@ -1510,7 +1521,7 @@ cdef _class(CMR_MATROID_DEC *dec): raise NotImplementedError -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=None): +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=None, base_ring=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. @@ -1526,4 +1537,5 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=N result._set_row_keys(row_keys) if column_keys is not None: result._set_column_keys(column_keys) + result._base_ring = base_ring return result From 137cbd8ff44103e18be62b61b5ff3dc087ba6280 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Mar 2024 17:23:39 -0700 Subject: [PATCH 188/262] Pass base rings through --- src/sage/matrix/matrix_cmr_sparse.pxd | 2 +- src/sage/matrix/matrix_cmr_sparse.pyx | 43 ++++++++--- src/sage/matrix/seymour_decomposition.pxd | 1 + src/sage/matrix/seymour_decomposition.pyx | 87 +++++++++++------------ 4 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index 14bc2909edb..0b8fa289a66 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -20,7 +20,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _init_from_dict(self, dict d, int nrows, int ncols, bint immutable=?) @staticmethod - cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?) + cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?, base_ring=?) cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4359b5b9f7e..0c83e45b51b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -250,7 +250,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return data @staticmethod - cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=False): + cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=False, base_ring=None): r""" INPUT: @@ -260,7 +260,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): """ cdef Matrix_cmr_chr_sparse result - ms = MatrixSpace(ZZ, mat.numRows, mat.numColumns, sparse=True) + if base_ring is None: + base_ring = ZZ + ms = MatrixSpace(base_ring, mat.numRows, mat.numColumns, sparse=True) result = Matrix_cmr_chr_sparse.__new__(Matrix_cmr_chr_sparse, ms, immutable=immutable) result._mat = mat result._root = None @@ -594,11 +596,32 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 0| 0 0 -1 0 1] [ 0 0 0 0| 1 0 0 -1 0] [ 0 0 0 0| 0 1 0 0 1] + + TESTS:: + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(GF(3), 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 5, 6]]); M1 + [1 2 0] + [1 2 0] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(GF(5), 2, 3, sparse=True), + ....: [[7, 8, 9], [-1, -2, -3]]); M2 + [2 3 4] + [4 3 2] + sage: Matrix_cmr_chr_sparse.two_sum(M1, M2, 2, 0) + Traceback (most recent call last): + ... + ValueError: summands must have the same base ring, + got Finite Field of size 3, Finite Field of size 5 """ cdef Matrix_cmr_chr_sparse sum, first, second cdef CMR_CHRMAT *sum_mat = NULL first = Matrix_cmr_chr_sparse._from_data(first_mat) second = Matrix_cmr_chr_sparse._from_data(second_mat) + first_base_ring = first.parent().base_ring() + second_base_ring = second.parent().base_ring() + if first_base_ring != second_base_ring: + raise ValueError(f'summands must have the same base ring, ' + f'got {first_base_ring}, {second_base_ring}') if nonzero_block not in ["top_right", "bottom_left"]: raise ValueError("Unknown two sum mode", nonzero_block) @@ -630,10 +653,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): first_marker = CMRrowToElement(row) second_marker = CMRcolumnToElement(column) - cdef int8_t characteristic = first_mat.parent().characteristic() - - if second_mat.parent().characteristic() != characteristic: - raise ValueError("The characteristic of two matrices are different") + cdef int8_t characteristic = first_base_ring.characteristic() sig_on() try: @@ -641,7 +661,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): finally: sig_off() - sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False) + sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat, immutable=False, base_ring=first_base_ring) if row_subdivision or column_subdivision: sum.subdivide(row_subdivision, column_subdivision) sum.set_immutable() @@ -1638,7 +1658,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result - node = create_DecompositionNode(dec, row_keys, column_keys, base_ring=GF2) + node = create_DecompositionNode(dec, self, row_keys, column_keys) if result: return True, node @@ -1747,8 +1767,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not certificate: return result + node = create_DecompositionNode(dec, self, row_keys, column_keys) + if result: - return True, create_DecompositionNode(dec, row_keys, column_keys) + return True, node if submat == NULL: submat_tuple = None @@ -1756,8 +1778,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), tuple(submat.columns[i] for i in range(submat.numColumns))) - return False, (create_DecompositionNode(dec, row_keys, column_keys), - submat_tuple) + return False, (node, submat_tuple) def is_complement_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index 3029f33b1d8..b4fdf46e0ea 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -42,5 +42,6 @@ cdef class SymbolicNode(DecompositionNode): cdef create_DecompositionNode(CMR_MATROID_DEC *dec, + matrix=?, row_keys=?, column_keys=?, base_ring=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 958b5e3e77c..79650a5fadd 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -33,9 +33,37 @@ cdef class DecompositionNode(SageObject): Base class for nodes in Seymour's decomposition """ - def __cinit__(self): + def __cinit__(self, *args, **kwds): self._dec = NULL + def __init__(self, matrix=None, row_keys=None, column_keys=None, base_ring=None): + if matrix is None: + self._matrix = None + elif isinstance(matrix, Matrix_cmr_chr_sparse): + self._matrix = matrix + else: + try: + self._matrix = matrix._matrix_cmr() + except (AttributeError, ImportError, TypeError): + if base_ring is not None: + matrix = Matrix(matrix, ring=base_ring) + else: + matrix = Matrix(matrix) + self._matrix = Matrix_cmr_chr_sparse(matrix.parent(), matrix) + else: + if row_keys is None: + row_keys = matrix.codomain().basis().keys() + if column_keys is None: + column_keys = matrix.domain().basis().keys() + if row_keys is not None: + self._set_row_keys(row_keys) + if column_keys is not None: + self._set_column_keys(column_keys) + if base_ring is None: + if self._matrix is not None: + base_ring = self._matrix.parent().base_ring() + self._base_ring = base_ring + cdef _set_dec(self, CMR_MATROID_DEC *dec): if self._dec != NULL: # We own it, so we have to free it. @@ -268,7 +296,7 @@ cdef class DecompositionNode(SageObject): for element in parent_rows_tuple) child_column_keys = tuple(self._CMRelement_to_key(element) for element in parent_columns_tuple) - child = create_DecompositionNode(child_dec, + child = create_DecompositionNode(child_dec, matrix=None, row_keys=child_row_keys, column_keys=child_column_keys, base_ring=self.base_ring()) @@ -277,7 +305,7 @@ cdef class DecompositionNode(SageObject): for element in parent_rows_tuple) child_column_keys = tuple(CMRelementToColumnIndex(element) for element in parent_columns_tuple) - child = create_DecompositionNode(child_dec, + child = create_DecompositionNode(child_dec, matrix=None, row_keys=child_row_keys, column_keys=child_column_keys, base_ring=self.base_ring()) @@ -528,25 +556,6 @@ cdef class UnknownNode(DecompositionNode): [0 1 1] """ - def __init__(self, matrix=None, row_keys=None, column_keys=None): - if matrix is None: - self._matrix = None - elif isinstance(matrix, Matrix_cmr_chr_sparse): - self._matrix = matrix - else: - try: - self._matrix = matrix._matrix_cmr() - except (AttributeError, ImportError, TypeError): - matrix = Matrix(matrix) - self._matrix = Matrix_cmr_chr_sparse(matrix.parent(), matrix) - else: - if row_keys is None: - row_keys = matrix.codomain().basis().keys() - if column_keys is None: - column_keys = matrix.domain().basis().keys() - self._row_keys = row_keys - self._column_keys = column_keys - def is_graphic(self, *, decomposition=False, certificate=False, **kwds): r""" EXAMPLES:: @@ -1007,7 +1016,7 @@ cdef class ThreeSumNode(SumNode): composition=True) child1_column_keys += (extra_key,) - child1 = create_DecompositionNode(child1_dec, + child1 = create_DecompositionNode(child1_dec, matrix=None, row_keys=child1_row_keys, column_keys=child1_column_keys, base_ring=self.base_ring()) @@ -1070,7 +1079,7 @@ cdef class ThreeSumNode(SumNode): composition=True) child2_column_keys = (extra_key,) + child2_column_keys - child2 = create_DecompositionNode(child2_dec, + child2 = create_DecompositionNode(child2_dec, matrix=None, row_keys=child2_row_keys, column_keys=child2_column_keys, base_ring=self.base_ring()) @@ -1155,19 +1164,14 @@ cdef class ThreeSumNode(SumNode): cdef class BaseGraphicNode(DecompositionNode): - def __init__(self, matrix=None, graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None, base_ring=None): - if base_ring is None: - if matrix is not None: - base_ring = matrix.parent().base_ring() - self._base_ring = base_ring - self._matrix = matrix + def __init__(self, matrix=None, + graph=None, forest_edges=None, coforest_edges=None, + row_keys=None, column_keys=None, base_ring=None): + super().__init__(matrix=matrix, row_keys=row_keys, column_keys=column_keys, + base_ring=base_ring) self._graph = graph self._forest_edges = forest_edges self._coforest_edges = coforest_edges - if row_keys is not None: - self._set_row_keys(row_keys) - if column_keys is not None: - self._set_column_keys(column_keys) def graph(self): r""" @@ -1395,7 +1399,7 @@ cdef class SubmatrixNode(DecompositionNode): cdef class SymbolicNode(DecompositionNode): - def __init__(self, symbol, *, row_keys=None, column_keys=None): + def __init__(self, symbol, *, row_keys=None, column_keys=None, base_ring=None): r""" EXAMPLES:: @@ -1422,9 +1426,8 @@ cdef class SymbolicNode(DecompositionNode): sage: XY = X.one_sum(Y); XY OneSumNode (5×8) with 2 children """ + super().__init__(row_keys=row_keys, column_keys=column_keys, base_ring=base_ring) self._symbol = symbol - self._set_row_keys(row_keys) - self._set_column_keys(column_keys) def _repr_(self): nrows, ncols = self.dimensions() @@ -1521,7 +1524,7 @@ cdef _class(CMR_MATROID_DEC *dec): raise NotImplementedError -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=None, base_ring=None): +cdef create_DecompositionNode(CMR_MATROID_DEC *dec, matrix=None, row_keys=None, column_keys=None, base_ring=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. @@ -1531,11 +1534,7 @@ cdef create_DecompositionNode(CMR_MATROID_DEC *dec, row_keys=None, column_keys=N """ if dec == NULL: return None - cdef DecompositionNode result = _class(dec)() + cdef DecompositionNode result = _class(dec)( + matrix, row_keys=row_keys, column_keys=column_keys, base_ring=base_ring) result._set_dec(dec) - if row_keys is not None: - result._set_row_keys(row_keys) - if column_keys is not None: - result._set_column_keys(column_keys) - result._base_ring = base_ring return result From fde01ffea4ee868e5a9286d9107c8c1b634dc23d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Mar 2024 17:25:05 -0700 Subject: [PATCH 189/262] ancestor_rows_and_columns: Remove --- src/sage/matrix/seymour_decomposition.pyx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 79650a5fadd..65b8d7fa145 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -136,9 +136,6 @@ cdef class DecompositionNode(SageObject): r""" Return a :class:`Matrix`. - Use :meth:`ancestor_rows_and_columns` for the embedding of it - into the matrix of ... - EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -201,10 +198,6 @@ cdef class DecompositionNode(SageObject): row_keys=self.row_keys(), column_keys=self.column_keys()) - @cached_method - def ancestor_rows_and_columns(self): - return self.row_keys(), self.column_keys() - def as_ordered_tree(self): r""" EXAMPLES:: From 7f810170babe458e5360c679f012ca4f421644af Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 3 Apr 2024 23:54:37 -0700 Subject: [PATCH 190/262] build/pkgs/cmr: Update to c2c1b7dc2d0adf90ae836fd8776ad14c194afea1 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 30afb273b14..2fd92210e76 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=3927c05adb4a21122deb59df01707122df0ba7b2 -md5=ed2211ba7c06abed5579b6987f67974b -cksum=3326371555 +sha1=e3d1892eddcde50e47389fe75eb4ab8b02181e21 +md5=22388e0e3c68d535e11218a3a13eb2b3 +cksum=2117523128 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 809b3fa2a95..7a47e8733e1 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -5a8fc240b1c3c7807c246ec27bee5246db2e0e1e +c2c1b7dc2d0adf90ae836fd8776ad14c194afea1 From cf1e9d7eea72e4f206b0e0ac84fc96c37f7ddf00 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 4 Apr 2024 23:21:28 -0700 Subject: [PATCH 191/262] WIP partial_decomposition --- src/sage/libs/cmr/cmr.pxd | 10 ++- src/sage/matrix/matrix_cmr_sparse.pyx | 95 +++++++++++++++++++++-- src/sage/matrix/seymour_decomposition.pyx | 51 ++++++++++++ 3 files changed, 150 insertions(+), 6 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 60258789332..dbecfcf9fbd 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -256,6 +256,7 @@ cdef extern from "cmr/matroid.h": size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + CMR_ERROR CMRmatroiddecCloneUnknown(CMR* cmr, CMR_MATROID_DEC* dec, CMR_MATROID_DEC** pclone) CMR_ERROR CMRmatroiddecCapture(CMR* cmr, CMR_MATROID_DEC* dec) CMR_ERROR CMRmatroiddecRelease(CMR* cmr, CMR_MATROID_DEC** pdec) @@ -371,11 +372,18 @@ cdef extern from "cmr/regular.h": const int CMR_DEC_CONSTRUCT_LEAVES const int CMR_DEC_CONSTRUCT_ALL + const int CMR_REGULAR_TREE_FLAGS_RECURSE + const int CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR + const int CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC + const int CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC + const int CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC + const int CMR_REGULAR_TREE_FLAGS_DEFAULT + ctypedef struct CMR_REGULAR_PARAMS: bint directGraphicness bint seriesParallel bint planarityCheck - bint completeTree + int treeFlags bool threeSumPivotChildren int threeSumStrategy CMR_DEC_CONSTRUCT graphs diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 0c83e45b51b..0b9602cb086 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1509,7 +1509,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='if_regular', + complete_tree='find_irregular', three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False, @@ -1523,7 +1523,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - - ``certificate``: One of ``False``, ``True``, ``'if_regular'``, ``'if_not_regular'`` + - ``certificate``: ``False`` or ``True`` + - ``complete_tree``: one of the following values + ``True`` - return the full decomposition node + ``False`` - return the decomposition node with only children (no grandchildren). + If the node type is not determined, return a UnknownNode. + ``'find_irregular'`` - return the decomposition node which only stops + when you find an irregular node + ``'find_nongraphic'`` - return the decomposition node which only stops + when you find a nongraphic node + ``'find_noncographic'`` - return the decomposition node which only stops + when you find a noncographic node + ``'find_nongraphic_and_noncographic'`` + - return the decomposition node which stops + when you find a nongraphic node and a noncographic node EXAMPLES:: @@ -1668,7 +1681,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='if_regular', + complete_tree='find_irregular', three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False, @@ -1730,6 +1743,64 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 1 1] [1 0 1] [1 1 0] + + This is test ``TreeFlagsNorecurse``, ``TreeFlagsStopNoncographic``, + and ``TreeFlagsStopNongraphic`` in CMR's ``test_regular.cpp``:: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree='if_not_regular') + sage: result, certificate + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree='if_not_graphic') + sage: result, certificate + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭──────OneSumNode (9×9) with 2 children──────╮ + │ │ + SubmatrixNode (5×4) UnknownNode (4×5) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree='if_not_cographic') + sage: result, certificate + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭──────OneSumNode (9×9) with 2 children──────╮ + │ │ + SubmatrixNode (5×4) SubmatrixNode (4×5) + │ │ + Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=4) + sage: result, certificate + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=8) + sage: result, certificate + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) """ base_ring = self.parent().base_ring() if base_ring.characteristic(): @@ -1784,7 +1855,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='if_regular', + complete_tree='find_irregular', construct_matrices=False, construct_transposes=False, construct_graphs=False, @@ -1806,7 +1877,6 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): params.directGraphicness = kwds['use_direct_graphicness_test'] params.seriesParallel = kwds['series_parallel_ok'] params.planarityCheck = kwds['check_graphic_minors_planar'] - params.completeTree = kwds['complete_tree'] is True params.threeSumPivotChildren = kwds['three_sum_pivot_children'] if kwds['three_sum_strategy'] is not None: if kwds['three_sum_strategy'] == 'Mixed_Mixed': @@ -1815,6 +1885,21 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE else: params.threeSumStrategy = kwds['three_sum_strategy'] + if kwds['complete_tree'] is not None: + if kwds['complete_tree'] is True: + params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE + elif kwds['complete_tree'] is False or kwds['complete_tree'] == 'no_recurse': + params.treeFlags = CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR + elif kwds['complete_tree'] == 'find_irregular': + params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR + elif kwds['complete_tree'] == 'find_nongraphic': + params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC + elif kwds['complete_tree'] == 'find_noncographic': + params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC + elif kwds['complete_tree'] == 'find_nongraphic_and_noncographic': + params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC + else: + params.treeFlags = kwds['complete_tree'] params.graphs = _cmr_dec_construct(kwds['construct_graphs']) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 65b8d7fa145..d71771979b5 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -502,6 +502,25 @@ cdef class DecompositionNode(SageObject): # compute it... wait for CMR functions raise NotImplementedError + def is_cographic(self, *, decomposition=False, **kwds): + r""" + + """ + certificate = kwds.get('certificate', False) + cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) + if cographicness: + result = cographicness == +1 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result + # compute it... wait for CMR functions + raise NotImplementedError + cdef class ThreeConnectedIrregularNode(DecompositionNode): @@ -582,6 +601,38 @@ cdef class UnknownNode(DecompositionNode): result.append(cert) return result + def is_cographic(self, *, decomposition=False, certificate=False, **kwds): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, -1, 0], [0, 1, -1]]); node + UnknownNode (2×3) + sage: node.matrix() + [ 1 -1 0] + [ 0 1 -1] + sage: node.is_cographic() + True + sage: result, certificate = node.is_cographic(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: forest_edges + ((1, 2), (7, 1), (12, 7)) + """ + matrix = self.matrix() + if not decomposition and not certificate: + return matrix.is_cographic(**kwds) + result, cert = matrix.is_cographic(certificate=True, + row_keys=self.row_keys(), + column_keys=self.column_keys(), **kwds) + result = [result] + if decomposition: + graph, forest_edges, coforest_edges = cert + node = CographicNode(matrix, graph, forest_edges, coforest_edges) + result.append(node) + if certificate: + result.append(cert) + return result + cdef class SumNode(DecompositionNode): r""" From 21006ae3d4d2d6e7ce90883002eedb06ed1d63ca Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 4 Apr 2024 23:22:47 -0700 Subject: [PATCH 192/262] WIP add test example --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 0b9602cb086..3aeaf83d7af 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1580,6 +1580,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ ThreeConnectedIrregularNode (3×4) sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + (False, (OneSumNode (6×14) with 2 children, NotImplemented)) + sage: unicode_art(certificate) + ╭───────────OneSumNode (6×14) with 2 children + │ │ + UnknownNode (3×7) UnknownNode (3×7) + sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) sage: result, certificate (False, (OneSumNode (6×14) with 2 children, NotImplemented)) From f62055a5dde9969dcb2e7eef2281eb8a037ff5cc Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 4 Apr 2024 23:42:43 -0700 Subject: [PATCH 193/262] WIP fix indeterminant case --- src/sage/matrix/matrix_cmr_sparse.pyx | 40 +++++++++------------------ 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 3aeaf83d7af..309234e425a 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1582,8 +1582,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=False) sage: result, certificate - (False, (OneSumNode (6×14) with 2 children, NotImplemented)) - sage: unicode_art(certificate) + ('Not Determined', (OneSumNode (6×14) with 2 children, NotImplemented)) + sage: unicode_art(certificate[0]) ╭───────────OneSumNode (6×14) with 2 children │ │ UnknownNode (3×7) UnknownNode (3×7) @@ -1651,7 +1651,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not GF2.has_coerce_map_from(base_ring): raise ValueError('not well-defined') - cdef bool result + cdef bool result_bool = False cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats cdef CMR_MATROID_DEC *dec = NULL @@ -1671,19 +1671,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): _set_cmr_regular_parameters(¶ms, kwds) sig_on() try: - CMR_CALL(CMRregularTest(cmr, self._mat, &result, pdec, pminor, + CMR_CALL(CMRregularTest(cmr, self._mat, &result_bool, pdec, pminor, ¶ms, &stats, time_limit)) finally: sig_off() + result = result_bool + if result == False and CMRmatroiddecRegularity(dec) == 0: + result = 'Not Determined' if not certificate: - return result - + return result node = create_DecompositionNode(dec, self, row_keys, column_keys) - if result: + if result == True: return True, node - return False, (node, NotImplemented) + return result, (node, NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, @@ -1766,7 +1768,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree='if_not_regular') + ....: certificate=True, complete_tree=False) sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -1774,7 +1776,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ │ UnknownNode (5×4) UnknownNode (4×5) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree='if_not_graphic') + ....: certificate=True, complete_tree='find_nongraphic') sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -1784,7 +1786,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ Isomorphic to a minor of |det| = 2 submatrix sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree='if_not_cographic') + ....: certificate=True, complete_tree='find_noncographic') sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -1793,22 +1795,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): SubmatrixNode (5×4) SubmatrixNode (4×5) │ │ Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix - sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=4) - sage: result, certificate - (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) - sage: unicode_art(certificate[0]) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) - sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=8) - sage: result, certificate - (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) - sage: unicode_art(certificate[0]) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) """ base_ring = self.parent().base_ring() if base_ring.characteristic(): From bd256b4d87644681b48e629092ea83b0218a6408 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 5 Apr 2024 00:03:21 -0700 Subject: [PATCH 194/262] fix doctests for partial decomposition --- src/sage/matrix/matrix_cmr_sparse.pyx | 32 ++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 309234e425a..988b216f020 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1582,8 +1582,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=False) sage: result, certificate - ('Not Determined', (OneSumNode (6×14) with 2 children, NotImplemented)) - sage: unicode_art(certificate[0]) + ('Not Determined', OneSumNode (6×14) with 2 children) + sage: unicode_art(certificate) ╭───────────OneSumNode (6×14) with 2 children │ │ UnknownNode (3×7) UnknownNode (3×7) @@ -1651,7 +1651,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not GF2.has_coerce_map_from(base_ring): raise ValueError('not well-defined') - cdef bool result_bool = False + cdef bool result_bool = True cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats cdef CMR_MATROID_DEC *dec = NULL @@ -1677,14 +1677,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() result = result_bool - if result == False and CMRmatroiddecRegularity(dec) == 0: + if result == True and CMRmatroiddecRegularity(dec) == 0: result = 'Not Determined' if not certificate: return result node = create_DecompositionNode(dec, self, row_keys, column_keys) - if result == True: - return True, node + if result != False: + return result, node return result, (node, NotImplemented) def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, @@ -1770,8 +1770,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, complete_tree=False) sage: result, certificate - (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) - sage: unicode_art(certificate[0]) + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) ╭───────────OneSumNode (9×9) with 2 children │ │ UnknownNode (5×4) UnknownNode (4×5) @@ -1800,7 +1800,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if base_ring.characteristic(): raise ValueError(f'only defined over characteristic 0, got {base_ring}') - cdef bool result + cdef bool result_bool = True cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats cdef CMR_MATROID_DEC *dec = NULL @@ -1824,18 +1824,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): _set_cmr_regular_parameters(¶ms.regular, kwds) sig_on() try: - CMR_CALL(CMRtuTest(cmr, self._mat, &result, pdec, psubmat, + CMR_CALL(CMRtuTest(cmr, self._mat, &result_bool, pdec, psubmat, ¶ms, &stats, time_limit)) finally: sig_off() + result = result_bool + if result == True and CMRmatroiddecRegularity(dec) == 0: + result = 'Not Determined' if not certificate: - return result - + return result node = create_DecompositionNode(dec, self, row_keys, column_keys) - if result: - return True, node + if result != False: + return result, node if submat == NULL: submat_tuple = None @@ -1843,7 +1845,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), tuple(submat.columns[i] for i in range(submat.numColumns))) - return False, (node, submat_tuple) + return result, (node, submat_tuple) def is_complement_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, From 37c855ee8913fab79d58b858afd31e2a05173a13 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Fri, 5 Apr 2024 00:13:09 -0700 Subject: [PATCH 195/262] fix is_cographic doctests --- src/sage/matrix/seymour_decomposition.pyx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d71771979b5..e8a5195018a 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -583,8 +583,14 @@ cdef class UnknownNode(DecompositionNode): True sage: result, certificate = node.is_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate - sage: forest_edges + sage: graph.vertices(sort=True) # the numbers have no meaning + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] + sage: forest_edges # indexed by rows of M ((1, 2), (7, 1), (12, 7)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (1, 12)) """ matrix = self.matrix() if not decomposition and not certificate: @@ -615,8 +621,14 @@ cdef class UnknownNode(DecompositionNode): True sage: result, certificate = node.is_cographic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate - sage: forest_edges - ((1, 2), (7, 1), (12, 7)) + sage: graph.vertices(sort=True) # the numbers have no meaning + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(1, 2), (1, 7), (1, 12), (2, 7), (7, 12)] + sage: forest_edges # indexed by rows of M + ((1, 2), (7, 1)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (1, 12), (1, 2)) """ matrix = self.matrix() if not decomposition and not certificate: From b909dbcbcf8008f6c5b8755edfa3184c0d0d9a1e Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 7 Apr 2024 21:57:13 -0700 Subject: [PATCH 196/262] add complete_decomposition --- src/sage/libs/cmr/cmr.pxd | 2 +- src/sage/matrix/matrix_cmr_sparse.pxd | 4 +- src/sage/matrix/matrix_cmr_sparse.pyx | 96 +++++++++++++++++++++-- src/sage/matrix/seymour_decomposition.pyx | 96 ++++++++++++++++++++++- 4 files changed, 187 insertions(+), 11 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index dbecfcf9fbd..503a82b73c4 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -440,7 +440,7 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRtuStatsInit(CMR_TU_STATS* stats) # CMR_ERROR CMRtuStatsPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) CMR_ERROR CMRtuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_MATROID_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) - CMR_ERROR CMRtuCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRtuCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) cdef extern from "cmr/equimodular.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index 0b8fa289a66..f4565bf5cda 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_GRAPH, CMR_GRAPH_EDGE, bool +from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_REGULAR_PARAMS, CMR_GRAPH, CMR_GRAPH_EDGE, bool from .matrix_sparse cimport Matrix_sparse @@ -22,6 +22,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): @staticmethod cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?, base_ring=?) +cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds) + cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys) cdef _sage_graph(CMR_GRAPH *graph) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 988b216f020..ade74c6989b 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1632,6 +1632,79 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ GraphicNode (4×4) + This is the example in tests ``TreeFlagsNorecurse``, + ``TreeFlagsStopNoncographic`` in CMR's ``test_regular.cpp``:: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, + ....: complete_tree='find_noncographic') + sage: result, certificate + (True, OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) CographicNode (4×5) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, + ....: check_graphic_minors_planar=True, + ....: complete_tree='find_noncographic') + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + + This is the same example, but tests stopping at nongraphic nodes:: + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, + ....: complete_tree='find_nongraphic') + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, + ....: check_graphic_minors_planar=True, + ....: complete_tree='find_nongraphic') + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: MT = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), M.transpose()) + sage: result, certificate = MT._is_binary_linear_matroid_regular( + ....: certificate=True, + ....: check_graphic_minors_planar=True, + ....: complete_tree='find_nongraphic') + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (4×5) UnknownNode (5×4) + Base ring check:: sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(5), 3, 2, sparse=True), @@ -1776,25 +1849,32 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ │ UnknownNode (5×4) UnknownNode (4×5) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree='find_nongraphic') + ....: certificate=True, + ....: complete_tree='find_noncographic') sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) ╭──────OneSumNode (9×9) with 2 children──────╮ │ │ - SubmatrixNode (5×4) UnknownNode (4×5) - │ - Isomorphic to a minor of |det| = 2 submatrix + SubmatrixNode (5×4) SubmatrixNode (4×5) + │ │ + Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix + sage: C1, C2 = certificate[0].child_nodes() + sage: C1.matrix().is_network_matrix() + sage: C2.matrix().is_network_matrix() sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree='find_noncographic') + ....: certificate=True, + ....: complete_tree='find_nongraphic') sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) ╭──────OneSumNode (9×9) with 2 children──────╮ │ │ - SubmatrixNode (5×4) SubmatrixNode (4×5) - │ │ - Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix + SubmatrixNode (5×4) UnknownNode (4×5) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: C1, C2 = certificate[0].child_nodes() + sage: C1.matrix().is_network_matrix() """ base_ring = self.parent().base_ring() if base_ring.characteristic(): diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index e8a5195018a..0f51010b52a 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -17,6 +17,8 @@ Seymour's decomposition of totally unimodular matrices and regular matroids from libc.stdint cimport SIZE_MAX +from cysignals.signals cimport sig_on, sig_off + from sage.libs.cmr.cmr cimport * from sage.misc.cachefunc import cached_method from sage.rings.integer cimport Integer @@ -24,7 +26,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject from .constructor import Matrix -from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph, _set_cmr_regular_parameters from .matrix_space import MatrixSpace @@ -645,6 +647,98 @@ cdef class UnknownNode(DecompositionNode): result.append(cert) return result + def complete_decomposition(self, *, time_limit=60.0, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='find_irregular', + three_sum_pivot_children=False, + three_sum_strategy=None, + construct_graphs=False,): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: C1, C2 = certificate.child_nodes() + sage: C11 = C1.complete_decomposition(complete_tree=False); C11 + SubmatrixNode (5×4) + sage: unicode_art(C11) + SubmatrixNode (5×4) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: C1.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C11.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C22 = C2.complete_decomposition(complete_tree=False); C22 + SubmatrixNode (4×5) + sage: unicode_art(C22) + SubmatrixNode (4×5) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: C2.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + sage: C22.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + """ + cdef CMR_TU_PARAMS params + cdef CMR_TU_STATS stats + cdef CMR_MATROID_DEC *clone = NULL + + cdef CMR_MATROID_DEC **pclone = &clone + + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + series_parallel_ok=series_parallel_ok, + check_graphic_minors_planar=check_graphic_minors_planar, + complete_tree=complete_tree, + three_sum_pivot_children=three_sum_pivot_children, + three_sum_strategy=three_sum_strategy, + construct_graphs=construct_graphs) + params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION + params.directCamion = False + _set_cmr_regular_parameters(¶ms.regular, kwds) + + sig_on() + try: + CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) + CMR_CALL(CMRtuCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) + finally: + sig_off() + node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) + return node + cdef class SumNode(DecompositionNode): r""" From 30f516ce57092197e675fc74c68da342c53696ce Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 7 Apr 2024 22:16:59 -0700 Subject: [PATCH 197/262] add is_conetwork_matrix --- src/sage/matrix/matrix_cmr_sparse.pyx | 74 +++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index ade74c6989b..e0cc7a09017 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1398,6 +1398,23 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 1 1 0 0 1 -1] sage: M.is_cographic() True + sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 1, 0], + ....: [1, 0, 1], + ....: [0, 1, 1]]); C3 + [1 1 0] + [1 0 1] + [0 1 1] + sage: result, certificate = C3.is_cographic(certificate=True) + sage: result + True + sage: graph, forest_edges, coforest_edges = certificate + sage: graph.edges(sort=True, labels=False) + [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] + sage: forest_edges + ((3, 2), (0, 3), (1, 3)) + sage: coforest_edges + ((2, 0), (2, 1), (0, 1)) """ base_ring = self.parent().base_ring() if base_ring.characteristic(): @@ -1501,9 +1518,58 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, NotImplemented # submatrix TBD - def is_dual_network_matrix(self, *, time_limit=60.0, certificate=False, + def is_conetwork_matrix(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): - raise NotImplementedError + r""" + EXAMPLES: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), + ....: [[1, 1, 0], + ....: [1, 0, 1], + ....: [0, 1, 1]]); C3 + [1 1 0] + [1 0 1] + [0 1 1] + sage: result, certificate = C3.is_conetwork_matrix(certificate=True) + sage: result + False + """ + base_ring = self.parent().base_ring() + if base_ring.characteristic(): + raise ValueError(f'only defined over characteristic 0, got {base_ring}') + + cdef bool result + cdef bool support_result + cdef CMR_GRAPH *digraph = NULL + cdef CMR_GRAPH_EDGE* forest_arcs = NULL + cdef CMR_GRAPH_EDGE* coforest_arcs = NULL + cdef bool* arcs_reversed = NULL + cdef CMR_SUBMAT* submatrix = NULL + cdef CMR_NETWORK_STATISTICS stats + + sig_on() + try: + if certificate: + CMR_CALL(CMRnetworkTestTranspose(cmr, self._mat, &result, &support_result, &digraph, &forest_arcs, + &coforest_arcs, &arcs_reversed, &submatrix, &stats, + time_limit)) + else: + CMR_CALL(CMRnetworkTestTranspose(cmr, self._mat, &result, &support_result, NULL, NULL, + NULL, NULL, NULL, &stats, time_limit)) + finally: + sig_off() + + if not certificate: + return result + + if result: + sage_digraph = _sage_digraph(digraph, arcs_reversed) + sage_forest_arcs = _sage_arcs(digraph, forest_arcs, arcs_reversed, self.nrows(), row_keys) + sage_coforest_arcs = _sage_arcs(digraph, coforest_arcs, arcs_reversed, self.ncols(), column_keys) + return True, (sage_digraph, sage_forest_arcs, sage_coforest_arcs) + + return False, NotImplemented # submatrix TBD def _is_binary_linear_matroid_regular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, @@ -1860,8 +1926,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ │ Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix sage: C1, C2 = certificate[0].child_nodes() - sage: C1.matrix().is_network_matrix() - sage: C2.matrix().is_network_matrix() + sage: C1.matrix().is_conetwork_matrix() + sage: C2.matrix().is_conetwork_matrix() sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, ....: complete_tree='find_nongraphic') From 9abf8d4d3480deecadd01a118d9e1c76cdd14403 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 7 Apr 2024 22:59:37 -0700 Subject: [PATCH 198/262] add not determined for graphic/cographic --- src/sage/matrix/matrix_cmr_sparse.pyx | 5 ---- src/sage/matrix/seymour_decomposition.pyx | 28 +++++++++++++++++++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e0cc7a09017..b004a4bfb5f 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1925,9 +1925,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): SubmatrixNode (5×4) SubmatrixNode (4×5) │ │ Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix - sage: C1, C2 = certificate[0].child_nodes() - sage: C1.matrix().is_conetwork_matrix() - sage: C2.matrix().is_conetwork_matrix() sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, ....: complete_tree='find_nongraphic') @@ -1939,8 +1936,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): SubmatrixNode (5×4) UnknownNode (4×5) │ Isomorphic to a minor of |det| = 2 submatrix - sage: C1, C2 = certificate[0].child_nodes() - sage: C1.matrix().is_network_matrix() """ base_ring = self.parent().base_ring() if base_ring.characteristic(): diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 0f51010b52a..b9e01b71e48 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -502,7 +502,9 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return result # compute it... wait for CMR functions - raise NotImplementedError + if decomposition: + raise NotImplementedError + return "Graphic/Network Not Determined" def is_cographic(self, *, decomposition=False, **kwds): r""" @@ -521,7 +523,29 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return result # compute it... wait for CMR functions - raise NotImplementedError + if decomposition: + raise NotImplementedError + return "Cographic/Conetwork Not Determined" + + def is_regular(self, *, decomposition=False, **kwds): + r""" + + """ + certificate = kwds.get('certificate', False) + cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) + if regularity: + result = regularity > 0 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result + if decomposition: + raise NotImplementedError + return "Regular/TU Not Determined" cdef class ThreeConnectedIrregularNode(DecompositionNode): From b48faf07ec9b3c6dd447de7064bc191029b1108c Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 11 Apr 2024 12:30:33 -0700 Subject: [PATCH 199/262] WIP change is_graphic to _is_binary_linear_matroid_graphic --- src/sage/matrix/matrix_cmr_sparse.pyx | 20 +- src/sage/matrix/seymour_decomposition.pyx | 315 +++++++++++++++------- 2 files changed, 238 insertions(+), 97 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b004a4bfb5f..4ac20dce881 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1288,9 +1288,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return True if result else False - def is_graphic(self, *, time_limit=60.0, decomposition=False, certificate=False, + def _is_binary_linear_matroid_graphic(self, *, time_limit=60.0, decomposition=False, certificate=False, row_keys=None, column_keys=None): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is graphic. + + This is an internal method because it should really be exposed + as a method of :class:`Matroid`. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1301,7 +1306,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 -1] sage: M.is_graphic() True - sage: result, certificate = M.is_graphic(certificate=True) + sage: result, certificate = M._is_binary_linear_matroid_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate sage: graph.vertices(sort=True) # the numbers have no meaning [1, 2, 7, 12] @@ -1381,9 +1386,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): result.append(NotImplemented) # submatrix TBD return result - def is_cographic(self, *, time_limit=60.0, certificate=False, + def _is_binary_linear_matroid_cographic(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is cographic. + + This is an internal method because it should really be exposed + as a method of :class:`Matroid`. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1396,7 +1406,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 1 0 0 0 1 -1 1 0] [ 0 0 1 0 0 0 1 -1 1] [ 0 0 0 1 1 0 0 1 -1] - sage: M.is_cographic() + sage: M._is_binary_linear_matroid_cographic() True sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), ....: [[1, 1, 0], @@ -1405,7 +1415,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 1 0] [1 0 1] [0 1 1] - sage: result, certificate = C3.is_cographic(certificate=True) + sage: result, certificate = C3._is_binary_linear_matroid_cographic(certificate=True) sage: result True sage: graph, forest_edges, coforest_edges = certificate diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index b9e01b71e48..fccecbf3a84 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -485,6 +485,24 @@ cdef class DecompositionNode(SageObject): result._column_keys = column_keys return result + def _regularity(self): + cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) + if regularity: + return regularity > 0 + raise ValueError('It is not determined whether the decomposition node is regular/TU') + + def _graphicness(self): + cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) + if graphicness: + return graphicness > 0 + raise ValueError('It is not determined whether the decomposition node is graphic/network') + + def _cographicness(self): + cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) + if cographicness: + return cographicness > 0 + raise ValueError('It is not determined whether the decomposition node is cographic/conetwork') + def is_graphic(self, *, decomposition=False, **kwds): r""" @@ -547,6 +565,185 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return "Regular/TU Not Determined" + def _binary_linear_matroid_complete_decomposition(self, *, + time_limit=60.0, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='find_irregular', + three_sum_pivot_children=False, + three_sum_strategy=None, + construct_graphs=False): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M._is_binary_linear_matroid_regular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: C1, C2 = certificate.child_nodes() + sage: C11 = C1._binary_linear_matroid_complete_decomposition(complete_tree=False); C11 + GraphicNode (5×4) + sage: unicode_art(C11) + GraphicNode (5×4) + sage: C1.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C11.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C22 = C2._binary_linear_matroid_complete_decomposition(complete_tree=False); C22 + CographicNode (4×5) + sage: unicode_art(C22) + CographicNode (4×5) + sage: C2.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + sage: C22.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + """ + cdef CMR_REGULAR_PARAMS params + cdef CMR_REGULAR_STATS stats + cdef CMR_MATROID_DEC *clone = NULL + + cdef CMR_MATROID_DEC **pclone = &clone + + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + series_parallel_ok=series_parallel_ok, + check_graphic_minors_planar=check_graphic_minors_planar, + complete_tree=complete_tree, + three_sum_pivot_children=three_sum_pivot_children, + three_sum_strategy=three_sum_strategy, + construct_graphs=construct_graphs) + _set_cmr_regular_parameters(¶ms, kwds) + + sig_on() + try: + CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) + CMR_CALL(CMRregularCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) + finally: + sig_off() + node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) + return node + + def complete_decomposition(self, *, time_limit=60.0, + use_direct_graphicness_test=True, + series_parallel_ok=True, + check_graphic_minors_planar=False, + complete_tree='find_irregular', + three_sum_pivot_children=False, + three_sum_strategy=None, + construct_graphs=False): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: C1, C2 = certificate.child_nodes() + sage: C11 = C1.complete_decomposition(complete_tree=False); C11 + SubmatrixNode (5×4) + sage: unicode_art(C11) + SubmatrixNode (5×4) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: C1.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C11.matrix() + [1 1 0 0] + [1 1 1 0] + [0 1 1 1] + [1 0 0 1] + [0 0 1 1] + sage: C22 = C2.complete_decomposition(complete_tree=False); C22 + SubmatrixNode (4×5) + sage: unicode_art(C22) + SubmatrixNode (4×5) + │ + Isomorphic to a minor of |det| = 2 submatrix + sage: C2.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + sage: C22.matrix() + [1 1 1 0 0] + [0 0 1 1 1] + [0 1 0 1 1] + [1 1 0 1 0] + """ + cdef CMR_TU_PARAMS params + cdef CMR_TU_STATS stats + cdef CMR_MATROID_DEC *clone = NULL + + cdef CMR_MATROID_DEC **pclone = &clone + + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + series_parallel_ok=series_parallel_ok, + check_graphic_minors_planar=check_graphic_minors_planar, + complete_tree=complete_tree, + three_sum_pivot_children=three_sum_pivot_children, + three_sum_strategy=three_sum_strategy, + construct_graphs=construct_graphs) + params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION + params.directCamion = False + _set_cmr_regular_parameters(¶ms.regular, kwds) + + sig_on() + try: + CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) + CMR_CALL(CMRtuCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) + finally: + sig_off() + node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) + return node + cdef class ThreeConnectedIrregularNode(DecompositionNode): @@ -671,98 +868,6 @@ cdef class UnknownNode(DecompositionNode): result.append(cert) return result - def complete_decomposition(self, *, time_limit=60.0, - use_direct_graphicness_test=True, - series_parallel_ok=True, - check_graphic_minors_planar=False, - complete_tree='find_irregular', - three_sum_pivot_children=False, - three_sum_strategy=None, - construct_graphs=False,): - r""" - EXAMPLES:: - - sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), - ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], - ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], - ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], - ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], - ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], - ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], - ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], - ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) - sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=False) - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) - sage: C1, C2 = certificate.child_nodes() - sage: C11 = C1.complete_decomposition(complete_tree=False); C11 - SubmatrixNode (5×4) - sage: unicode_art(C11) - SubmatrixNode (5×4) - │ - Isomorphic to a minor of |det| = 2 submatrix - sage: C1.matrix() - [1 1 0 0] - [1 1 1 0] - [0 1 1 1] - [1 0 0 1] - [0 0 1 1] - sage: C11.matrix() - [1 1 0 0] - [1 1 1 0] - [0 1 1 1] - [1 0 0 1] - [0 0 1 1] - sage: C22 = C2.complete_decomposition(complete_tree=False); C22 - SubmatrixNode (4×5) - sage: unicode_art(C22) - SubmatrixNode (4×5) - │ - Isomorphic to a minor of |det| = 2 submatrix - sage: C2.matrix() - [1 1 1 0 0] - [0 0 1 1 1] - [0 1 0 1 1] - [1 1 0 1 0] - sage: C22.matrix() - [1 1 1 0 0] - [0 0 1 1 1] - [0 1 0 1 1] - [1 1 0 1 0] - """ - cdef CMR_TU_PARAMS params - cdef CMR_TU_STATS stats - cdef CMR_MATROID_DEC *clone = NULL - - cdef CMR_MATROID_DEC **pclone = &clone - - cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, - series_parallel_ok=series_parallel_ok, - check_graphic_minors_planar=check_graphic_minors_planar, - complete_tree=complete_tree, - three_sum_pivot_children=three_sum_pivot_children, - three_sum_strategy=three_sum_strategy, - construct_graphs=construct_graphs) - params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION - params.directCamion = False - _set_cmr_regular_parameters(¶ms.regular, kwds) - - sig_on() - try: - CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) - CMR_CALL(CMRtuCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) - finally: - sig_off() - node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) - return node - cdef class SumNode(DecompositionNode): r""" @@ -1028,6 +1133,32 @@ cdef class ThreeSumNode(SumNode): [-1 -1 0 0 1] sage: C.child_indices() (((0, 1, a, 3), (b, c, d, e, +3+e)), ((0, 2, 3, 5), (+0+d, d, 4, e, f))) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: complete_tree=False, + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(6), + ....: column_keys='abcdef') + sage: result, certificate + ('Not Determined', PivotsNode (6×6)) + sage: unicode_art(certificate) + PivotsNode (6×6) + │ + ╭──────────ThreeSumNode (6×6) with 2 children + │ │ + UnknownNode (4×5) UnknownNode (4×5) + sage: unicode_art(certificate.complete_decomposition(complete_tree=True, + ....: three_sum_strategy="Wide_Wide")) + PivotsNode (6×6) + │ + ╭─────────────ThreeSumNode (6×6) with 2 children + │ │ + CographicNode (4×5) GraphicNode (4×5) + sage: unicode_art(certificate) + PivotsNode (6×6) + │ + ╭──────────ThreeSumNode (6×6) with 2 children + │ │ + UnknownNode (4×5) UnknownNode (4×5) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), From 9e2d7758cb3cc304d1a567b0c9a6c2e45995680d Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 11 Apr 2024 12:39:36 -0700 Subject: [PATCH 200/262] WIP change the reference to _is_binary_linear_matroid --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 +++---- src/sage/matrix/seymour_decomposition.pyx | 26 +++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4ac20dce881..4061c7bb353 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1304,7 +1304,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 1 0] [-1 1] [ 0 -1] - sage: M.is_graphic() + sage: M._is_binary_linear_matroid_graphic() True sage: result, certificate = M._is_binary_linear_matroid_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate @@ -1319,7 +1319,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): With keys:: - sage: result, certificate = M.is_graphic(certificate=True, + sage: result, certificate = M._is_binary_linear_matroid_graphic(certificate=True, ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) sage: graph, forest_edges, coforest_edges = certificate sage: forest_edges @@ -1329,14 +1329,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): Creating a decomposition node:: - sage: result, node = M.is_graphic(decomposition=True, + sage: result, node = M._is_binary_linear_matroid_graphic(decomposition=True, ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) sage: result, node (True, GraphicNode (3×2)) TESTS:: - sage: M.is_graphic(time_limit=0.0) + sage: M._is_binary_linear_matroid_graphic(time_limit=0.0) Traceback (most recent call last): ... RuntimeError: Time limit exceeded diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index fccecbf3a84..ff99bb53783 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -503,7 +503,7 @@ cdef class DecompositionNode(SageObject): return cographicness > 0 raise ValueError('It is not determined whether the decomposition node is cographic/conetwork') - def is_graphic(self, *, decomposition=False, **kwds): + def _is_binary_linear_matroid_graphic(self, *, decomposition=False, **kwds): r""" """ @@ -524,7 +524,7 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return "Graphic/Network Not Determined" - def is_cographic(self, *, decomposition=False, **kwds): + def _is_binary_linear_matroid_cographic(self, *, decomposition=False, **kwds): r""" """ @@ -791,7 +791,7 @@ cdef class UnknownNode(DecompositionNode): [0 1 1] """ - def is_graphic(self, *, decomposition=False, certificate=False, **kwds): + def _is_binary_linear_matroid_graphic(self, *, decomposition=False, certificate=False, **kwds): r""" EXAMPLES:: @@ -802,9 +802,9 @@ cdef class UnknownNode(DecompositionNode): [ 1 0] [-1 1] [ 0 -1] - sage: node.is_graphic() + sage: node._is_binary_linear_matroid_graphic() True - sage: result, certificate = node.is_graphic(certificate=True) + sage: result, certificate = node._is_binary_linear_matroid_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate sage: graph.vertices(sort=True) # the numbers have no meaning [1, 2, 7, 12] @@ -817,8 +817,8 @@ cdef class UnknownNode(DecompositionNode): """ matrix = self.matrix() if not decomposition and not certificate: - return matrix.is_graphic(**kwds) - result, cert = matrix.is_graphic(certificate=True, + return matrix._is_binary_linear_matroid_graphic(**kwds) + result, cert = matrix._is_binary_linear_matroid_graphic(certificate=True, row_keys=self.row_keys(), column_keys=self.column_keys(), **kwds) result = [result] @@ -830,7 +830,7 @@ cdef class UnknownNode(DecompositionNode): result.append(cert) return result - def is_cographic(self, *, decomposition=False, certificate=False, **kwds): + def _is_binary_linear_matroid_cographic(self, *, decomposition=False, certificate=False, **kwds): r""" EXAMPLES:: @@ -840,9 +840,9 @@ cdef class UnknownNode(DecompositionNode): sage: node.matrix() [ 1 -1 0] [ 0 1 -1] - sage: node.is_cographic() + sage: node._is_binary_linear_matroid_cographic() True - sage: result, certificate = node.is_cographic(certificate=True) + sage: result, certificate = node._is_binary_linear_matroid_cographic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate sage: graph.vertices(sort=True) # the numbers have no meaning [1, 2, 7, 12] @@ -855,8 +855,8 @@ cdef class UnknownNode(DecompositionNode): """ matrix = self.matrix() if not decomposition and not certificate: - return matrix.is_cographic(**kwds) - result, cert = matrix.is_cographic(certificate=True, + return matrix._is_binary_linear_matroid_cographic(**kwds) + result, cert = matrix._is_binary_linear_matroid_cographic(certificate=True, row_keys=self.row_keys(), column_keys=self.column_keys(), **kwds) result = [result] @@ -1533,7 +1533,7 @@ cdef class BaseGraphicNode(DecompositionNode): b⎜-1 1⎟ c⎝ 0 1⎠ sage: phi_node = UnknownNode(phi) - sage: is_graphic, rephined_node = phi_node.is_graphic(decomposition=True) + sage: is_graphic, rephined_node = phi_node._is_binary_linear_matroid_graphic(decomposition=True) sage: is_graphic, rephined_node (True, GraphicNode (3×2)) sage: rephined_node.forest_edges() From 2128343df5b083f8832bfaabc3db8165f0cf338f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 11 Apr 2024 15:14:53 -0700 Subject: [PATCH 201/262] WIP add is_network_matrix --- src/sage/matrix/matrix_cmr_sparse.pyx | 34 +++++ src/sage/matrix/seymour_decomposition.pyx | 153 ++++++++++++++++++++-- 2 files changed, 177 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4061c7bb353..9937ea32e98 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1464,6 +1464,27 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" EXAMPLES: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, -1]]); M + [ 1 0] + [-1 1] + [ 0 -1] + sage: M.is_network_matrix() + True + sage: result, certificate = M.is_network_matrix(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: graph + Digraph on 4 vertices + sage: graph.vertices(sort=True) # the numbers have no meaning + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(2, 1), (2, 7), (7, 1), (7, 12), (12, 1)] + sage: forest_edges # indexed by rows of M + ((2, 1), (7, 1), (7, 12)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (12, 1)) + This is test ``Basic`` in CMR's ``test_network.cpp``:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1533,6 +1554,19 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): r""" EXAMPLES: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 9, sparse=True), + ....: [[1, 0, 0, 0, 1, -1, 1, 0, 0], + ....: [0, 1, 0, 0, 0, 1, -1, 1, 0], + ....: [0, 0, 1, 0, 0, 0, 1, -1, 1], + ....: [0, 0, 0, 1, 1, 0, 0, 1, -1]]); M + [ 1 0 0 0 1 -1 1 0 0] + [ 0 1 0 0 0 1 -1 1 0] + [ 0 0 1 0 0 0 1 -1 1] + [ 0 0 0 1 1 0 0 1 -1] + sage: M.is_conetwork_matrix() + True + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), ....: [[1, 1, 0], diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ff99bb53783..6037ea2ef4a 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -520,9 +520,7 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return result # compute it... wait for CMR functions - if decomposition: - raise NotImplementedError - return "Graphic/Network Not Determined" + raise NotImplementedError("Graphic Not Determined") def _is_binary_linear_matroid_cographic(self, *, decomposition=False, **kwds): r""" @@ -541,11 +539,9 @@ cdef class DecompositionNode(SageObject): raise NotImplementedError return result # compute it... wait for CMR functions - if decomposition: - raise NotImplementedError - return "Cographic/Conetwork Not Determined" + raise NotImplementedError("Cographic Not Determined") - def is_regular(self, *, decomposition=False, **kwds): + def _is_binary_linear_matroid_regular(self, *, decomposition=False, **kwds): r""" """ @@ -561,9 +557,8 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - if decomposition: - raise NotImplementedError - return "Regular/TU Not Determined" + # compute it... wait for CMR functions + raise NotImplementedError("Regularity Not Determined") def _binary_linear_matroid_complete_decomposition(self, *, time_limit=60.0, @@ -652,6 +647,63 @@ cdef class DecompositionNode(SageObject): node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) return node + def is_network_matrix(self, *, decomposition=False, **kwds): + r""" + + """ + certificate = kwds.get('certificate', False) + cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) + if graphicness: + result = graphicness == +1 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result + # compute it... wait for CMR functions + raise NotImplementedError("Network Not Determined") + + def is_conetwork_matrix(self, *, decomposition=False, **kwds): + r""" + + """ + certificate = kwds.get('certificate', False) + cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) + if cographicness: + result = cographicness == +1 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result + # compute it... wait for CMR functions + raise NotImplementedError("Conetwork Not Determined") + + def is_totally_unimodular(self, *, decomposition=False, **kwds): + r""" + + """ + certificate = kwds.get('certificate', False) + cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) + if regularity: + result = regularity > 0 + if not decomposition and not certificate: + return result + result = [result] + if decomposition: + result.append(self) + if certificate: + raise NotImplementedError + return result + # compute it... wait for CMR functions + raise NotImplementedError("TU Not Determined") + def complete_decomposition(self, *, time_limit=60.0, use_direct_graphicness_test=True, series_parallel_ok=True, @@ -868,6 +920,87 @@ cdef class UnknownNode(DecompositionNode): result.append(cert) return result + def is_network_matrix(self, *, decomposition=False, certificate=False, **kwds): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 0], [-1, 1], [0, -1]]); node + UnknownNode (3×2) + sage: node.matrix() + [ 1 0] + [-1 1] + [ 0 -1] + sage: node.is_network_matrix() + True + sage: result, certificate = node.is_network_matrix(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: graph + Digraph on 4 vertices + sage: graph.vertices(sort=True) # the numbers have no meaning + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(2, 1), (2, 7), (7, 1), (7, 12), (12, 1)] + sage: forest_edges # indexed by rows of M + ((2, 1), (7, 1), (7, 12)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (12, 1)) + """ + matrix = self.matrix() + if not decomposition and not certificate: + return matrix.is_network_matrix(**kwds) + result, cert = matrix.is_network_matrix(certificate=True, + row_keys=self.row_keys(), + column_keys=self.column_keys(), **kwds) + result = [result] + if decomposition: + graph, forest_edges, coforest_edges = cert + node = GraphicNode(matrix, graph, forest_edges, coforest_edges) + result.append(node) + if certificate: + result.append(cert) + return result + + def is_conetwork_matrix(self, *, decomposition=False, certificate=False, **kwds): + r""" + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, -1, 0], [0, 1, -1]]); node + UnknownNode (2×3) + sage: node.matrix() + [ 1 -1 0] + [ 0 1 -1] + sage: node.is_conetwork_matrix() + True + sage: result, certificate = node.is_conetwork_matrix(certificate=True) + sage: graph, forest_edges, coforest_edges = certificate + sage: graph + Digraph on 4 vertices + sage: graph.vertices(sort=True) # the numbers have no meaning + [1, 2, 7, 12] + sage: graph.edges(sort=True, labels=False) + [(2, 1), (2, 7), (7, 1), (7, 12), (12, 1)] + sage: forest_edges # indexed by rows of M + ((2, 1), (7, 1)) + sage: coforest_edges # indexed by cols of M + ((2, 7), (12, 1), (2, 1)) + """ + matrix = self.matrix() + if not decomposition and not certificate: + return matrix.is_conetwork_matrix(**kwds) + result, cert = matrix.is_conetwork_matrix(certificate=True, + row_keys=self.row_keys(), + column_keys=self.column_keys(), **kwds) + result = [result] + if decomposition: + graph, forest_edges, coforest_edges = cert + node = CographicNode(matrix, graph, forest_edges, coforest_edges) + result.append(node) + if certificate: + result.append(cert) + return result + cdef class SumNode(DecompositionNode): r""" From 7111e1bbef103a20add0b3c1045d02033bb95d98 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 23 Apr 2024 11:14:45 -0700 Subject: [PATCH 202/262] add doctests and use try except --- src/sage/matrix/matrix_cmr_sparse.pyx | 57 +++++++++++++++++++++ src/sage/matrix/seymour_decomposition.pyx | 60 +++++++++++------------ 2 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 9937ea32e98..1e1e3ff35d8 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1485,6 +1485,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: coforest_edges # indexed by cols of M ((2, 7), (12, 1)) + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: K33 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 4, sparse=True), + ....: [[-1, -1, -1, -1], + ....: [ 1, 1, 0, 0], + ....: [ 0, 0, 1, 1], + ....: [ 1, 0, 1, 0], + ....: [ 0, 1, 0, 1]]); K33 + [-1 -1 -1 -1] + [ 1 1 0 0] + [ 0 0 1 1] + [ 1 0 1 0] + [ 0 1 0 1] + sage: K33.is_network_matrix() + True + This is test ``Basic`` in CMR's ``test_network.cpp``:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1567,6 +1582,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: M.is_conetwork_matrix() True + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: K33 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 4, sparse=True), + ....: [[-1, -1, -1, -1], + ....: [ 1, 1, 0, 0], + ....: [ 0, 0, 1, 1], + ....: [ 1, 0, 1, 0], + ....: [ 0, 1, 0, 1]]); K33 + [-1 -1 -1 -1] + [ 1 1 0 0] + [ 0 0 1 1] + [ 1 0 1 0] + [ 0 1 0 1] + sage: K33.is_conetwork_matrix() + False + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), ....: [[1, 1, 0], @@ -1937,6 +1967,33 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [1 1 0] + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[-1,-1,-1,-1, 0, 0, 0, 0, 0], + ....: [1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [1, 0, 1, 0, 0, 0, 0, 0, 0], + ....: [0, 1, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0,-1, 1, 0, 1, 0], + ....: [0, 0, 0, 0,-1, 1, 0, 0, 1], + ....: [0, 0, 0, 0,-1, 0, 1, 1, 0], + ....: [0, 0, 0, 0,-1, 0, 1, 0, 1]]) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=False) + sage: result, certificate + ('Not Determined', OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + UnknownNode (5×4) UnknownNode (4×5) + sage: result, certificate = M.is_totally_unimodular( + ....: certificate=True, complete_tree=True) + sage: result, certificate + (True, OneSumNode (9×9) with 2 children) + sage: unicode_art(certificate) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) CographicNode (4×5) + This is test ``TreeFlagsNorecurse``, ``TreeFlagsStopNoncographic``, and ``TreeFlagsStopNongraphic`` in CMR's ``test_regular.cpp``:: diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 6037ea2ef4a..ab806c3d3be 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -508,9 +508,8 @@ cdef class DecompositionNode(SageObject): """ certificate = kwds.get('certificate', False) - cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) - if graphicness: - result = graphicness == +1 + try: + result = self._graphicness() if not decomposition and not certificate: return result result = [result] @@ -519,17 +518,17 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("Graphic Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("Graphic Not Determined") def _is_binary_linear_matroid_cographic(self, *, decomposition=False, **kwds): r""" """ certificate = kwds.get('certificate', False) - cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) - if cographicness: - result = cographicness == +1 + try: + result = self._cographicness() if not decomposition and not certificate: return result result = [result] @@ -538,17 +537,17 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("Cographic Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("Cographic Not Determined") def _is_binary_linear_matroid_regular(self, *, decomposition=False, **kwds): r""" """ certificate = kwds.get('certificate', False) - cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) - if regularity: - result = regularity > 0 + try: + result = self._regularity() if not decomposition and not certificate: return result result = [result] @@ -557,8 +556,9 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("Regularity Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("Regularity Not Determined") def _binary_linear_matroid_complete_decomposition(self, *, time_limit=60.0, @@ -652,9 +652,8 @@ cdef class DecompositionNode(SageObject): """ certificate = kwds.get('certificate', False) - cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) - if graphicness: - result = graphicness == +1 + try: + result = self._graphicness() if not decomposition and not certificate: return result result = [result] @@ -663,17 +662,17 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("Network Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("Network Not Determined") def is_conetwork_matrix(self, *, decomposition=False, **kwds): r""" """ certificate = kwds.get('certificate', False) - cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) - if cographicness: - result = cographicness == +1 + try: + result = self._cographicness() if not decomposition and not certificate: return result result = [result] @@ -682,17 +681,17 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("Conetwork Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("Conetwork Not Determined") def is_totally_unimodular(self, *, decomposition=False, **kwds): r""" """ certificate = kwds.get('certificate', False) - cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) - if regularity: - result = regularity > 0 + try: + result = self._regularity() if not decomposition and not certificate: return result result = [result] @@ -701,8 +700,9 @@ cdef class DecompositionNode(SageObject): if certificate: raise NotImplementedError return result - # compute it... wait for CMR functions - raise NotImplementedError("TU Not Determined") + except ValueError: + # compute it... wait for CMR functions + raise NotImplementedError("TU Not Determined") def complete_decomposition(self, *, time_limit=60.0, use_direct_graphicness_test=True, From 72d777993bda348e839624aea631568bf06d5b64 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 23 Apr 2024 12:17:42 -0700 Subject: [PATCH 203/262] change base_ring check for binary matroid --- src/sage/matrix/matrix_cmr_sparse.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1e1e3ff35d8..fff2d975184 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1342,8 +1342,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): RuntimeError: Time limit exceeded """ base_ring = self.parent().base_ring() - if base_ring.characteristic(): - raise ValueError(f'only defined over characteristic 0, got {base_ring}') + from sage.rings.finite_rings.finite_field_constructor import GF + GF2 = GF(2) + if not GF2.has_coerce_map_from(base_ring): + raise ValueError('not well-defined') cdef bool result_bool cdef CMR_GRAPH *graph = NULL @@ -1427,8 +1429,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ((2, 0), (2, 1), (0, 1)) """ base_ring = self.parent().base_ring() - if base_ring.characteristic(): - raise ValueError(f'only defined over characteristic 0, got {base_ring}') + from sage.rings.finite_rings.finite_field_constructor import GF + GF2 = GF(2) + if not GF2.has_coerce_map_from(base_ring): + raise ValueError('not well-defined') cdef bool result cdef CMR_GRAPH *graph = NULL From d1f17bd4913af01926b59cc6e257fbe9dd023b39 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 23 Apr 2024 12:19:51 -0700 Subject: [PATCH 204/262] build/pkgs/cmr: Update to edd64258cacab23fe170006bc32f429621652bf0 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 2fd92210e76..2cc45f82ea3 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=e3d1892eddcde50e47389fe75eb4ab8b02181e21 -md5=22388e0e3c68d535e11218a3a13eb2b3 -cksum=2117523128 +sha1=37715f6d8923aa266354b44dbe5265543faaf882 +md5=3e7681d1569395fea165832734753598 +cksum=1901556332 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 7a47e8733e1..cad3c28eb3d 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -c2c1b7dc2d0adf90ae836fd8776ad14c194afea1 +edd64258cacab23fe170006bc32f429621652bf0 From 789772b95e908b463c7569703a368077cd31ffb4 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 24 Apr 2024 15:04:36 -0700 Subject: [PATCH 205/262] add methods to set root decomposition node and finish complete decomposition for binary matroid and matrix --- src/sage/libs/cmr/cmr.pxd | 1 + src/sage/matrix/matrix_cmr_sparse.pyx | 153 +++++++++------------- src/sage/matrix/seymour_decomposition.pxd | 1 + src/sage/matrix/seymour_decomposition.pyx | 73 +++++++---- 4 files changed, 116 insertions(+), 112 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 503a82b73c4..5d864ee27f9 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -259,6 +259,7 @@ cdef extern from "cmr/matroid.h": CMR_ERROR CMRmatroiddecCloneUnknown(CMR* cmr, CMR_MATROID_DEC* dec, CMR_MATROID_DEC** pclone) CMR_ERROR CMRmatroiddecCapture(CMR* cmr, CMR_MATROID_DEC* dec) CMR_ERROR CMRmatroiddecRelease(CMR* cmr, CMR_MATROID_DEC** pdec) + CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) cdef extern from "cmr/separation.h": diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index fff2d975184..507a7129fb1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1669,18 +1669,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``certificate``: ``False`` or ``True`` - ``complete_tree``: one of the following values - ``True`` - return the full decomposition node - ``False`` - return the decomposition node with only children (no grandchildren). - If the node type is not determined, return a UnknownNode. - ``'find_irregular'`` - return the decomposition node which only stops - when you find an irregular node - ``'find_nongraphic'`` - return the decomposition node which only stops - when you find a nongraphic node - ``'find_noncographic'`` - return the decomposition node which only stops - when you find a noncographic node - ``'find_nongraphic_and_noncographic'`` - - return the decomposition node which stops - when you find a nongraphic node and a noncographic node + ``True`` - return the node with full decomposition + ``'find_irregular'`` or ``False`` + - return the node when the decomposition detects + an irregular node EXAMPLES:: @@ -1726,11 +1718,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=False) sage: result, certificate - ('Not Determined', OneSumNode (6×14) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (6×14) with 2 children - │ │ - UnknownNode (3×7) UnknownNode (3×7) + (False, (OneSumNode (6×14) with 2 children, NotImplemented)) + sage: unicode_art(certificate[0]) + ╭OneSumNode (6×14) with 2 children╮ + │ │ + SeriesParallelReductionNode (3×7) UnknownNode (3×7) + │ + ThreeConnectedIrregularNode (3×4) sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=True) sage: result, certificate @@ -1792,15 +1786,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M._is_binary_linear_matroid_regular( ....: certificate=True, complete_tree=False) sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, - ....: complete_tree='find_noncographic') - sage: result, certificate (True, OneSumNode (9×9) with 2 children) sage: unicode_art(certificate) ╭───────────OneSumNode (9×9) with 2 children @@ -1808,46 +1793,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): GraphicNode (5×4) CographicNode (4×5) sage: result, certificate = M._is_binary_linear_matroid_regular( ....: certificate=True, - ....: check_graphic_minors_planar=True, ....: complete_tree='find_noncographic') - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - GraphicNode (5×4) UnknownNode (4×5) - - This is the same example, but tests stopping at nongraphic nodes:: - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, - ....: complete_tree='find_nongraphic') - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - GraphicNode (5×4) UnknownNode (4×5) - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, - ....: check_graphic_minors_planar=True, - ....: complete_tree='find_nongraphic') - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - GraphicNode (5×4) UnknownNode (4×5) - sage: MT = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), M.transpose()) - sage: result, certificate = MT._is_binary_linear_matroid_regular( - ....: certificate=True, - ....: check_graphic_minors_planar=True, - ....: complete_tree='find_nongraphic') - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (4×5) UnknownNode (5×4) + Traceback (most recent call last): + ... + ValueError: Unknown complete tree parameter find_noncographic + either stop when an irregular child is found + or return the full complete tree Base ring check:: @@ -1868,7 +1819,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not GF2.has_coerce_map_from(base_ring): raise ValueError('not well-defined') - cdef bool result_bool = True + if complete_tree not in ["find_irregular", False, True]: + raise ValueError(f'Unknown complete tree parameter {complete_tree} ' + f'either stop when an irregular child is found ' + f'or return the full complete tree') + if complete_tree == False: + complete_tree = "find_irregular" + + cdef bool result_bool cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats cdef CMR_MATROID_DEC *dec = NULL @@ -1894,13 +1852,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() result = result_bool - if result == True and CMRmatroiddecRegularity(dec) == 0: - result = 'Not Determined' if not certificate: return result node = create_DecompositionNode(dec, self, row_keys, column_keys) - if result != False: + if result: return result, node return result, (node, NotImplemented) @@ -1923,6 +1879,15 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - [Sch1986]_, Chapter 19 + INPUT: + + - ``certificate``: ``False`` or ``True`` + - ``complete_tree``: one of the following values + ``True`` - return the node with full decomposition + ``'find_irregular'`` or ``False`` + - return the node when the decomposition detects + a not totally unimodular node + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1971,6 +1936,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1] [1 1 0] + If the matrix is totally unimodular, it always returns + a full decomposition as a certificate:: sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), ....: [[-1,-1,-1,-1, 0, 0, 0, 0, 0], ....: [1, 1, 0, 0, 0, 0, 0, 0, 0], @@ -1984,11 +1951,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, complete_tree=False) sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) + (True, OneSumNode (9×9) with 2 children) sage: unicode_art(certificate) ╭───────────OneSumNode (9×9) with 2 children │ │ - UnknownNode (5×4) UnknownNode (4×5) + GraphicNode (5×4) CographicNode (4×5) sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, complete_tree=True) sage: result, certificate @@ -1999,7 +1966,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): GraphicNode (5×4) CographicNode (4×5) This is test ``TreeFlagsNorecurse``, ``TreeFlagsStopNoncographic``, - and ``TreeFlagsStopNongraphic`` in CMR's ``test_regular.cpp``:: + and ``TreeFlagsStopNongraphic`` in CMR's ``test_regular.cpp``, + the underlying binary linear matroid is regular, + but the matrix is not totally unimodular:: sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], @@ -2014,14 +1983,16 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, complete_tree=False) sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) + (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) + sage: unicode_art(certificate[0]) + ╭──────OneSumNode (9×9) with 2 children──────╮ + │ │ + SubmatrixNode (5×4) UnknownNode (4×5) + │ + Isomorphic to a minor of |det| = 2 submatrix sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, - ....: complete_tree='find_noncographic') + ....: complete_tree=True) sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -2033,20 +2004,24 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, ....: complete_tree='find_nongraphic') - sage: result, certificate - (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) - sage: unicode_art(certificate[0]) - ╭──────OneSumNode (9×9) with 2 children──────╮ - │ │ - SubmatrixNode (5×4) UnknownNode (4×5) - │ - Isomorphic to a minor of |det| = 2 submatrix + Traceback (most recent call last): + ... + ValueError: Unknown complete tree parameter find_nongraphic + either stop when a not TU child is found + or return the full complete tree """ base_ring = self.parent().base_ring() if base_ring.characteristic(): raise ValueError(f'only defined over characteristic 0, got {base_ring}') - cdef bool result_bool = True + if complete_tree not in ["find_irregular", False, True]: + raise ValueError(f'Unknown complete tree parameter {complete_tree} ' + f'either stop when a not TU child is found ' + f'or return the full complete tree') + if complete_tree == False: + complete_tree = "find_irregular" + + cdef bool result_bool cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats cdef CMR_MATROID_DEC *dec = NULL @@ -2076,13 +2051,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_off() result = result_bool - if result == True and CMRmatroiddecRegularity(dec) == 0: - result = 'Not Determined' if not certificate: return result node = create_DecompositionNode(dec, self, row_keys, column_keys) - if result != False: + if result: return result, node if submat == NULL: diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index b4fdf46e0ea..f6b4c103504 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -12,6 +12,7 @@ cdef class DecompositionNode(SageObject): cdef object _child_nodes cdef _set_dec(self, CMR_MATROID_DEC *dec) + cdef _set_root_dec(self, isTernary=?) cdef _set_row_keys(self, row_keys) cdef _set_column_keys(self, column_keys) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ab806c3d3be..d9bd90896b8 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -74,6 +74,22 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRmatroiddecCapture(cmr, dec)) self._dec = dec + cdef _set_root_dec(self, isTernary=True): + cdef CMR_MATROID_DEC *root + cdef Matrix_cmr_chr_sparse matrix + try: + matrix = self.matrix() + except: + raise ValueError('no Matrix_cmr_chr_sparse matrix') + cdef CMR_CHRMAT *mat = matrix._mat + + sig_on() + try: + CMR_CALL(CMRmatroiddecCreateMatrixRoot(cmr, &root, isTernary, mat)) + finally: + sig_off() + self._set_dec(root) + cdef _set_row_keys(self, row_keys): """ Set the row keys with consistency checking: if the @@ -583,15 +599,18 @@ cdef class DecompositionNode(SageObject): ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=False) - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(M); node + UnknownNode (9×9) + sage: C0 = node._binary_linear_matroid_complete_decomposition( + ....: complete_tree=False) + sage: C0 + OneSumNode (9×9) with 2 children + sage: unicode_art(C0) ╭───────────OneSumNode (9×9) with 2 children │ │ UnknownNode (5×4) UnknownNode (4×5) - sage: C1, C2 = certificate.child_nodes() + sage: C1, C2 = C0.child_nodes() sage: C11 = C1._binary_linear_matroid_complete_decomposition(complete_tree=False); C11 GraphicNode (5×4) sage: unicode_art(C11) @@ -629,6 +648,9 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC **pclone = &clone + if self._dec == NULL: + self._set_root_dec(isTernary=False) + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, @@ -726,15 +748,15 @@ cdef class DecompositionNode(SageObject): ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) - sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=False) - sage: result, certificate - ('Not Determined', OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(M); node + UnknownNode (9×9) + sage: C0 = node.complete_decomposition(complete_tree=False) + sage: unicode_art(C0) ╭───────────OneSumNode (9×9) with 2 children │ │ UnknownNode (5×4) UnknownNode (4×5) - sage: C1, C2 = certificate.child_nodes() + sage: C1, C2 = C0.child_nodes() sage: C11 = C1.complete_decomposition(complete_tree=False); C11 SubmatrixNode (5×4) sage: unicode_art(C11) @@ -776,6 +798,9 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC **pclone = &clone + if self._dec == NULL: + self._set_root_dec(isTernary=True) + cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, @@ -1266,27 +1291,31 @@ cdef class ThreeSumNode(SumNode): [-1 -1 0 0 1] sage: C.child_indices() (((0, 1, a, 3), (b, c, d, e, +3+e)), ((0, 2, 3, 5), (+0+d, d, 4, e, f))) - sage: result, certificate = R12.is_totally_unimodular(certificate=True, - ....: complete_tree=False, - ....: three_sum_strategy="Wide_Wide", - ....: row_keys=range(6), - ....: column_keys='abcdef') - sage: result, certificate - ('Not Determined', PivotsNode (6×6)) - sage: unicode_art(certificate) + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(R12, + ....: row_keys=range(6), + ....: column_keys='abcdef'); node + UnknownNode (6×6) + sage: C0 = node.complete_decomposition( + ....: complete_tree=False, + ....: three_sum_strategy="Wide_Wide", + ....: ) + sage: C0 + PivotsNode (6×6) + sage: unicode_art(C0) PivotsNode (6×6) │ ╭──────────ThreeSumNode (6×6) with 2 children │ │ UnknownNode (4×5) UnknownNode (4×5) - sage: unicode_art(certificate.complete_decomposition(complete_tree=True, + sage: unicode_art(C0.complete_decomposition(complete_tree=True, ....: three_sum_strategy="Wide_Wide")) PivotsNode (6×6) │ ╭─────────────ThreeSumNode (6×6) with 2 children │ │ CographicNode (4×5) GraphicNode (4×5) - sage: unicode_art(certificate) + sage: unicode_art(C0) PivotsNode (6×6) │ ╭──────────ThreeSumNode (6×6) with 2 children From b0e8e2ec0e5bdf358ca4c37481076924bb7078ef Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 2 May 2024 10:44:20 -0700 Subject: [PATCH 206/262] build/pkgs/cmr: Update to 63f3e1fbaf52174e25fb95770af439260a4b5631 --- build/pkgs/cmr/checksums.ini | 6 +++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 2cc45f82ea3..db13f68194f 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,5 @@ tarball=cmr-0+VERSION.tar.gz -sha1=37715f6d8923aa266354b44dbe5265543faaf882 -md5=3e7681d1569395fea165832734753598 -cksum=1901556332 +sha1=1fb6c029456eaa030205e06ee2eb526ac7c2553e +md5=95e7c27c74a66e55e74791c2fbc46988 +cksum=622510774 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index cad3c28eb3d..0aa641ebcbb 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -edd64258cacab23fe170006bc32f429621652bf0 +63f3e1fbaf52174e25fb95770af439260a4b5631 From 2c145a8d67503e61a5ae42035078a8af06ae9c13 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 13 May 2024 09:51:09 -0700 Subject: [PATCH 207/262] WIP align treeFlags with cmr --- src/sage/matrix/matrix_cmr_sparse.pyx | 143 +++++++++----------------- 1 file changed, 47 insertions(+), 96 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 507a7129fb1..94df2300809 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1533,8 +1533,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): Graphics object consisting of 21 graphics primitives """ base_ring = self.parent().base_ring() - if base_ring.characteristic(): - raise ValueError(f'only defined over characteristic 0, got {base_ring}') + if base_ring.characteristic() not in [0, 3] : + raise ValueError(f'only defined over characteristic 0 or 3, got {base_ring}') cdef bool result cdef bool support_result @@ -1614,8 +1614,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): False """ base_ring = self.parent().base_ring() - if base_ring.characteristic(): - raise ValueError(f'only defined over characteristic 0, got {base_ring}') + if base_ring.characteristic() not in [0, 3] : + raise ValueError(f'only defined over characteristic 0 or 3, got {base_ring}') cdef bool result cdef bool support_result @@ -1653,7 +1653,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='find_irregular', + recurse=True, + stop_when_irregular=True, three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False, @@ -1668,11 +1669,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - ``certificate``: ``False`` or ``True`` - - ``complete_tree``: one of the following values - ``True`` - return the node with full decomposition - ``'find_irregular'`` or ``False`` - - return the node when the decomposition detects - an irregular node EXAMPLES:: @@ -1716,7 +1712,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ ThreeConnectedIrregularNode (3×4) sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=False) + ....: certificate=True) sage: result, certificate (False, (OneSumNode (6×14) with 2 children, NotImplemented)) sage: unicode_art(certificate[0]) @@ -1726,7 +1722,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ ThreeConnectedIrregularNode (3×4) sage: result, certificate = MFR2cmr._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=True) + ....: certificate=True, stop_when_irregular=False) sage: result, certificate (False, (OneSumNode (6×14) with 2 children, NotImplemented)) sage: unicode_art(certificate[0]) @@ -1753,13 +1749,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], ....: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]) sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=True) + ....: certificate=True) sage: result, certificate (True, GraphicNode (11×11)) sage: unicode_art(certificate) GraphicNode (11×11) sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=True, + ....: certificate=True, ....: use_direct_graphicness_test=False) sage: result, certificate (True, TwoSumNode (11×11) with 2 children) @@ -1770,36 +1766,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ GraphicNode (4×4) - This is the example in tests ``TreeFlagsNorecurse``, - ``TreeFlagsStopNoncographic`` in CMR's ``test_regular.cpp``:: - - sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), - ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], - ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], - ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], - ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], - ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], - ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], - ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], - ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, complete_tree=False) - sage: result, certificate - (True, OneSumNode (9×9) with 2 children) - sage: unicode_art(certificate) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - GraphicNode (5×4) CographicNode (4×5) - sage: result, certificate = M._is_binary_linear_matroid_regular( - ....: certificate=True, - ....: complete_tree='find_noncographic') - Traceback (most recent call last): - ... - ValueError: Unknown complete tree parameter find_noncographic - either stop when an irregular child is found - or return the full complete tree - Base ring check:: sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(5), 3, 2, sparse=True), @@ -1819,13 +1785,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if not GF2.has_coerce_map_from(base_ring): raise ValueError('not well-defined') - if complete_tree not in ["find_irregular", False, True]: - raise ValueError(f'Unknown complete tree parameter {complete_tree} ' - f'either stop when an irregular child is found ' - f'or return the full complete tree') - if complete_tree == False: - complete_tree = "find_irregular" - cdef bool result_bool cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats @@ -1838,7 +1797,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - complete_tree=complete_tree, + recurse=recurse, + stop_when_irregular=stop_when_irregular, + stop_when_nongraphic=False, + stop_when_noncographic=False, + stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) @@ -1864,7 +1827,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='find_irregular', + recurse=True, + stop_when_nonTU=True, three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False, @@ -1882,11 +1846,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - ``certificate``: ``False`` or ``True`` - - ``complete_tree``: one of the following values - ``True`` - return the node with full decomposition - ``'find_irregular'`` or ``False`` - - return the node when the decomposition detects - a not totally unimodular node EXAMPLES:: @@ -1922,7 +1881,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: MFR2cmr.is_totally_unimodular(certificate=True) (False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3)))) sage: result, certificate = MFR2cmr.is_totally_unimodular(certificate=True, - ....: complete_tree=True) + ....: stop_when_nonTU=True) sage: result, certificate (False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3)))) sage: submatrix = MFR2.matrix_from_rows_and_columns(*certificate[1]); submatrix @@ -1949,7 +1908,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: [0, 0, 0, 0,-1, 0, 1, 1, 0], ....: [0, 0, 0, 0,-1, 0, 1, 0, 1]]) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=False) + ....: certificate=True) sage: result, certificate (True, OneSumNode (9×9) with 2 children) sage: unicode_art(certificate) @@ -1957,7 +1916,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): │ │ GraphicNode (5×4) CographicNode (4×5) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=True) + ....: certificate=True, stop_when_nonTU=False) sage: result, certificate (True, OneSumNode (9×9) with 2 children) sage: unicode_art(certificate) @@ -1981,7 +1940,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, complete_tree=False) + ....: certificate=True) sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -1992,7 +1951,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): Isomorphic to a minor of |det| = 2 submatrix sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, - ....: complete_tree=True) + ....: stop_when_nonTU=False) sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) @@ -2001,25 +1960,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): SubmatrixNode (5×4) SubmatrixNode (4×5) │ │ Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix - sage: result, certificate = M.is_totally_unimodular( - ....: certificate=True, - ....: complete_tree='find_nongraphic') - Traceback (most recent call last): - ... - ValueError: Unknown complete tree parameter find_nongraphic - either stop when a not TU child is found - or return the full complete tree """ base_ring = self.parent().base_ring() - if base_ring.characteristic(): - raise ValueError(f'only defined over characteristic 0, got {base_ring}') - - if complete_tree not in ["find_irregular", False, True]: - raise ValueError(f'Unknown complete tree parameter {complete_tree} ' - f'either stop when a not TU child is found ' - f'or return the full complete tree') - if complete_tree == False: - complete_tree = "find_irregular" + if base_ring.characteristic() not in [0, 3] : + raise ValueError(f'only defined over characteristic 0 or 3, got {base_ring}') cdef bool result_bool cdef CMR_TU_PARAMS params @@ -2035,7 +1979,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - complete_tree=complete_tree, + recurse=recurse, + stop_when_irregular=stop_when_nonTU, + stop_when_nongraphic=False, + stop_when_noncographic=False, + stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) @@ -2100,21 +2048,24 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE else: params.threeSumStrategy = kwds['three_sum_strategy'] - if kwds['complete_tree'] is not None: - if kwds['complete_tree'] is True: - params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE - elif kwds['complete_tree'] is False or kwds['complete_tree'] == 'no_recurse': - params.treeFlags = CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR - elif kwds['complete_tree'] == 'find_irregular': - params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR - elif kwds['complete_tree'] == 'find_nongraphic': - params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC - elif kwds['complete_tree'] == 'find_noncographic': - params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC - elif kwds['complete_tree'] == 'find_nongraphic_and_noncographic': - params.treeFlags = CMR_REGULAR_TREE_FLAGS_RECURSE | CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC - else: - params.treeFlags = kwds['complete_tree'] + treeFlags_list = [] + if kwds['recurse'] is True: + treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_RECURSE) + if kwds['stop_when_irregular'] is True: + treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR) + if kwds['stop_when_nongraphic'] is True: + treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC) + if kwds['stop_when_noncographic'] is True: + treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC) + if kwds['stop_when_nongraphic_and_noncographic'] is True: + treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC) + if treeFlags_list: + treeFlag = 0 + for flag in treeFlags_list: + treeFlag |= flag + params.treeFlags = treeFlag + else: + params.treeFlags = CMR_REGULAR_TREE_FLAGS_DEFAULT params.graphs = _cmr_dec_construct(kwds['construct_graphs']) From dc6dc38f9d051fd4141333ba43f61997796a9fb0 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 13 May 2024 12:59:53 -0700 Subject: [PATCH 208/262] fix complete decomposition in seymour_decomposition --- src/sage/matrix/matrix_cmr_sparse.pyx | 8 +- src/sage/matrix/seymour_decomposition.pyx | 90 +++++++++++++++++++---- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 94df2300809..667dca319fc 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1653,7 +1653,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - recurse=True, stop_when_irregular=True, three_sum_pivot_children=False, three_sum_strategy=None, @@ -1797,7 +1796,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=recurse, + recurse=True, stop_when_irregular=stop_when_irregular, stop_when_nongraphic=False, stop_when_noncographic=False, @@ -1827,7 +1826,6 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - recurse=True, stop_when_nonTU=True, three_sum_pivot_children=False, three_sum_strategy=None, @@ -1979,7 +1977,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=recurse, + recurse=True, stop_when_irregular=stop_when_nonTU, stop_when_nongraphic=False, stop_when_noncographic=False, @@ -2065,7 +2063,7 @@ cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): treeFlag |= flag params.treeFlags = treeFlag else: - params.treeFlags = CMR_REGULAR_TREE_FLAGS_DEFAULT + params.treeFlags = 0 params.graphs = _cmr_dec_construct(kwds['construct_graphs']) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d9bd90896b8..4c636d7aa5c 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -581,7 +581,11 @@ cdef class DecompositionNode(SageObject): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='find_irregular', + recurse=True, + stop_when_irregular=False, + stop_when_nongraphic=False, + stop_when_noncographic=False, + stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False): @@ -602,8 +606,7 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M); node UnknownNode (9×9) - sage: C0 = node._binary_linear_matroid_complete_decomposition( - ....: complete_tree=False) + sage: C0 = node._binary_linear_matroid_complete_decomposition(recurse=False) sage: C0 OneSumNode (9×9) with 2 children sage: unicode_art(C0) @@ -611,7 +614,7 @@ cdef class DecompositionNode(SageObject): │ │ UnknownNode (5×4) UnknownNode (4×5) sage: C1, C2 = C0.child_nodes() - sage: C11 = C1._binary_linear_matroid_complete_decomposition(complete_tree=False); C11 + sage: C11 = C1._binary_linear_matroid_complete_decomposition(recurse=False); C11 GraphicNode (5×4) sage: unicode_art(C11) GraphicNode (5×4) @@ -627,7 +630,7 @@ cdef class DecompositionNode(SageObject): [0 1 1 1] [1 0 0 1] [0 0 1 1] - sage: C22 = C2._binary_linear_matroid_complete_decomposition(complete_tree=False); C22 + sage: C22 = C2._binary_linear_matroid_complete_decomposition(recurse=False); C22 CographicNode (4×5) sage: unicode_art(C22) CographicNode (4×5) @@ -641,6 +644,55 @@ cdef class DecompositionNode(SageObject): [0 0 1 1 1] [0 1 0 1 1] [1 1 0 1 0] + + This is test ``TreeFlagsStopNoncographic`` in CMR's ``test_regular.cpp``. + The default settings will not do the planarity check:: + + sage: unicode_art(node) + UnknownNode (9×9) + sage: certificate1 = node._binary_linear_matroid_complete_decomposition( + ....: recurse=True, + ....: stop_when_noncographic=True, + ....: check_graphic_minors_planar=True) + sage: unicode_art(certificate1) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: certificate2 = node._binary_linear_matroid_complete_decomposition( + ....: recurse=True, + ....: stop_when_noncographic=True) + sage: unicode_art(certificate2) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) CographicNode (4×5) + + sage: certificate1 = node._binary_linear_matroid_complete_decomposition( + ....: recurse=True, + ....: stop_when_nongraphic=True, + ....: check_graphic_minors_planar=True) + sage: unicode_art(certificate1) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: C1, C2 = certificate1.child_nodes() + sage: C1._is_binary_linear_matroid_cographic() + False + sage: C2._is_binary_linear_matroid_graphic() + False + sage: certificate2 = node._binary_linear_matroid_complete_decomposition( + ....: recurse=True, + ....: stop_when_nongraphic=True) + sage: unicode_art(certificate2) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: C1, C2 = certificate2.child_nodes() + sage: C1._is_binary_linear_matroid_cographic() + Traceback (most recent call last): + ... + NotImplementedError: Cographic Not Determined + sage: C2._is_binary_linear_matroid_graphic() + False """ cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats @@ -654,7 +706,11 @@ cdef class DecompositionNode(SageObject): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - complete_tree=complete_tree, + recurse=recurse, + stop_when_irregular=stop_when_irregular, + stop_when_nongraphic=stop_when_nongraphic, + stop_when_noncographic=stop_when_noncographic, + stop_when_nongraphic_and_noncographic=stop_when_nongraphic_and_noncographic, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) @@ -730,7 +786,11 @@ cdef class DecompositionNode(SageObject): use_direct_graphicness_test=True, series_parallel_ok=True, check_graphic_minors_planar=False, - complete_tree='find_irregular', + recurse=True, + stop_when_nonTU=False, + stop_when_nonnetwork=False, + stop_when_nonconetwork=False, + stop_when_nonnetwork_and_nonconetwork=False, three_sum_pivot_children=False, three_sum_strategy=None, construct_graphs=False): @@ -751,13 +811,13 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M); node UnknownNode (9×9) - sage: C0 = node.complete_decomposition(complete_tree=False) + sage: C0 = node.complete_decomposition(recurse=False) sage: unicode_art(C0) ╭───────────OneSumNode (9×9) with 2 children │ │ UnknownNode (5×4) UnknownNode (4×5) sage: C1, C2 = C0.child_nodes() - sage: C11 = C1.complete_decomposition(complete_tree=False); C11 + sage: C11 = C1.complete_decomposition(recurse=False); C11 SubmatrixNode (5×4) sage: unicode_art(C11) SubmatrixNode (5×4) @@ -775,7 +835,7 @@ cdef class DecompositionNode(SageObject): [0 1 1 1] [1 0 0 1] [0 0 1 1] - sage: C22 = C2.complete_decomposition(complete_tree=False); C22 + sage: C22 = C2.complete_decomposition(); C22 SubmatrixNode (4×5) sage: unicode_art(C22) SubmatrixNode (4×5) @@ -804,7 +864,11 @@ cdef class DecompositionNode(SageObject): cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - complete_tree=complete_tree, + recurse=recurse, + stop_when_irregular=stop_when_nonTU, + stop_when_nongraphic=stop_when_nonnetwork, + stop_when_noncographic=stop_when_nonconetwork, + stop_when_nongraphic_and_noncographic=stop_when_nonnetwork_and_nonconetwork, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, construct_graphs=construct_graphs) @@ -1297,7 +1361,7 @@ cdef class ThreeSumNode(SumNode): ....: column_keys='abcdef'); node UnknownNode (6×6) sage: C0 = node.complete_decomposition( - ....: complete_tree=False, + ....: recurse=False, ....: three_sum_strategy="Wide_Wide", ....: ) sage: C0 @@ -1308,7 +1372,7 @@ cdef class ThreeSumNode(SumNode): ╭──────────ThreeSumNode (6×6) with 2 children │ │ UnknownNode (4×5) UnknownNode (4×5) - sage: unicode_art(C0.complete_decomposition(complete_tree=True, + sage: unicode_art(C0.complete_decomposition(recurse=True, stop_when_nonTU=True, ....: three_sum_strategy="Wide_Wide")) PivotsNode (6×6) │ From 70d64cf3540abf07e9b9278eaf39de4813a988d0 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 13 May 2024 13:27:05 -0700 Subject: [PATCH 209/262] remove isTernary in _set_root_dec --- src/sage/matrix/seymour_decomposition.pxd | 2 +- src/sage/matrix/seymour_decomposition.pyx | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index f6b4c103504..e9df580b74a 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -12,7 +12,7 @@ cdef class DecompositionNode(SageObject): cdef object _child_nodes cdef _set_dec(self, CMR_MATROID_DEC *dec) - cdef _set_root_dec(self, isTernary=?) + cdef _set_root_dec(self) cdef _set_row_keys(self, row_keys) cdef _set_column_keys(self, column_keys) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 4c636d7aa5c..a6a4febead5 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -74,13 +74,17 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRmatroiddecCapture(cmr, dec)) self._dec = dec - cdef _set_root_dec(self, isTernary=True): + cdef _set_root_dec(self): cdef CMR_MATROID_DEC *root cdef Matrix_cmr_chr_sparse matrix try: matrix = self.matrix() except: raise ValueError('no Matrix_cmr_chr_sparse matrix') + base_ring = matrix.parent().base_ring() + if base_ring.characteristic() not in [0, 2, 3] : + raise ValueError(f'only defined over binary or ternary, got {base_ring}') + isTernary = base_ring.characteristic() != 2 cdef CMR_CHRMAT *mat = matrix._mat sig_on() @@ -593,7 +597,7 @@ cdef class DecompositionNode(SageObject): EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 9, 9, sparse=True), ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], @@ -701,7 +705,7 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC **pclone = &clone if self._dec == NULL: - self._set_root_dec(isTernary=False) + self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, @@ -859,7 +863,7 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC **pclone = &clone if self._dec == NULL: - self._set_root_dec(isTernary=True) + self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, series_parallel_ok=series_parallel_ok, From da9c545c7ff4c0cdd1a6e930deb68b7a4b9709a2 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 13 May 2024 13:40:52 -0700 Subject: [PATCH 210/262] fix base_ring() --- src/sage/matrix/seymour_decomposition.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index a6a4febead5..09ad3495f71 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -81,7 +81,7 @@ cdef class DecompositionNode(SageObject): matrix = self.matrix() except: raise ValueError('no Matrix_cmr_chr_sparse matrix') - base_ring = matrix.parent().base_ring() + base_ring = self.base_ring() if base_ring.characteristic() not in [0, 2, 3] : raise ValueError(f'only defined over binary or ternary, got {base_ring}') isTernary = base_ring.characteristic() != 2 @@ -705,6 +705,9 @@ cdef class DecompositionNode(SageObject): cdef CMR_MATROID_DEC **pclone = &clone if self._dec == NULL: + base_ring = self.base_ring() + if base_ring.characteristic() != 2: + raise ValueError(f'only defined over binary, got {base_ring}') self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, From b60c6660ef788c7e9af8326bba54cf2556eed6d7 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 13 May 2024 14:35:50 -0700 Subject: [PATCH 211/262] first try to complete decompositions for is_graphic is_cographic tests --- src/sage/matrix/seymour_decomposition.pyx | 88 ++++++++++++++++++++--- 1 file changed, 78 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 09ad3495f71..56a8c0f5357 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -540,7 +540,13 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("Graphic Not Determined") + full_dec = self._binary_linear_matroid_complete_decomposition( + recurse=True, + stop_when_nongraphic=True, + check_graphic_minors_planar=True) + return full_dec._is_binary_linear_matroid_graphic( + decomposition=decomposition, + certificate=certificate) def _is_binary_linear_matroid_cographic(self, *, decomposition=False, **kwds): r""" @@ -559,11 +565,61 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("Cographic Not Determined") + full_dec = self._binary_linear_matroid_complete_decomposition( + recurse=True, + stop_when_noncographic=True, + check_graphic_minors_planar=True) + return full_dec._is_binary_linear_matroid_cographic( + decomposition=decomposition, + certificate=certificate) def _is_binary_linear_matroid_regular(self, *, decomposition=False, **kwds): r""" + EXAMPLES:: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(M) + sage: C0 = node._binary_linear_matroid_complete_decomposition(recurse=False) + sage: C0 + OneSumNode (9×9) with 2 children + sage: result, decomposition = C0._is_binary_linear_matroid_graphic(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: decomposition.child_nodes()[1]._graphicness() + False + sage: result, decomposition = C0._is_binary_linear_matroid_cographic(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: decomposition.child_nodes()[1]._graphicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is graphic/network + sage: result, decomposition = C0._is_binary_linear_matroid_regular(decomposition=True) + sage: result + True + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) CographicNode (4×5) """ certificate = kwds.get('certificate', False) try: @@ -578,7 +634,13 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("Regularity Not Determined") + full_dec = self._binary_linear_matroid_complete_decomposition( + recurse=True, + stop_when_irregular=True, + check_graphic_minors_planar=True) + return full_dec._is_binary_linear_matroid_regular( + decomposition=decomposition, + certificate=certificate) def _binary_linear_matroid_complete_decomposition(self, *, time_limit=60.0, @@ -679,9 +741,9 @@ cdef class DecompositionNode(SageObject): │ │ GraphicNode (5×4) UnknownNode (4×5) sage: C1, C2 = certificate1.child_nodes() - sage: C1._is_binary_linear_matroid_cographic() + sage: C1._cographicness() False - sage: C2._is_binary_linear_matroid_graphic() + sage: C2._graphicness() False sage: certificate2 = node._binary_linear_matroid_complete_decomposition( ....: recurse=True, @@ -691,11 +753,11 @@ cdef class DecompositionNode(SageObject): │ │ GraphicNode (5×4) UnknownNode (4×5) sage: C1, C2 = certificate2.child_nodes() - sage: C1._is_binary_linear_matroid_cographic() + sage: C1._cographicness() Traceback (most recent call last): ... - NotImplementedError: Cographic Not Determined - sage: C2._is_binary_linear_matroid_graphic() + ValueError: It is not determined whether the decomposition node is cographic/conetwork + sage: C2._graphicness() False """ cdef CMR_REGULAR_PARAMS params @@ -729,7 +791,10 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRregularCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) finally: sig_off() - node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) + node = create_DecompositionNode(clone, matrix=self.matrix(), + row_keys=self.row_keys(), + column_keys=self.column_keys(), + base_ring=self.base_ring()) return node def is_network_matrix(self, *, decomposition=False, **kwds): @@ -889,7 +954,10 @@ cdef class DecompositionNode(SageObject): CMR_CALL(CMRtuCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) finally: sig_off() - node = create_DecompositionNode(clone, self.matrix(), self.row_keys(), self.column_keys()) + node = create_DecompositionNode(clone, matrix=self.matrix(), + row_keys=self.row_keys(), + column_keys=self.column_keys(), + base_ring=self.base_ring()) return node From db9d53e18b8300afa32de5ede6dfcdcc8a79e6b7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Jun 2024 10:58:52 -0700 Subject: [PATCH 212/262] build/pkgs/sagemath_cmr/distros: Remove --- build/pkgs/sagemath_cmr/distros/conda.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 build/pkgs/sagemath_cmr/distros/conda.txt diff --git a/build/pkgs/sagemath_cmr/distros/conda.txt b/build/pkgs/sagemath_cmr/distros/conda.txt deleted file mode 100644 index d6139d966ec..00000000000 --- a/build/pkgs/sagemath_cmr/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -sagemath-bliss From 0b62823e2b1a1d23fc854f65b3f50847a5083c06 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Jun 2024 11:03:43 -0700 Subject: [PATCH 213/262] build/pkgs/sagemath_cmr/version_requirements.txt: Rename from install-requires.txt --- .../{install-requires.txt => version_requirements.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build/pkgs/sagemath_cmr/{install-requires.txt => version_requirements.txt} (100%) diff --git a/build/pkgs/sagemath_cmr/install-requires.txt b/build/pkgs/sagemath_cmr/version_requirements.txt similarity index 100% rename from build/pkgs/sagemath_cmr/install-requires.txt rename to build/pkgs/sagemath_cmr/version_requirements.txt From 03c1b9c3380a7932136d2f531da6f0bba86a8511 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Jun 2024 11:07:37 -0700 Subject: [PATCH 214/262] build/pkgs/sagemath_cmr: Install like sagemath_bliss --- build/pkgs/sagemath_cmr/spkg-install | 29 ------------------------- build/pkgs/sagemath_cmr/spkg-install.in | 1 + 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100755 build/pkgs/sagemath_cmr/spkg-install create mode 120000 build/pkgs/sagemath_cmr/spkg-install.in diff --git a/build/pkgs/sagemath_cmr/spkg-install b/build/pkgs/sagemath_cmr/spkg-install deleted file mode 100755 index 7ce202f09ae..00000000000 --- a/build/pkgs/sagemath_cmr/spkg-install +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# From sage-spkg. -# For type=script packages, the build rule in build/make/Makefile sources -# sage-env but not sage-dist-helpers. -lib="$SAGE_ROOT/build/bin/sage-dist-helpers" -source "$lib" -if [ $? -ne 0 ]; then - echo >&2 "Error: failed to source $lib" - echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" - exit 1 -fi -cd src - -export PIP_NO_INDEX=true -export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" - -if [ "$SAGE_EDITABLE" = yes ]; then - # SAGE_ROOT/src/setup.py installs everything, nothing to do... - if [ "$SAGE_WHEELS" = yes ]; then - # ... except we build the wheel if requested - sdh_setup_bdist_wheel && sdh_store_wheel . - fi -else - if [ "$SAGE_WHEELS" = yes ]; then - # Modularized install via wheels - sdh_pip_install . - # else nothing to do in legacy direct installation. - fi -fi diff --git a/build/pkgs/sagemath_cmr/spkg-install.in b/build/pkgs/sagemath_cmr/spkg-install.in new file mode 120000 index 00000000000..e38ca3ace8b --- /dev/null +++ b/build/pkgs/sagemath_cmr/spkg-install.in @@ -0,0 +1 @@ +../sagemath_bliss/spkg-install.in \ No newline at end of file From d815e58c1ff0e1ecd7480558fc3a0bd1dde6b101 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 10 Jun 2024 11:58:02 -0700 Subject: [PATCH 215/262] build/pkgs/cmr: Update to b0a60ad3ce782c59513f016c96e1d08f7d955bee --- build/pkgs/cmr/checksums.ini | 5 ++--- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index db13f68194f..954ace794a7 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,5 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=1fb6c029456eaa030205e06ee2eb526ac7c2553e -md5=95e7c27c74a66e55e74791c2fbc46988 -cksum=622510774 +sha1=b5921d918333b4a37acbd6644742a04004cff40d +sha256=6c48947762362ef8a20a5cc703dedcf86457630b9784c172d3347f55535d2c10 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 0aa641ebcbb..48aedaf2c93 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -63f3e1fbaf52174e25fb95770af439260a4b5631 +b0a60ad3ce782c59513f016c96e1d08f7d955bee From 67c7843d4c3098d4f5e6b19ab0ba20aa5ef70609 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 19 Jun 2024 23:32:36 -0700 Subject: [PATCH 216/262] update to seymour node in cmr.pxd --- src/sage/libs/cmr/cmr.pxd | 238 +++++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 108 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 5d864ee27f9..8e1792370d6 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -167,6 +167,7 @@ cdef extern from "cmr/graph.h": # CMR_ERROR CMRgraphPrint(CMR_GRAPH* graph, FILE* stream) CMR_ERROR CMRgraphMergeNodes(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH_NODE u, CMR_GRAPH_NODE v) # CMR_ERROR CMRgraphCreateFromEdgeList(CMR* cmr, CMR_GRAPH** pgraph, CMR_ELEMENT** pedgeElements, char*** pnodeLabels, FILE* stream) + # CMR_ERROR CMRgraphCopy(CMR* cmr, CMR_GRAPH* graph, CMR_GRAPH** pcopy) cdef extern from "cmr/matroid.h": @@ -175,91 +176,30 @@ cdef extern from "cmr/matroid.h": CMR_ERROR CMRchrmatBinaryPivots(CMR* cmr, CMR_CHRMAT* matrix, size_t numPivots, size_t* pivotRows, size_t* pivotColumns, CMR_CHRMAT** presult) CMR_ERROR CMRchrmatTernaryPivots(CMR* cmr, CMR_CHRMAT* matrix, size_t numPivots, size_t* pivotRows, size_t* pivotColumns, CMR_CHRMAT** presult) + ctypedef int CMR_MINOR_TYPE + + const int CMR_MINOR_TYPE_DETERMINANT + const int CMR_MINOR_TYPE_ENTRY + const int CMR_MINOR_TYPE_CUSTOM + const int CMR_MINOR_TYPE_U24 + const int CMR_MINOR_TYPE_FANO + const int CMR_MINOR_TYPE_FANO_DUAL + const int CMR_MINOR_TYPE_K5 + const int CMR_MINOR_TYPE_K5_DUAL + const int CMR_MINOR_TYPE_K33 + const int CMR_MINOR_TYPE_K33_DUAL + ctypedef struct CMR_MINOR: size_t numPivots size_t* pivotRows size_t* pivotColumns CMR_SUBMAT* remainingSubmatrix + CMR_MINOR_TYPE type - CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix) + CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix, CMR_MINOR_TYPE type) CMR_ERROR CMRminorFree(CMR* cmr, CMR_MINOR** pminor) - - ctypedef struct CMR_MATROID_DEC - - ctypedef int CMR_MATROID_DEC_TYPE - - const int CMR_MATROID_DEC_TYPE_IRREGULAR - const int CMR_MATROID_DEC_TYPE_UNKNOWN - const int CMR_MATROID_DEC_TYPE_ONE_SUM - const int CMR_MATROID_DEC_TYPE_TWO_SUM - const int CMR_MATROID_DEC_TYPE_THREE_SUM - const int CMR_MATROID_DEC_TYPE_SERIES_PARALLEL - const int CMR_MATROID_DEC_TYPE_PIVOTS - const int CMR_MATROID_DEC_TYPE_SUBMATRIX - const int CMR_MATROID_DEC_TYPE_GRAPH - const int CMR_MATROID_DEC_TYPE_COGRAPH - const int CMR_MATROID_DEC_TYPE_PLANAR - const int CMR_MATROID_DEC_TYPE_R10 - const int CMR_MATROID_DEC_TYPE_FANO - const int CMR_MATROID_DEC_TYPE_FANO_DUAL - const int CMR_MATROID_DEC_TYPE_K5 - const int CMR_MATROID_DEC_TYPE_K5_DUAL - const int CMR_MATROID_DEC_TYPE_K33 - const int CMR_MATROID_DEC_TYPE_K33_DUAL - const int CMR_MATROID_DEC_TYPE_DETERMINANT - - ctypedef int CMR_MATROID_DEC_THREESUM_FLAG - - const int CMR_MATROID_DEC_THREESUM_FLAG_NO_PIVOTS - const int CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS - const int CMR_MATROID_DEC_THREESUM_FLAG_CONCENTRATED_RANK - const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE - const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_TALL - const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_MIXED - const int CMR_MATROID_DEC_THREESUM_FLAG_FIRST_ALLREPR - const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE - const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_TALL - const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_MIXED - const int CMR_MATROID_DEC_THREESUM_FLAG_SECOND_ALLREPR - const int CMR_MATROID_DEC_THREESUM_FLAG_SEYMOUR - const int CMR_MATROID_DEC_THREESUM_FLAG_TRUEMPER - - bool CMRmatroiddecIsTernary(CMR_MATROID_DEC* dec) - bool CMRmatroiddecThreeSumDistributedRanks(CMR_MATROID_DEC* dec) - bool CMRmatroiddecThreeSumConcentratedRank(CMR_MATROID_DEC* dec) - bool CMRmatroiddecHasTranspose(CMR_MATROID_DEC* dec) - CMR_CHRMAT* CMRmatroiddecGetMatrix(CMR_MATROID_DEC* dec) - CMR_CHRMAT* CMRmatroiddecGetTranspose(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecNumChildren(CMR_MATROID_DEC* dec) - CMR_MATROID_DEC* CMRmatroiddecChild(CMR_MATROID_DEC* dec, size_t childIndex) - CMR_MATROID_DEC_TYPE CMRmatroiddecType(CMR_MATROID_DEC* dec) - int8_t CMRmatroiddecGraphicness(CMR_MATROID_DEC* dec) - int8_t CMRmatroiddecCographicness(CMR_MATROID_DEC* dec) - int8_t CMRmatroiddecRegularity(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecNumRows(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecNumColumns(CMR_MATROID_DEC* dec) - CMR_ELEMENT* CMRmatroiddecChildRowsToParent(CMR_MATROID_DEC* dec, size_t childIndex) - CMR_ELEMENT* CMRmatroiddecChildColumnsToParent(CMR_MATROID_DEC* dec, size_t childIndex) - CMR_GRAPH* CMRmatroiddecGraph(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecGraphForest(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecGraphSizeForest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecGraphCoforest(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecGraphSizeCoforest(CMR_MATROID_DEC* dec) - bool* CMRmatroiddecGraphArcsReversed(CMR_MATROID_DEC* dec) - CMR_GRAPH* CMRmatroiddecCograph(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecCographSizeForest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecCographForest(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecCographSizeCoforest(CMR_MATROID_DEC* dec) - CMR_GRAPH_EDGE* CMRmatroiddecCographCoforest(CMR_MATROID_DEC* dec) - bool* CMRmatroiddecCographArcsReversed(CMR_MATROID_DEC* dec) - size_t CMRmatroiddecNumPivots(CMR_MATROID_DEC* dec) - size_t* CMRmatroiddecPivotRows(CMR_MATROID_DEC* dec) - size_t* CMRmatroiddecPivotColumns(CMR_MATROID_DEC* dec) - # CMR_ERROR CMRmatroiddecPrint(CMR* cmr, CMR_MATROID_DEC* dec, FILE* stream, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) - CMR_ERROR CMRmatroiddecCloneUnknown(CMR* cmr, CMR_MATROID_DEC* dec, CMR_MATROID_DEC** pclone) - CMR_ERROR CMRmatroiddecCapture(CMR* cmr, CMR_MATROID_DEC* dec) - CMR_ERROR CMRmatroiddecRelease(CMR* cmr, CMR_MATROID_DEC** pdec) - CMR_ERROR CMRmatroiddecCreateMatrixRoot(CMR* cmr, CMR_MATROID_DEC** pdec, bool isTernary, CMR_CHRMAT* matrix) + CMR_MINOR_TYPE CMRminorType(CMR_MINOR* minor) + # CMR_ERROR CMRminorWriteToFile(CMR* cmr, CMR_MINOR* minor, size_t numRows, size_t numColumns, const char* fileName) cdef extern from "cmr/separation.h": @@ -365,39 +305,47 @@ cdef extern from "cmr/network.h": CMR_ERROR CMRnetworkTestMatrix(CMR* cmr, CMR_CHRMAT* matrix, bool* pisNetwork, bool* psupportIsGraphic, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) CMR_ERROR CMRnetworkTestTranspose(CMR* cmr, CMR_CHRMAT* matrix, bool* pisConetwork, bool* psupportIsCographic, CMR_GRAPH** pdigraph, CMR_GRAPH_EDGE** pforestArcs, CMR_GRAPH_EDGE** pcoforestArcs, bool** parcsReversed, CMR_SUBMAT** psubmatrix, CMR_NETWORK_STATISTICS* stats, double timeLimit) -cdef extern from "cmr/regular.h": - - ctypedef int CMR_DEC_CONSTRUCT - - const int CMR_DEC_CONSTRUCT_NONE - const int CMR_DEC_CONSTRUCT_LEAVES - const int CMR_DEC_CONSTRUCT_ALL - const int CMR_REGULAR_TREE_FLAGS_RECURSE - const int CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR - const int CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC - const int CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC - const int CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC - const int CMR_REGULAR_TREE_FLAGS_DEFAULT - - ctypedef struct CMR_REGULAR_PARAMS: - bint directGraphicness - bint seriesParallel - bint planarityCheck - int treeFlags +cdef extern from "cmr/seymour.h": + + ctypedef int CMR_SEYMOUR_THREESUM_FLAG + + const int CMR_SEYMOUR_THREESUM_FLAG_NO_PIVOTS + const int CMR_SEYMOUR_THREESUM_FLAG_DISTRIBUTED_RANKS + const int CMR_SEYMOUR_THREESUM_FLAG_CONCENTRATED_RANK + const int CMR_SEYMOUR_THREESUM_FLAG_FIRST_WIDE + const int CMR_SEYMOUR_THREESUM_FLAG_FIRST_TALL + const int CMR_SEYMOUR_THREESUM_FLAG_FIRST_MIXED + const int CMR_SEYMOUR_THREESUM_FLAG_FIRST_ALLREPR + const int CMR_SEYMOUR_THREESUM_FLAG_SECOND_WIDE + const int CMR_SEYMOUR_THREESUM_FLAG_SECOND_TALL + const int CMR_SEYMOUR_THREESUM_FLAG_SECOND_MIXED + const int CMR_SEYMOUR_THREESUM_FLAG_SECOND_ALLREPR + const int CMR_SEYMOUR_THREESUM_FLAG_SEYMOUR + const int CMR_SEYMOUR_THREESUM_FLAG_TRUEMPER + + ctypedef struct CMR_SEYMOUR_PARAMS: + bool stopWhenIrregular + bool stopWhenNongraphic + bool stopWhenNoncographic + bool stopWhenNeitherGraphicNorCoGraphic + bool seriesParallel + bool planarityCheck + bool directGraphicness + bool preferGraphicness bool threeSumPivotChildren int threeSumStrategy - CMR_DEC_CONSTRUCT graphs + bool constructLeafGraphs + bool constructAllGraphs - CMR_ERROR CMRregularParamsInit(CMR_REGULAR_PARAMS* params) + CMR_ERROR CMRseymourParamsInit(CMR_SEYMOUR_PARAMS* params) - ctypedef struct CMR_REGULAR_STATS: + ctypedef struct CMR_SEYMOUR_STATS: uint32_t totalCount double totalTime CMR_SP_STATISTICS seriesParallel CMR_GRAPHIC_STATISTICS graphic CMR_NETWORK_STATISTICS network - CMR_CAMION_STATISTICS camion uint32_t sequenceExtensionCount double sequenceExtensionTime uint32_t sequenceGraphicCount @@ -406,10 +354,82 @@ cdef extern from "cmr/regular.h": double enumerationTime uint32_t enumerationCandidatesCount + CMR_ERROR CMRseymourStatsInit(CMR_SEYMOUR_STATS* stats) + # CMR_ERROR CMRseymourStatsPrint(FILE* stream, CMR_SEYMOUR_STATS* stats, const char* prefix) + + ctypedef struct CMR_SEYMOUR_NODE + + ctypedef int CMR_SEYMOUR_NODE_TYPE + + const int CMR_SEYMOUR_NODE_TYPE_IRREGULAR + const int CMR_SEYMOUR_NODE_TYPE_UNKNOWN + const int CMR_SEYMOUR_NODE_TYPE_ONE_SUM + const int CMR_SEYMOUR_NODE_TYPE_TWO_SUM + const int CMR_SEYMOUR_NODE_TYPE_THREE_SUM + const int CMR_SEYMOUR_NODE_TYPE_SERIES_PARALLEL + const int CMR_SEYMOUR_NODE_TYPE_PIVOTS + const int CMR_SEYMOUR_NODE_TYPE_GRAPH + const int CMR_SEYMOUR_NODE_TYPE_COGRAPH + const int CMR_SEYMOUR_NODE_TYPE_PLANAR + const int CMR_SEYMOUR_NODE_TYPE_R10 + + bool CMRseymourIsTernary(CMR_SEYMOUR_NODE* node) + bool CMRseymourThreeSumDistributedRanks(CMR_SEYMOUR_NODE* node) + bool CMRseymourThreeSumConcentratedRank(CMR_SEYMOUR_NODE* node) + bool CMRseymourHasTranspose(CMR_SEYMOUR_NODE* node) + CMR_CHRMAT* CMRseymourGetMatrix(CMR_SEYMOUR_NODE* node) + CMR_CHRMAT* CMRseymourGetTranspose(CMR_SEYMOUR_NODE* node) + size_t CMRseymourNumChildren(CMR_SEYMOUR_NODE* node) + CMR_SEYMOUR_NODE* CMRseymourChild(CMR_SEYMOUR_NODE* node, size_t childIndex) + CMR_SEYMOUR_NODE_TYPE CMRseymourType(CMR_SEYMOUR_NODE* node) + size_t CMRseymourNumMinors(CMR_SEYMOUR_NODE* node) + CMR_MINOR* CMRseymourMinor(CMR_SEYMOUR_NODE* node, size_t minorIndex) + int8_t CMRseymourGraphicness(CMR_SEYMOUR_NODE* node) + int8_t CMRseymourCographicness(CMR_SEYMOUR_NODE* node) + int8_t CMRseymourRegularity(CMR_SEYMOUR_NODE* node) + size_t CMRseymourNumRows(CMR_SEYMOUR_NODE* node) + size_t CMRseymourNumColumns(CMR_SEYMOUR_NODE* node) + CMR_ELEMENT* CMRseymourChildRowsToParent(CMR_SEYMOUR_NODE* node, size_t childIndex) + CMR_ELEMENT* CMRseymourChildColumnsToParent(CMR_SEYMOUR_NODE* node, size_t childIndex) + CMR_GRAPH* CMRseymourGraph(CMR_SEYMOUR_NODE* node) + CMR_GRAPH_EDGE* CMRseymourGraphForest(CMR_SEYMOUR_NODE* node) + size_t CMRseymourGraphSizeForest(CMR_SEYMOUR_NODE* node) + CMR_GRAPH_EDGE* CMRseymourGraphCoforest(CMR_SEYMOUR_NODE* node) + size_t CMRseymourGraphSizeCoforest(CMR_SEYMOUR_NODE* node) + bool* CMRseymourGraphArcsReversed(CMR_SEYMOUR_NODE* node) + CMR_GRAPH* CMRseymourCograph(CMR_SEYMOUR_NODE* node) + size_t CMRseymourCographSizeForest(CMR_SEYMOUR_NODE* node) + CMR_GRAPH_EDGE* CMRseymourCographForest(CMR_SEYMOUR_NODE* node) + size_t CMRseymourCographSizeCoforest(CMR_SEYMOUR_NODE* node) + CMR_GRAPH_EDGE* CMRseymourCographCoforest(CMR_SEYMOUR_NODE* node) + bool* CMRseymourCographArcsReversed(CMR_SEYMOUR_NODE* node) + size_t CMRseymourNumPivots(CMR_SEYMOUR_NODE* node) + size_t* CMRseymourPivotRows(CMR_SEYMOUR_NODE* node) + size_t* CMRseymourPivotColumns(CMR_SEYMOUR_NODE* node) + size_t CMRseymourGetUsed(CMR_SEYMOUR_NODE* node) + # CMR_ERROR CMRseymourPrint(CMR* cmr, CMR_SEYMOUR_NODE* node, FILE* stream, bool printChildren, bool printParentElements, bool printMatrices, bool printGraphs, bool printReductions, bool printPivots) + CMR_ERROR CMRseymourCapture(CMR* cmr, CMR_SEYMOUR_NODE* node) + CMR_ERROR CMRseymourRelease(CMR* cmr, CMR_SEYMOUR_NODE** pnode) + CMR_ERROR CMRseymourCreate(CMR* cmr, CMR_SEYMOUR_NODE** pnode, bool isTernary, CMR_CHRMAT* matrix) + CMR_ERROR CMRseymourCloneUnknown(CMR* cmr, CMR_SEYMOUR_NODE* node, CMR_SEYMOUR_NODE** pclone) + CMR_ERROR CMRseymourCloneSubtrees(CMR* cmr, size_t numSubtrees, CMR_SEYMOUR_NODE** subtreeRoots,CMR_SEYMOUR_NODE** clonedSubtrees) + + +cdef extern from "cmr/regular.h": + + ctypedef struct CMR_REGULAR_PARAMS: + CMR_SEYMOUR_PARAMS seymour + + CMR_ERROR CMRregularParamsInit(CMR_REGULAR_PARAMS* params) + + ctypedef struct CMR_REGULAR_STATS: + CMR_SEYMOUR_STATS seymour + CMR_ERROR CMRregularStatsInit(CMR_REGULAR_STATS* stats) # CMR_ERROR CMRstatsRegularPrint(FILE* stream, CMR_REGULAR_STATS* stats, const char* prefix) - CMR_ERROR CMRregularTest(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_MATROID_DEC** pdec, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) - CMR_ERROR CMRregularCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRregularTest(CMR* cmr, CMR_CHRMAT* matrix, bint *pisRegular, CMR_SEYMOUR_NODE** pnode, CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRregularCompleteDecomposition(CMR* cmr, CMR_SEYMOUR_NODE* node, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) + CMR_ERROR CMRregularRefineDecomposition(CMR* cmr, size_t numNodes, CMR_SEYMOUR_NODE** nodes, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit) cdef extern from "cmr/tu.h": @@ -422,13 +442,15 @@ cdef extern from "cmr/tu.h": ctypedef struct CMR_TU_PARAMS: CMR_TU_ALGORITHM algorithm - bool directCamion - CMR_REGULAR_PARAMS regular + CMR_SEYMOUR_PARAMS seymour + bool ternary + bool camionFirst CMR_ERROR CMRtuParamsInit(CMR_TU_PARAMS* params) ctypedef struct CMR_TU_STATS: - CMR_REGULAR_STATS decomposition + CMR_SEYMOUR_STATS seymour + CMR_CAMION_STATISTICS camion uint32_t enumerationRowSubsets uint32_t enumerationColumnSubsets @@ -440,8 +462,8 @@ cdef extern from "cmr/tu.h": CMR_ERROR CMRtuStatsInit(CMR_TU_STATS* stats) # CMR_ERROR CMRtuStatsPrint(FILE* stream, CMR_TU_STATS* stats, const char* prefix) - CMR_ERROR CMRtuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_MATROID_DEC** pdec, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) - CMR_ERROR CMRtuCompleteDecomposition(CMR* cmr, CMR_MATROID_DEC* dec, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) + CMR_ERROR CMRtuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisTotallyUnimodular, CMR_SEYMOUR_NODE** proot, CMR_SUBMAT** psubmatrix, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) + CMR_ERROR CMRtuCompleteDecomposition(CMR* cmr, CMR_SEYMOUR_NODE* node, CMR_TU_PARAMS* params, CMR_TU_STATS* stats, double timeLimit) cdef extern from "cmr/equimodular.h": From f951df4179c9d11b037ba472c8b3c8c80c14d717 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 20 Jun 2024 16:38:19 -0700 Subject: [PATCH 217/262] WIP fix interface --- src/sage/matrix/matrix_cmr_sparse.pxd | 4 +- src/sage/matrix/matrix_cmr_sparse.pyx | 75 +++---- src/sage/matrix/seymour_decomposition.pxd | 8 +- src/sage/matrix/seymour_decomposition.pyx | 240 ++++++++++++---------- 4 files changed, 173 insertions(+), 154 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pxd b/src/sage/matrix/matrix_cmr_sparse.pxd index f4565bf5cda..51b44895af1 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pxd +++ b/src/sage/matrix/matrix_cmr_sparse.pxd @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_REGULAR_PARAMS, CMR_GRAPH, CMR_GRAPH_EDGE, bool +from sage.libs.cmr.cmr cimport CMR_CHRMAT, CMR_SEYMOUR_PARAMS, CMR_GRAPH, CMR_GRAPH_EDGE, bool from .matrix_sparse cimport Matrix_sparse @@ -22,7 +22,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): @staticmethod cdef _from_cmr(CMR_CHRMAT *mat, bint immutable=?, base_ring=?) -cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds) +cdef _set_cmr_seymour_parameters(CMR_SEYMOUR_PARAMS *params, dict kwds) cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e) cdef _sage_edges(CMR_GRAPH *graph, CMR_GRAPH_EDGE *edges, int n, keys) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 667dca319fc..e3ad0fa936c 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1651,12 +1651,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def _is_binary_linear_matroid_regular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, + prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, stop_when_irregular=True, three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False, + construct_leaf_graphs=False, + construct_all_graphs=False, row_keys=None, column_keys=None): r""" @@ -1787,25 +1789,26 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bool result_bool cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats - cdef CMR_MATROID_DEC *dec = NULL + cdef CMR_SEYMOUR_NODE *dec = NULL cdef CMR_MINOR *minor = NULL - cdef CMR_MATROID_DEC **pdec = &dec + cdef CMR_SEYMOUR_NODE **pdec = &dec cdef CMR_MINOR **pminor = &minor cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + prefer_graphicness=prefer_graphicness, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=True, stop_when_irregular=stop_when_irregular, stop_when_nongraphic=False, stop_when_noncographic=False, stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, - construct_graphs=construct_graphs) + construct_leaf_graphs=construct_leaf_graphs, + construct_all_graphs=construct_all_graphs) - _set_cmr_regular_parameters(¶ms, kwds) + _set_cmr_seymour_parameters(¶ms.seymour, kwds) sig_on() try: CMR_CALL(CMRregularTest(cmr, self._mat, &result_bool, pdec, pminor, @@ -1824,12 +1827,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_totally_unimodular(self, *, time_limit=60.0, certificate=False, use_direct_graphicness_test=True, + prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, stop_when_nonTU=True, three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False, + construct_leaf_graphs=False, + construct_all_graphs=False, row_keys=None, column_keys=None): r""" @@ -1966,29 +1971,31 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef bool result_bool cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats - cdef CMR_MATROID_DEC *dec = NULL + cdef CMR_SEYMOUR_NODE *dec = NULL cdef CMR_SUBMAT *submat = NULL - cdef CMR_MATROID_DEC **pdec = &dec + cdef CMR_SEYMOUR_NODE **pdec = &dec cdef CMR_SUBMAT **psubmat = &submat if three_sum_pivot_children: raise NotImplementedError cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + prefer_graphicness=prefer_graphicness, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=True, stop_when_irregular=stop_when_nonTU, stop_when_nongraphic=False, stop_when_noncographic=False, stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, - construct_graphs=construct_graphs) + construct_leaf_graphs=construct_leaf_graphs, + construct_all_graphs=construct_all_graphs) params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION - params.directCamion = False - _set_cmr_regular_parameters(¶ms.regular, kwds) + params.ternary = True + params.camionFirst = False + _set_cmr_seymour_parameters(¶ms.seymour, kwds) sig_on() try: CMR_CALL(CMRtuTest(cmr, self._mat, &result_bool, pdec, psubmat, @@ -2025,46 +2032,26 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): raise NotImplementedError -cdef _cmr_dec_construct(param): - if not param: - return CMR_DEC_CONSTRUCT_NONE - if param == 'leaves': - return CMR_DEC_CONSTRUCT_LEAVES - return CMR_DEC_CONSTRUCT_ALL - - -cdef _set_cmr_regular_parameters(CMR_REGULAR_PARAMS *params, dict kwds): - CMR_CALL(CMRregularParamsInit(params)) +cdef _set_cmr_seymour_parameters(CMR_SEYMOUR_PARAMS *params, dict kwds): + CMR_CALL(CMRseymourParamsInit(params)) + params.stopWhenIrregular = kwds['stop_when_irregular'] + params.stopWhenNongraphic = kwds['stop_when_nongraphic'] + params.stopWhenNoncographic = kwds['stop_when_noncographic'] + params.stopWhenNeitherGraphicNorCoGraphic = kwds['stop_when_nongraphic_and_noncographic'] params.directGraphicness = kwds['use_direct_graphicness_test'] + params.preferGraphicness = kwds['prefer_graphicness'] params.seriesParallel = kwds['series_parallel_ok'] params.planarityCheck = kwds['check_graphic_minors_planar'] params.threeSumPivotChildren = kwds['three_sum_pivot_children'] if kwds['three_sum_strategy'] is not None: if kwds['three_sum_strategy'] == 'Mixed_Mixed': - params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_CONCENTRATED_RANK | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_MIXED | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_MIXED + params.threeSumStrategy = CMR_SEYMOUR_THREESUM_FLAG_CONCENTRATED_RANK | CMR_SEYMOUR_THREESUM_FLAG_FIRST_MIXED | CMR_SEYMOUR_THREESUM_FLAG_SECOND_MIXED elif kwds['three_sum_strategy'] == 'Wide_Wide': - params.threeSumStrategy = CMR_MATROID_DEC_THREESUM_FLAG_DISTRIBUTED_RANKS | CMR_MATROID_DEC_THREESUM_FLAG_FIRST_WIDE | CMR_MATROID_DEC_THREESUM_FLAG_SECOND_WIDE + params.threeSumStrategy = CMR_SEYMOUR_THREESUM_FLAG_DISTRIBUTED_RANKS | CMR_SEYMOUR_THREESUM_FLAG_FIRST_WIDE | CMR_SEYMOUR_THREESUM_FLAG_SECOND_WIDE else: params.threeSumStrategy = kwds['three_sum_strategy'] - treeFlags_list = [] - if kwds['recurse'] is True: - treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_RECURSE) - if kwds['stop_when_irregular'] is True: - treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_IRREGULAR) - if kwds['stop_when_nongraphic'] is True: - treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC) - if kwds['stop_when_noncographic'] is True: - treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONCOGRAPHIC) - if kwds['stop_when_nongraphic_and_noncographic'] is True: - treeFlags_list.append(CMR_REGULAR_TREE_FLAGS_STOP_NONGRAPHIC_NONCOGRAPHIC) - if treeFlags_list: - treeFlag = 0 - for flag in treeFlags_list: - treeFlag |= flag - params.treeFlags = treeFlag - else: - params.treeFlags = 0 - params.graphs = _cmr_dec_construct(kwds['construct_graphs']) + params.constructLeafGraphs = kwds['construct_leaf_graphs'] + params.constructAllGraphs = kwds['construct_all_graphs'] cdef _sage_edge(CMR_GRAPH *graph, CMR_GRAPH_EDGE e): diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index e9df580b74a..a937278820c 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -1,17 +1,17 @@ # sage_setup: distribution = sagemath-cmr -from sage.libs.cmr.cmr cimport CMR_MATROID_DEC, CMR_ELEMENT +from sage.libs.cmr.cmr cimport CMR_SEYMOUR_NODE, CMR_ELEMENT from sage.structure.sage_object cimport SageObject cdef class DecompositionNode(SageObject): cdef object _base_ring cdef object _matrix - cdef CMR_MATROID_DEC *_dec + cdef CMR_SEYMOUR_NODE *_dec cdef object _row_keys cdef object _column_keys cdef object _child_nodes - cdef _set_dec(self, CMR_MATROID_DEC *dec) + cdef _set_dec(self, CMR_SEYMOUR_NODE *dec) cdef _set_root_dec(self) cdef _set_row_keys(self, row_keys) cdef _set_column_keys(self, column_keys) @@ -42,7 +42,7 @@ cdef class SymbolicNode(DecompositionNode): cdef object _symbol -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, +cdef create_DecompositionNode(CMR_SEYMOUR_NODE *dec, matrix=?, row_keys=?, column_keys=?, base_ring=?) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 56a8c0f5357..d19717d138e 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -26,7 +26,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.sage_object cimport SageObject from .constructor import Matrix -from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph, _set_cmr_regular_parameters +from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph, _set_cmr_seymour_parameters from .matrix_space import MatrixSpace @@ -66,16 +66,16 @@ cdef class DecompositionNode(SageObject): base_ring = self._matrix.parent().base_ring() self._base_ring = base_ring - cdef _set_dec(self, CMR_MATROID_DEC *dec): + cdef _set_dec(self, CMR_SEYMOUR_NODE *dec): if self._dec != NULL: # We own it, so we have to free it. - CMR_CALL(CMRmatroiddecRelease(cmr, &self._dec)) + CMR_CALL(CMRseymourRelease(cmr, &self._dec)) if dec != NULL: - CMR_CALL(CMRmatroiddecCapture(cmr, dec)) + CMR_CALL(CMRseymourCapture(cmr, dec)) self._dec = dec cdef _set_root_dec(self): - cdef CMR_MATROID_DEC *root + cdef CMR_SEYMOUR_NODE *root cdef Matrix_cmr_chr_sparse matrix try: matrix = self.matrix() @@ -89,7 +89,7 @@ cdef class DecompositionNode(SageObject): sig_on() try: - CMR_CALL(CMRmatroiddecCreateMatrixRoot(cmr, &root, isTernary, mat)) + CMR_CALL(CMRseymourCreate(cmr, &root, isTernary, mat)) finally: sig_off() self._set_dec(root) @@ -134,7 +134,7 @@ cdef class DecompositionNode(SageObject): if self._row_keys is not None: return len(self._row_keys) if self._dec != NULL: - return CMRmatroiddecNumRows(self._dec) + return CMRseymourNumRows(self._dec) if self._matrix is not None: return self._matrix.nrows() raise RuntimeError('nrows undefined') @@ -143,7 +143,7 @@ cdef class DecompositionNode(SageObject): if self._column_keys is not None: return len(self._column_keys) if self._dec != NULL: - return CMRmatroiddecNumColumns(self._dec) + return CMRseymourNumColumns(self._dec) if self._matrix is not None: return self._matrix.ncols() raise RuntimeError('ncols undefined') @@ -177,7 +177,7 @@ cdef class DecompositionNode(SageObject): if self._matrix is not None: return self._matrix cdef Matrix_cmr_chr_sparse result - cdef CMR_CHRMAT *mat = CMRmatroiddecGetMatrix(self._dec) + cdef CMR_CHRMAT *mat = CMRseymourGetMatrix(self._dec) if mat == NULL: return None ms = MatrixSpace(self.base_ring(), mat.numRows, mat.numColumns, sparse=True) @@ -267,7 +267,7 @@ cdef class DecompositionNode(SageObject): r""" Returns true iff the decomposition is over `\mathbb{F}_3`. """ - return CMRmatroiddecIsTernary(self._dec) + return CMRseymourIsTernary(self._dec) def nchildren(self): r""" @@ -277,7 +277,7 @@ cdef class DecompositionNode(SageObject): return len(self._child_nodes) if self._dec == NULL: return 0 - return CMRmatroiddecNumChildren(self._dec) + return CMRseymourNumChildren(self._dec) cdef _CMRelement_to_key(self, CMR_ELEMENT element): if not CMRelementIsValid(element): @@ -292,11 +292,11 @@ cdef class DecompositionNode(SageObject): def _create_child_node(self, index): row_keys = self.row_keys() column_keys = self.column_keys() - cdef CMR_MATROID_DEC *child_dec = CMRmatroiddecChild(self._dec, index) - cdef CMR_ELEMENT *parent_rows = CMRmatroiddecChildRowsToParent(self._dec, index) - cdef CMR_ELEMENT *parent_columns = CMRmatroiddecChildColumnsToParent(self._dec, index) - child_nrows = CMRmatroiddecNumRows(child_dec) - child_ncols = CMRmatroiddecNumColumns(child_dec) + cdef CMR_SEYMOUR_NODE *child_dec = CMRseymourChild(self._dec, index) + cdef CMR_ELEMENT *parent_rows = CMRseymourChildRowsToParent(self._dec, index) + cdef CMR_ELEMENT *parent_columns = CMRseymourChildColumnsToParent(self._dec, index) + child_nrows = CMRseymourNumRows(child_dec) + child_ncols = CMRseymourNumColumns(child_dec) if parent_rows == NULL or all(parent_rows[i] == 0 for i in range(child_nrows)): raise ValueError(f"Child {index} does not have parents rows") @@ -506,19 +506,19 @@ cdef class DecompositionNode(SageObject): return result def _regularity(self): - cdef int8_t regularity = CMRmatroiddecRegularity(self._dec) + cdef int8_t regularity = CMRseymourRegularity(self._dec) if regularity: return regularity > 0 raise ValueError('It is not determined whether the decomposition node is regular/TU') def _graphicness(self): - cdef int8_t graphicness = CMRmatroiddecGraphicness(self._dec) + cdef int8_t graphicness = CMRseymourGraphicness(self._dec) if graphicness: return graphicness > 0 raise ValueError('It is not determined whether the decomposition node is graphic/network') def _cographicness(self): - cdef int8_t cographicness = CMRmatroiddecCographicness(self._dec) + cdef int8_t cographicness = CMRseymourCographicness(self._dec) if cographicness: return cographicness > 0 raise ValueError('It is not determined whether the decomposition node is cographic/conetwork') @@ -645,6 +645,7 @@ cdef class DecompositionNode(SageObject): def _binary_linear_matroid_complete_decomposition(self, *, time_limit=60.0, use_direct_graphicness_test=True, + prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, recurse=True, @@ -654,7 +655,8 @@ cdef class DecompositionNode(SageObject): stop_when_nongraphic_and_noncographic=False, three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False): + construct_leaf_graphs=False, + construct_all_graphs=False): r""" EXAMPLES:: @@ -762,9 +764,9 @@ cdef class DecompositionNode(SageObject): """ cdef CMR_REGULAR_PARAMS params cdef CMR_REGULAR_STATS stats - cdef CMR_MATROID_DEC *clone = NULL + cdef CMR_SEYMOUR_NODE *clone = NULL - cdef CMR_MATROID_DEC **pclone = &clone + cdef CMR_SEYMOUR_NODE **pclone = &clone if self._dec == NULL: base_ring = self.base_ring() @@ -773,21 +775,22 @@ cdef class DecompositionNode(SageObject): self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + prefer_graphicness=prefer_graphicness, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=recurse, stop_when_irregular=stop_when_irregular, stop_when_nongraphic=stop_when_nongraphic, stop_when_noncographic=stop_when_noncographic, stop_when_nongraphic_and_noncographic=stop_when_nongraphic_and_noncographic, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, - construct_graphs=construct_graphs) - _set_cmr_regular_parameters(¶ms, kwds) + construct_leaf_graphs=construct_leaf_graphs, + construct_all_graphs=construct_all_graphs) + _set_cmr_seymour_parameters(¶ms.seymour, kwds) sig_on() try: - CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) + CMR_CALL(CMRseymourCloneUnknown(cmr, self._dec, pclone)) CMR_CALL(CMRregularCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) finally: sig_off() @@ -854,8 +857,58 @@ cdef class DecompositionNode(SageObject): # compute it... wait for CMR functions raise NotImplementedError("TU Not Determined") + def nminors(self): + r""" + Return the number of minors of the node. + """ + if self._minors is not None: + return len(self._minors) + if self._dec == NULL: + return 0 + return CMRseymourNumMinors(self._dec) + + def _create_minor(self, index): + cdef CMR_MINOR * minor = CMRseymourMinor(self._dec, index) + cdef CMR_MINOR_TYPE typ = CMRminorType(minor) + import sage.matroids.matroids_catalog as matroids + from sage.graphs.graph_generators import graphs + from sage.matroids.matroid import Matroid + + if typ == CMR_MINOR_TYPE_FANO: + return matroids.catalog.Fano() + if typ == CMR_MINOR_TYPE_FANO_DUAL: + return matroids.catalog.Fano().dual() + if typ == CMR_MINOR_TYPE_K5: + return matroids.CompleteGraphic(5) + if typ == CMR_MINOR_TYPE_K5_DUAL: + return matroids.CompleteGraphic(5).dual() + if typ == CMR_MINOR_TYPE_K33: + E = 'abcdefghi' + G = graphs.CompleteBipartiteGraph(3, 3) + return Matroid(groundset=E, graph=G, regular=True) + if typ == CMR_MINOR_TYPE_K33_DUAL: + return matroids.catalog.K33dual() + if typ == CMR_MINOR_TYPE_DETERMINANT: + return '|det| = 2 submatrix' + if typ == CMR_MINOR_TYPE_ENTRY: + return 'bad entry' + if typ == CMR_MINOR_TYPE_CUSTOM: + return 'custom' + + def _minors(self): + if self._minors is not None: + return self._minors + minors_tuple = tuple(self._create_minor(index) + for index in range(self.nminors())) + self._minors = minors_tuple + return self._minors + + def minors(self): + return self._minors() + def complete_decomposition(self, *, time_limit=60.0, use_direct_graphicness_test=True, + prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, recurse=True, @@ -865,7 +918,8 @@ cdef class DecompositionNode(SageObject): stop_when_nonnetwork_and_nonconetwork=False, three_sum_pivot_children=False, three_sum_strategy=None, - construct_graphs=False): + construct_leaf_graphs=False, + construct_all_graphs=False): r""" EXAMPLES:: @@ -926,31 +980,33 @@ cdef class DecompositionNode(SageObject): """ cdef CMR_TU_PARAMS params cdef CMR_TU_STATS stats - cdef CMR_MATROID_DEC *clone = NULL + cdef CMR_SEYMOUR_NODE *clone = NULL - cdef CMR_MATROID_DEC **pclone = &clone + cdef CMR_SEYMOUR_NODE **pclone = &clone if self._dec == NULL: self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, + prefer_graphicness=prefer_graphicness, series_parallel_ok=series_parallel_ok, check_graphic_minors_planar=check_graphic_minors_planar, - recurse=recurse, stop_when_irregular=stop_when_nonTU, stop_when_nongraphic=stop_when_nonnetwork, stop_when_noncographic=stop_when_nonconetwork, stop_when_nongraphic_and_noncographic=stop_when_nonnetwork_and_nonconetwork, three_sum_pivot_children=three_sum_pivot_children, three_sum_strategy=three_sum_strategy, - construct_graphs=construct_graphs) + construct_leaf_graphs=construct_leaf_graphs, + construct_all_graphs=construct_all_graphs) params.algorithm = CMR_TU_ALGORITHM_DECOMPOSITION - params.directCamion = False - _set_cmr_regular_parameters(¶ms.regular, kwds) + params.ternary = True + params.camionFirst = False + _set_cmr_seymour_parameters(¶ms.seymour, kwds) sig_on() try: - CMR_CALL(CMRmatroiddecCloneUnknown(cmr, self._dec, pclone)) + CMR_CALL(CMRseymourCloneUnknown(cmr, self._dec, pclone)) CMR_CALL(CMRtuCompleteDecomposition(cmr, clone, ¶ms, &stats, time_limit)) finally: sig_off() @@ -1549,20 +1605,20 @@ cdef class ThreeSumNode(SumNode): self.set_default_keys() - cdef CMR_MATROID_DEC *child1_dec = CMRmatroiddecChild(self._dec, 0) - cdef CMR_ELEMENT *parent_rows1 = CMRmatroiddecChildRowsToParent(self._dec, 0) - cdef CMR_ELEMENT *parent_columns1 = CMRmatroiddecChildColumnsToParent(self._dec, 0) - cdef CMR_CHRMAT *mat1 = CMRmatroiddecGetMatrix(child1_dec) + cdef CMR_SEYMOUR_NODE *child1_dec = CMRseymourChild(self._dec, 0) + cdef CMR_ELEMENT *parent_rows1 = CMRseymourChildRowsToParent(self._dec, 0) + cdef CMR_ELEMENT *parent_columns1 = CMRseymourChildColumnsToParent(self._dec, 0) + cdef CMR_CHRMAT *mat1 = CMRseymourGetMatrix(child1_dec) - cdef CMR_MATROID_DEC *child2_dec = CMRmatroiddecChild(self._dec, 1) - cdef CMR_ELEMENT *parent_rows2 = CMRmatroiddecChildRowsToParent(self._dec, 1) - cdef CMR_ELEMENT *parent_columns2 = CMRmatroiddecChildColumnsToParent(self._dec, 1) - cdef CMR_CHRMAT *mat2 = CMRmatroiddecGetMatrix(child2_dec) + cdef CMR_SEYMOUR_NODE *child2_dec = CMRseymourChild(self._dec, 1) + cdef CMR_ELEMENT *parent_rows2 = CMRseymourChildRowsToParent(self._dec, 1) + cdef CMR_ELEMENT *parent_columns2 = CMRseymourChildColumnsToParent(self._dec, 1) + cdef CMR_CHRMAT *mat2 = CMRseymourGetMatrix(child2_dec) cdef size_t index1, index2 - child1_nrows = CMRmatroiddecNumRows(child1_dec) - child1_ncols = CMRmatroiddecNumColumns(child1_dec) + child1_nrows = CMRseymourNumRows(child1_dec) + child1_ncols = CMRseymourNumColumns(child1_dec) if self.is_concentrated_rank(): # Mixed_Mixed child1_row_keys = tuple(self._CMRelement_to_key(parent_rows1[i]) @@ -1627,8 +1683,8 @@ cdef class ThreeSumNode(SumNode): column_keys=child1_column_keys, base_ring=self.base_ring()) - child2_nrows = CMRmatroiddecNumRows(child2_dec) - child2_ncols = CMRmatroiddecNumColumns(child2_dec) + child2_nrows = CMRseymourNumRows(child2_dec) + child2_ncols = CMRseymourNumColumns(child2_dec) if self.is_concentrated_rank(): # Mixed_Mixed child2_row_keys = tuple(self._CMRelement_to_key(parent_rows2[i]) @@ -1717,10 +1773,10 @@ cdef class ThreeSumNode(SumNode): sage: C.is_concentrated_rank() False """ - return CMRmatroiddecThreeSumDistributedRanks(self._dec) + return CMRseymourThreeSumDistributedRanks(self._dec) def is_concentrated_rank(self): - return CMRmatroiddecThreeSumConcentratedRank(self._dec) + return CMRseymourThreeSumConcentratedRank(self._dec) def block_matrix_form(self): r""" @@ -1801,7 +1857,7 @@ cdef class BaseGraphicNode(DecompositionNode): """ if self._graph is not None: return self._graph - self._graph = _sage_graph(CMRmatroiddecGraph(self._dec)) + self._graph = _sage_graph(CMRseymourGraph(self._dec)) return self._graph def forest_edges(self): @@ -1844,18 +1900,18 @@ cdef class BaseGraphicNode(DecompositionNode): """ if self._forest_edges is not None: return self._forest_edges - cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - cdef size_t num_edges = CMRmatroiddecGraphSizeForest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphForest(self._dec) + cdef CMR_GRAPH *graph = CMRseymourGraph(self._dec) + cdef size_t num_edges = CMRseymourGraphSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourGraphForest(self._dec) self._forest_edges = _sage_edges(graph, edges, num_edges, self.row_keys()) return self._forest_edges def coforest_edges(self): if self._coforest_edges is not None: return self._coforest_edges - cdef CMR_GRAPH *graph = CMRmatroiddecGraph(self._dec) - cdef size_t num_edges = CMRmatroiddecGraphSizeCoforest(self._dec) - cdef CMR_GRAPH_EDGE *edges = CMRmatroiddecGraphCoforest(self._dec) + cdef CMR_GRAPH *graph = CMRseymourGraph(self._dec) + cdef size_t num_edges = CMRseymourGraphSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourGraphCoforest(self._dec) self._coforest_edges = _sage_edges(graph, edges, num_edges, self.column_keys()) return self._coforest_edges @@ -1871,13 +1927,13 @@ cdef class CographicNode(BaseGraphicNode): r""" Actually the cograph of matrix, in the case where it is not graphic. """ - return _sage_graph(CMRmatroiddecCograph(self._dec)) + return _sage_graph(CMRseymourCograph(self._dec)) cdef class PlanarNode(BaseGraphicNode): @cached_method def cograph(self): - return _sage_graph(CMRmatroiddecCograph(self._dec)) + return _sage_graph(CMRseymourCograph(self._dec)) cdef class SeriesParallelReductionNode(DecompositionNode): @@ -1909,36 +1965,18 @@ cdef class SeriesParallelReductionNode(DecompositionNode): return self.child_nodes()[0].matrix() -cdef class SpecialLeafNode(DecompositionNode): +cdef class R10Node(DecompositionNode): @cached_method def _matroid(self): r""" """ - cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(self._dec) + cdef CMR_SEYMOUR_NODE_TYPE typ = CMRseymourType(self._dec) import sage.matroids.matroids_catalog as matroids - from sage.graphs.graph_generators import graphs - from sage.matroids.matroid import Matroid - if typ == CMR_MATROID_DEC_TYPE_R10: + if typ == CMR_SEYMOUR_NODE_TYPE_R10: return matroids.catalog.R10() - if typ == CMR_MATROID_DEC_TYPE_FANO: - return matroids.catalog.Fano() - if typ == CMR_MATROID_DEC_TYPE_FANO_DUAL: - return matroids.catalog.Fano().dual() - if typ == CMR_MATROID_DEC_TYPE_K5: - return matroids.CompleteGraphic(5) - if typ == CMR_MATROID_DEC_TYPE_K5_DUAL: - return matroids.CompleteGraphic(5).dual() - if typ == CMR_MATROID_DEC_TYPE_K33: - E = 'abcdefghi' - G = graphs.CompleteBipartiteGraph(3, 3) - return Matroid(groundset=E, graph=G, regular=True) - if typ == CMR_MATROID_DEC_TYPE_K33_DUAL: - return matroids.catalog.K33dual() - if typ == CMR_MATROID_DEC_TYPE_DETERMINANT: - return '|det| = 2 submatrix' assert False, 'special leaf node with unknown type' def _repr_(self): @@ -1951,14 +1989,14 @@ cdef class SpecialLeafNode(DecompositionNode): assert NotImplementedError # cdef int representation_matrix - # cdef CMR_MATROID_DEC_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) + # cdef CMR_SEYMOUR_NODE_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) # return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) cdef class PivotsNode(DecompositionNode): def npivots(self): - return CMRmatroiddecNumPivots(self._dec) + return CMRseymourNumPivots(self._dec) @cached_method def pivot_rows_and_columns(self): @@ -1982,8 +2020,8 @@ cdef class PivotsNode(DecompositionNode): sage: certificate.pivot_rows_and_columns() ((1, 8),) """ - cdef size_t *pivot_rows = CMRmatroiddecPivotRows(self._dec) - cdef size_t *pivot_columns = CMRmatroiddecPivotColumns(self._dec) + cdef size_t *pivot_rows = CMRseymourPivotRows(self._dec) + cdef size_t *pivot_columns = CMRseymourPivotColumns(self._dec) return tuple((pivot_rows[i], pivot_columns[i]) for i in range(self.npivots())) @@ -1999,10 +2037,6 @@ cdef class PivotsNode(DecompositionNode): return self._child_nodes -cdef class SubmatrixNode(DecompositionNode): - pass - - cdef class SymbolicNode(DecompositionNode): def __init__(self, symbol, *, row_keys=None, column_keys=None, base_ring=None): @@ -2100,43 +2134,41 @@ cdef class ElementKey: return "".join([str(a) for a in self._key]) -cdef _class(CMR_MATROID_DEC *dec): - cdef CMR_MATROID_DEC_TYPE typ = CMRmatroiddecType(dec) +cdef _class(CMR_SEYMOUR_NODE *dec): + cdef CMR_SEYMOUR_NODE_TYPE typ = CMRseymourType(dec) - if typ == CMR_MATROID_DEC_TYPE_ONE_SUM: + if typ == CMR_SEYMOUR_NODE_TYPE_ONE_SUM: return OneSumNode - if typ == CMR_MATROID_DEC_TYPE_TWO_SUM: + if typ == CMR_SEYMOUR_NODE_TYPE_TWO_SUM: return TwoSumNode - if typ == CMR_MATROID_DEC_TYPE_THREE_SUM: + if typ == CMR_SEYMOUR_NODE_TYPE_THREE_SUM: return ThreeSumNode - if typ == CMR_MATROID_DEC_TYPE_GRAPH: + if typ == CMR_SEYMOUR_NODE_TYPE_GRAPH: return GraphicNode - if typ == CMR_MATROID_DEC_TYPE_COGRAPH: + if typ == CMR_SEYMOUR_NODE_TYPE_COGRAPH: return CographicNode - if typ == CMR_MATROID_DEC_TYPE_PLANAR: + if typ == CMR_SEYMOUR_NODE_TYPE_PLANAR: return PlanarNode - if typ < -1: - return SpecialLeafNode - if typ == CMR_MATROID_DEC_TYPE_SERIES_PARALLEL: + if typ == CMR_SEYMOUR_NODE_TYPE_SERIES_PARALLEL: return SeriesParallelReductionNode - if typ == CMR_MATROID_DEC_TYPE_PIVOTS: + if typ == CMR_SEYMOUR_NODE_TYPE_PIVOTS: return PivotsNode - if typ == CMR_MATROID_DEC_TYPE_SUBMATRIX: - return SubmatrixNode - if typ == CMR_MATROID_DEC_TYPE_IRREGULAR: + if typ == CMR_SEYMOUR_NODE_TYPE_IRREGULAR: return ThreeConnectedIrregularNode - if typ == CMR_MATROID_DEC_TYPE_UNKNOWN: + if typ == CMR_SEYMOUR_NODE_TYPE_UNKNOWN: return UnknownNode + if typ == CMR_SEYMOUR_NODE_TYPE_R10: + return R10Node raise NotImplementedError -cdef create_DecompositionNode(CMR_MATROID_DEC *dec, matrix=None, row_keys=None, column_keys=None, base_ring=None): +cdef create_DecompositionNode(CMR_SEYMOUR_NODE *dec, matrix=None, row_keys=None, column_keys=None, base_ring=None): r""" Create an instance of a subclass of :class:`DecompositionNode`. INPUT: - - ``dec`` -- a ``CMR_MATROID_DEC`` + - ``dec`` -- a ``CMR_SEYMOUR_NODE`` """ if dec == NULL: return None From 98744a5ad9780486ffed3138f85b8878f12392be Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 20 Jun 2024 16:38:52 -0700 Subject: [PATCH 218/262] build/pkgs/cmr: Update to fd241e963d244d6ecf9b3f03af59c1e214bd4248 --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 954ace794a7..54c57a647ce 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=b5921d918333b4a37acbd6644742a04004cff40d -sha256=6c48947762362ef8a20a5cc703dedcf86457630b9784c172d3347f55535d2c10 +sha1=d54f5286788e014ecef6b04b4e1a47fb542b6589 +sha256=8b125a3b14fc29cadfcc4d01a908d1d9c2b0856f33afd74a9a70071b4482663e upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 48aedaf2c93..43f276819d9 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -b0a60ad3ce782c59513f016c96e1d08f7d955bee +fd241e963d244d6ecf9b3f03af59c1e214bd4248 From 72e9d28fa488e90f86af103b5fb0a9c55e25b903 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 27 Jun 2024 11:14:11 -0700 Subject: [PATCH 219/262] delete the key recurse and fix doctests --- src/sage/matrix/matrix_cmr_sparse.pyx | 16 +++--- src/sage/matrix/seymour_decomposition.pyx | 59 +++++++---------------- 2 files changed, 23 insertions(+), 52 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e3ad0fa936c..2192740ed00 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1947,22 +1947,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) - ╭──────OneSumNode (9×9) with 2 children──────╮ - │ │ - SubmatrixNode (5×4) UnknownNode (4×5) - │ - Isomorphic to a minor of |det| = 2 submatrix + ╭OneSumNode (9×9) with 2 children─╮ + │ │ + ThreeConnectedIrregularNode (5×4) UnknownNode (4×5) sage: result, certificate = M.is_totally_unimodular( ....: certificate=True, ....: stop_when_nonTU=False) sage: result, certificate (False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0)))) sage: unicode_art(certificate[0]) - ╭──────OneSumNode (9×9) with 2 children──────╮ - │ │ - SubmatrixNode (5×4) SubmatrixNode (4×5) - │ │ - Isomorphic to a minor of |det| = 2 submatrix Isomorphic to a minor of |det| = 2 submatrix + ╭OneSumNode (9×9) with 2 children─╮ + │ │ + ThreeConnectedIrregularNode (5×4) ThreeConnectedIrregularNode (4×5) """ base_ring = self.parent().base_ring() if base_ring.characteristic() not in [0, 3] : diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index d19717d138e..5e627f2276f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -541,7 +541,6 @@ cdef class DecompositionNode(SageObject): except ValueError: # compute it... wait for CMR functions full_dec = self._binary_linear_matroid_complete_decomposition( - recurse=True, stop_when_nongraphic=True, check_graphic_minors_planar=True) return full_dec._is_binary_linear_matroid_graphic( @@ -566,7 +565,6 @@ cdef class DecompositionNode(SageObject): except ValueError: # compute it... wait for CMR functions full_dec = self._binary_linear_matroid_complete_decomposition( - recurse=True, stop_when_noncographic=True, check_graphic_minors_planar=True) return full_dec._is_binary_linear_matroid_cographic( @@ -590,7 +588,7 @@ cdef class DecompositionNode(SageObject): ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M) - sage: C0 = node._binary_linear_matroid_complete_decomposition(recurse=False) + sage: C0 = node._binary_linear_matroid_complete_decomposition() sage: C0 OneSumNode (9×9) with 2 children sage: result, decomposition = C0._is_binary_linear_matroid_graphic(decomposition=True) @@ -599,7 +597,7 @@ cdef class DecompositionNode(SageObject): sage: unicode_art(decomposition) ╭───────────OneSumNode (9×9) with 2 children │ │ - GraphicNode (5×4) UnknownNode (4×5) + GraphicNode (5×4) CographicNode (4×5) sage: decomposition.child_nodes()[1]._graphicness() False sage: result, decomposition = C0._is_binary_linear_matroid_cographic(decomposition=True) @@ -635,7 +633,6 @@ cdef class DecompositionNode(SageObject): except ValueError: # compute it... wait for CMR functions full_dec = self._binary_linear_matroid_complete_decomposition( - recurse=True, stop_when_irregular=True, check_graphic_minors_planar=True) return full_dec._is_binary_linear_matroid_regular( @@ -648,7 +645,6 @@ cdef class DecompositionNode(SageObject): prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, - recurse=True, stop_when_irregular=False, stop_when_nongraphic=False, stop_when_noncographic=False, @@ -674,15 +670,15 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M); node UnknownNode (9×9) - sage: C0 = node._binary_linear_matroid_complete_decomposition(recurse=False) + sage: C0 = node._binary_linear_matroid_complete_decomposition() sage: C0 OneSumNode (9×9) with 2 children sage: unicode_art(C0) ╭───────────OneSumNode (9×9) with 2 children │ │ - UnknownNode (5×4) UnknownNode (4×5) + GraphicNode (5×4) CographicNode (4×5) sage: C1, C2 = C0.child_nodes() - sage: C11 = C1._binary_linear_matroid_complete_decomposition(recurse=False); C11 + sage: C11 = C1._binary_linear_matroid_complete_decomposition(); C11 GraphicNode (5×4) sage: unicode_art(C11) GraphicNode (5×4) @@ -698,7 +694,7 @@ cdef class DecompositionNode(SageObject): [0 1 1 1] [1 0 0 1] [0 0 1 1] - sage: C22 = C2._binary_linear_matroid_complete_decomposition(recurse=False); C22 + sage: C22 = C2._binary_linear_matroid_complete_decomposition(); C22 CographicNode (4×5) sage: unicode_art(C22) CographicNode (4×5) @@ -719,7 +715,6 @@ cdef class DecompositionNode(SageObject): sage: unicode_art(node) UnknownNode (9×9) sage: certificate1 = node._binary_linear_matroid_complete_decomposition( - ....: recurse=True, ....: stop_when_noncographic=True, ....: check_graphic_minors_planar=True) sage: unicode_art(certificate1) @@ -727,7 +722,6 @@ cdef class DecompositionNode(SageObject): │ │ GraphicNode (5×4) UnknownNode (4×5) sage: certificate2 = node._binary_linear_matroid_complete_decomposition( - ....: recurse=True, ....: stop_when_noncographic=True) sage: unicode_art(certificate2) ╭───────────OneSumNode (9×9) with 2 children @@ -735,7 +729,6 @@ cdef class DecompositionNode(SageObject): GraphicNode (5×4) CographicNode (4×5) sage: certificate1 = node._binary_linear_matroid_complete_decomposition( - ....: recurse=True, ....: stop_when_nongraphic=True, ....: check_graphic_minors_planar=True) sage: unicode_art(certificate1) @@ -748,7 +741,6 @@ cdef class DecompositionNode(SageObject): sage: C2._graphicness() False sage: certificate2 = node._binary_linear_matroid_complete_decomposition( - ....: recurse=True, ....: stop_when_nongraphic=True) sage: unicode_art(certificate2) ╭───────────OneSumNode (9×9) with 2 children @@ -911,7 +903,6 @@ cdef class DecompositionNode(SageObject): prefer_graphicness=True, series_parallel_ok=True, check_graphic_minors_planar=False, - recurse=True, stop_when_nonTU=False, stop_when_nonnetwork=False, stop_when_nonconetwork=False, @@ -937,18 +928,16 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M); node UnknownNode (9×9) - sage: C0 = node.complete_decomposition(recurse=False) + sage: C0 = node.complete_decomposition() sage: unicode_art(C0) - ╭───────────OneSumNode (9×9) with 2 children - │ │ - UnknownNode (5×4) UnknownNode (4×5) + ╭OneSumNode (9×9) with 2 children─╮ + │ │ + ThreeConnectedIrregularNode (5×4) ThreeConnectedIrregularNode (4×5) sage: C1, C2 = C0.child_nodes() - sage: C11 = C1.complete_decomposition(recurse=False); C11 - SubmatrixNode (5×4) + sage: C11 = C1.complete_decomposition(); C11 + ThreeConnectedIrregularNode (5×4) sage: unicode_art(C11) - SubmatrixNode (5×4) - │ - Isomorphic to a minor of |det| = 2 submatrix + ThreeConnectedIrregularNode (5×4) sage: C1.matrix() [1 1 0 0] [1 1 1 0] @@ -962,11 +951,9 @@ cdef class DecompositionNode(SageObject): [1 0 0 1] [0 0 1 1] sage: C22 = C2.complete_decomposition(); C22 - SubmatrixNode (4×5) + ThreeConnectedIrregularNode (4×5) sage: unicode_art(C22) - SubmatrixNode (4×5) - │ - Isomorphic to a minor of |det| = 2 submatrix + ThreeConnectedIrregularNode (4×5) sage: C2.matrix() [1 1 1 0 0] [0 0 1 1 1] @@ -1492,7 +1479,6 @@ cdef class ThreeSumNode(SumNode): ....: column_keys='abcdef'); node UnknownNode (6×6) sage: C0 = node.complete_decomposition( - ....: recurse=False, ....: three_sum_strategy="Wide_Wide", ....: ) sage: C0 @@ -1500,22 +1486,11 @@ cdef class ThreeSumNode(SumNode): sage: unicode_art(C0) PivotsNode (6×6) │ - ╭──────────ThreeSumNode (6×6) with 2 children - │ │ - UnknownNode (4×5) UnknownNode (4×5) - sage: unicode_art(C0.complete_decomposition(recurse=True, stop_when_nonTU=True, - ....: three_sum_strategy="Wide_Wide")) - PivotsNode (6×6) - │ ╭─────────────ThreeSumNode (6×6) with 2 children │ │ CographicNode (4×5) GraphicNode (4×5) - sage: unicode_art(C0) - PivotsNode (6×6) - │ - ╭──────────ThreeSumNode (6×6) with 2 children - │ │ - UnknownNode (4×5) UnknownNode (4×5) + sage: unicode_art(node) + UnknownNode (6×6) sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), From d272ff3b36b864918b913afe50e481d0412ec4f5 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 27 Jun 2024 11:15:01 -0700 Subject: [PATCH 220/262] build/pkgs/cmr: Update to b90c33010f51ab631c288b8b6b56e670d5760ce5 --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index 54c57a647ce..e3409173e95 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=d54f5286788e014ecef6b04b4e1a47fb542b6589 -sha256=8b125a3b14fc29cadfcc4d01a908d1d9c2b0856f33afd74a9a70071b4482663e +sha1=cb8010fa3d2c05784392ac76dc418e95c9565fa3 +sha256=9c272b8cd1148f633584eb561a78fafba0390af4dd80aca8170e82e776bc3d41 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 43f276819d9..11b1be03bfc 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -fd241e963d244d6ecf9b3f03af59c1e214bd4248 +b90c33010f51ab631c288b8b6b56e670d5760ce5 From b8f207747df83520d33145e13d48fabbb974107f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 27 Jun 2024 11:59:17 -0700 Subject: [PATCH 221/262] update cmr and WIP minor --- src/sage/libs/cmr/cmr.pxd | 14 ++++++--- src/sage/matrix/seymour_decomposition.pxd | 1 + src/sage/matrix/seymour_decomposition.pyx | 37 ++++++++++++++++++++--- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index 8e1792370d6..c8067eb4da7 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -199,6 +199,10 @@ cdef extern from "cmr/matroid.h": CMR_ERROR CMRminorCreate(CMR* cmr, CMR_MINOR** pminor, size_t numPivots, CMR_SUBMAT* submatrix, CMR_MINOR_TYPE type) CMR_ERROR CMRminorFree(CMR* cmr, CMR_MINOR** pminor) CMR_MINOR_TYPE CMRminorType(CMR_MINOR* minor) + size_t CMRminorNumPivots(CMR_MINOR* minor) + size_t* CMRminorPivotRows(CMR_MINOR* minor) + size_t* CMRminorPivotColumns(CMR_MINOR* minor) + CMR_SUBMAT* CMRminorSubmatrix(CMR_MINOR* minor) # CMR_ERROR CMRminorWriteToFile(CMR* cmr, CMR_MINOR* minor, size_t numRows, size_t numColumns, const char* fileName) cdef extern from "cmr/separation.h": @@ -286,10 +290,10 @@ cdef extern from "cmr/series_parallel.h": bint CMRspIsCopy(CMR_SP_REDUCTION reduction) bint CMRspIsValid(CMR_SP_REDUCTION reduction) - CMR_ERROR CMRtestBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRtestTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRdecomposeBinarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) - CMR_ERROR CMRdecomposeTernarySeriesParallel(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRspTestBinary(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRspTestTernary(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRspDecomposeBinary(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) + CMR_ERROR CMRspDecomposeTernary(CMR* cmr, CMR_CHRMAT* matrix, bool* pisSeriesParallel, CMR_SP_REDUCTION* reductions, size_t maxNumReductions, size_t* pnumReductions, CMR_SUBMAT** preducedSubmatrix, CMR_SUBMAT** pviolatorSubmatrix, CMR_SEPA** pseparation, CMR_SP_STATISTICS* stats, double timeLimit) cdef extern from "cmr/network.h": @@ -513,7 +517,7 @@ cdef extern from "cmr/ctu.h": CMR_ERROR CMRstatsComplementTotalUnimodularityInit(CMR_CTU_STATS* stats) # CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(FILE* stream, CMR_CTU_STATS* stats, const char* prefix) - CMR_ERROR CMRcomplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) + CMR_ERROR CMRctuComplementRowColumn(CMR* cmr, CMR_CHRMAT* matrix, size_t complementRow, size_t complementColumn, CMR_CHRMAT** presult) CMR_ERROR CMRctuTest(CMR* cmr, CMR_CHRMAT* matrix, bool* pisComplementTotallyUnimodular, size_t* pcomplementRow, size_t* pcomplementColumn, CMR_CTU_PARAMS* params, CMR_CTU_STATS* stats, double timeLimit) diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index a937278820c..b314f25827e 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -10,6 +10,7 @@ cdef class DecompositionNode(SageObject): cdef object _row_keys cdef object _column_keys cdef object _child_nodes + cdef object _minors cdef _set_dec(self, CMR_SEYMOUR_NODE *dec) cdef _set_root_dec(self) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 5e627f2276f..206541dd57f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -862,6 +862,14 @@ cdef class DecompositionNode(SageObject): def _create_minor(self, index): cdef CMR_MINOR * minor = CMRseymourMinor(self._dec, index) cdef CMR_MINOR_TYPE typ = CMRminorType(minor) + cdef size_t npivots = CMRminorNumPivots(minor) + cdef size_t *pivot_rows = CMRminorPivotRows(minor) + cdef size_t *pivot_columns = CMRminorPivotColumns(minor) + cdef CMR_SUBMAT *submat = CMRminorSubmatrix(minor) + + pivots_tuple = tuple((pivot_rows[i], pivot_columns[i]) for i in range(npivots)) + submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), + tuple(submat.columns[i] for i in range(submat.numColumns))) import sage.matroids.matroids_catalog as matroids from sage.graphs.graph_generators import graphs from sage.matroids.matroid import Matroid @@ -881,13 +889,35 @@ cdef class DecompositionNode(SageObject): if typ == CMR_MINOR_TYPE_K33_DUAL: return matroids.catalog.K33dual() if typ == CMR_MINOR_TYPE_DETERMINANT: - return '|det| = 2 submatrix' + return '|det| = 2 submatrix', submat_tuple if typ == CMR_MINOR_TYPE_ENTRY: return 'bad entry' if typ == CMR_MINOR_TYPE_CUSTOM: return 'custom' - def _minors(self): + def minors(self): + r""" + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: C0 = UnknownNode(M).complete_decomposition() + sage: C1, C2 = C0.child_nodes() + sage: C1.minors() + (('|det| = 2 submatrix', ((4, 3, 1), (2, 3, 0))),) + sage: C2.minors() + (('|det| = 2 submatrix', ((2, 1, 0), (4, 2, 1))),) + """ if self._minors is not None: return self._minors minors_tuple = tuple(self._create_minor(index) @@ -895,9 +925,6 @@ cdef class DecompositionNode(SageObject): self._minors = minors_tuple return self._minors - def minors(self): - return self._minors() - def complete_decomposition(self, *, time_limit=60.0, use_direct_graphicness_test=True, prefer_graphicness=True, From 231fb1964e2521932594a090be302bed141a1682 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 29 Jul 2024 07:41:00 -0700 Subject: [PATCH 222/262] build/pkgs/cmr: Update to c6ff00c615e6ee0e644912c84fe3c5bc2b5d29e6 --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index e3409173e95..d2b69b73f1b 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=cb8010fa3d2c05784392ac76dc418e95c9565fa3 -sha256=9c272b8cd1148f633584eb561a78fafba0390af4dd80aca8170e82e776bc3d41 +sha1=b1ec972c1dbecf25841293ce8b0abdc0f174eba8 +sha256=735cb369799da59383a4c53fdd4c6972dfee86d7cd7726cb653c550513ba4ead upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 11b1be03bfc..785d4a50283 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -b90c33010f51ab631c288b8b6b56e670d5760ce5 +c6ff00c615e6ee0e644912c84fe3c5bc2b5d29e6 From b846604fd0804a2c2c7c1ef8910fdaa7f36fe387 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 29 Jul 2024 08:02:38 -0700 Subject: [PATCH 223/262] Change ZoomSubmat to Slice --- src/sage/libs/cmr/cmr.pxd | 4 ++-- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index c8067eb4da7..d22398bd60e 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -61,7 +61,7 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRintmatSortNonzeros(CMR* cmr, CMR_INTMAT* matrix) # CMR_ERROR CMRintmatPrintDense(CMR* cmr, CMR_INTMAT* matrix, FILE* stream, char zeroChar, bint header) CMR_ERROR CMRintmatFindEntry(CMR_INTMAT* matrix, size_t row, size_t column, size_t* pentry) - CMR_ERROR CMRintmatZoomSubmat(CMR* cmr, CMR_INTMAT* matrix, CMR_SUBMAT* submatrix, CMR_INTMAT** presult) + CMR_ERROR CMRintmatSlice(CMR* cmr, CMR_INTMAT* matrix, CMR_SUBMAT* submatrix, CMR_INTMAT** presult) CMR_ERROR CMRintmatFree(CMR* cmr, CMR_INTMAT** pmatrix) ctypedef struct CMR_CHRMAT: @@ -76,7 +76,7 @@ cdef extern from "cmr/matrix.h": CMR_ERROR CMRchrmatSortNonzeros(CMR* cmr, CMR_CHRMAT* matrix) # CMR_ERROR CMRchrmatPrintDense(CMR* cmr, CMR_CHRMAT* matrix, FILE* stream, char zeroChar, bint header) CMR_ERROR CMRchrmatFindEntry(CMR_CHRMAT* matrix, size_t row, size_t column, size_t* pentry) - CMR_ERROR CMRchrmatZoomSubmat(CMR* cmr, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, CMR_CHRMAT** presult) + CMR_ERROR CMRchrmatSlice(CMR* cmr, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, CMR_CHRMAT** presult) CMR_ERROR CMRchrmatFree(CMR* cmr, CMR_CHRMAT** pmatrix) CMR_ERROR CMRchrmatToInt(CMR* cmr, CMR_CHRMAT* matrix, CMR_INTMAT** presult) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 2192740ed00..1c0628a2503 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -191,7 +191,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): for j in range(submatrix.numColumns): submatrix.columns[j] = columns[j] - CMR_CALL(CMRchrmatZoomSubmat(cmr, self._mat, submatrix, &cmr_submatrix)) + CMR_CALL(CMRchrmatSlice(cmr, self._mat, submatrix, &cmr_submatrix)) finally: CMR_CALL(CMRsubmatFree(cmr, &submatrix)) From c604dbe4c3567c2ddfecca6808453f7efa4b3a05 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Oct 2024 13:28:44 -0700 Subject: [PATCH 224/262] add algorithm=cmr to is_regular in matroid --- src/sage/matroids/matroid.pxd | 4 +-- src/sage/matroids/matroid.pyx | 48 +++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/sage/matroids/matroid.pxd b/src/sage/matroids/matroid.pxd index 6218cb804f4..61432ef4cec 100644 --- a/src/sage/matroids/matroid.pxd +++ b/src/sage/matroids/matroid.pxd @@ -195,8 +195,8 @@ cdef class Matroid(SageObject): cpdef _local_ternary_matroid(self, basis=*) cpdef ternary_matroid(self, randomized_tests=*, verify=*) cpdef is_ternary(self, randomized_tests=*) - cpdef bint is_regular(self) noexcept - cpdef bint is_graphic(self) noexcept + cpdef bint is_regular(self, algorithm=*) noexcept + cpdef bint is_graphic(self) except -1 # matroid k-closed cpdef is_k_closed(self, int k) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 0384ff81a22..03757e705ca 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6612,7 +6612,7 @@ cdef class Matroid(SageObject): return False return True - cpdef bint is_regular(self) noexcept: + cpdef bint is_regular(self, algorithm="cmr") except -1: r""" Return if ``self`` is regular. @@ -6623,25 +6623,57 @@ cdef class Matroid(SageObject): Alternatively, a matroid is regular if and only if it has no minor isomorphic to `U_{2, 4}`, `F_7`, or `F_7^*`. + INPUT: + + - ``algorithm`` -- (default: ``"cmr"``); specify which algorithm + to check regularity: + + - ``None`` -- an algorithm based on excluded minors. + - ``"cmr"`` -- an algorithm based on Seymour's decomposition, + the optional package "cmr" is required. + + .. SEEALSO:: + + :meth:`M.is_regular() ` + :meth:`M.is_regular() ` + :meth:`M._is_binary_linear_matroid_regular() ` + :meth:`M.is_totally_unimodular() ` + EXAMPLES:: sage: M = matroids.catalog.Wheel4() sage: M.is_regular() True sage: M = matroids.catalog.R9() - sage: M.is_regular() + sage: M.is_regular() # optional - cmr + False + sage: from sage.matroids.advanced import LinearMatroid + sage: M1 = LinearMatroid(Matrix(ZZ,[[1,0,1,1],[0,1,1,-1]])) + sage: M1.is_regular() # optional - cmr False REFERENCES: - [Oxl2011]_, p. 373. + [Oxl2011]_, p. 373, chapter 13. """ - if not self.is_binary(): # equivalent to checking for a U24 minor - return False - from sage.matroids.database_matroids import Fano, FanoDual - if self.has_minor(Fano()) or self.has_minor(FanoDual()): + M = self.binary_matroid() + if M is None: # equivalent to checking for a U24 minor return False - return True + if algorithm is None: + from sage.matroids.database_matroids import Fano, FanoDual + if self.has_minor(Fano()) or self.has_minor(FanoDual()): + return False + return True + if algorithm == "cmr": + from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + A = M.representation() + A_cmr = Matrix_cmr_chr_sparse(A.parent(), A) + return A_cmr._is_binary_linear_matroid_regular() + raise ValueError("Not a valid algorithm.") # matroid k-closed From 9f4ae3ef2bb61b04782434e6a07639f5547f2a99 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Oct 2024 16:00:50 -0700 Subject: [PATCH 225/262] change default to algorithm=None in sage.matroids.matroid.is_regular --- src/sage/matroids/graphic_matroid.pyx | 2 +- src/sage/matroids/linear_matroid.pyx | 2 +- src/sage/matroids/matroid.pyx | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/matroids/graphic_matroid.pyx b/src/sage/matroids/graphic_matroid.pyx index 5e740e78637..5d0e15958d5 100644 --- a/src/sage/matroids/graphic_matroid.pyx +++ b/src/sage/matroids/graphic_matroid.pyx @@ -1124,7 +1124,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_regular(self) noexcept: + cpdef bint is_regular(self, **kwds) except -1: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 6848604f0c8..e9e6af1208f 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -6299,7 +6299,7 @@ cdef class RegularMatroid(LinearMatroid): # representation - cpdef bint is_regular(self) noexcept: + cpdef bint is_regular(self, **kwds) except -1: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 03757e705ca..631042c7de0 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6612,7 +6612,7 @@ cdef class Matroid(SageObject): return False return True - cpdef bint is_regular(self, algorithm="cmr") except -1: + cpdef bint is_regular(self, algorithm=None) except -1: r""" Return if ``self`` is regular. @@ -6625,7 +6625,7 @@ cdef class Matroid(SageObject): INPUT: - - ``algorithm`` -- (default: ``"cmr"``); specify which algorithm + - ``algorithm`` -- (default: ``None``); specify which algorithm to check regularity: - ``None`` -- an algorithm based on excluded minors. @@ -6649,11 +6649,11 @@ cdef class Matroid(SageObject): sage: M.is_regular() True sage: M = matroids.catalog.R9() - sage: M.is_regular() # optional - cmr + sage: M.is_regular(algorithm="cmr") # optional - cmr False sage: from sage.matroids.advanced import LinearMatroid sage: M1 = LinearMatroid(Matrix(ZZ,[[1,0,1,1],[0,1,1,-1]])) - sage: M1.is_regular() # optional - cmr + sage: M1.is_regular(algorithm="cmr") # optional - cmr False REFERENCES: From bffcbe5eb4fb05d903e5ceb38a45677e5de966a7 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 1 Sep 2024 18:38:49 -0500 Subject: [PATCH 226/262] WIP add doctests in matrix_cmr_sparse --- src/sage/matrix/matrix_cmr_sparse.pyx | 117 ++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 1c0628a2503..e9d019a2cf9 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -91,6 +91,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): """ def __init__(self, parent, entries=None, copy=None, bint coerce=True, immutable=True): r""" + Create a sparse matrix with 8-bit integer entries implemented in CMR. + + INPUT: + + - ``parent`` -- a matrix space + + - ``entries`` -- see :func:`matrix` + + - ``copy`` -- ignored (for backwards compatibility) + + - ``coerce`` -- if False, assume without checking that the + entries lie in the base ring + + - ``immutable`` -- ignored (for backwards compatibility)? + TESTS:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -106,6 +121,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): self._init_from_dict(d, ma.nrows, ma.ncols, immutable=True) cdef _init_from_dict(self, dict d, int nrows, int ncols, bint immutable=True): + r""" + Create ``self._mat`` (a ``CMR_CHRMAT``) from a dictionary via CMR functions. + + INPUT: + + - ``dict`` -- a dictionary of all nonzero elements. + + - ``nrows`` -- the number of rows. + + - ``ncols`` -- the number of columns. + + - ``immutable`` -- (boolean) make the matrix immutable. By default, + the output matrix is mutable. + """ if cmr == NULL: CMRcreateEnvironment(&cmr) CMR_CALL(CMRchrmatCreate(cmr, &self._mat, nrows, ncols, len(d))) @@ -198,6 +227,30 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return Matrix_cmr_chr_sparse._from_cmr(cmr_submatrix) cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): + """ + Return ``(i, j)`` entry of this matrix as an integer. + + .. warning:: + + This is very unsafe; it assumes ``i`` and ``j`` are in the right + range. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]); M + [1 2 3] + [4 0 6] + sage: M[1, 2] + 6 + sage: M[1, 3] + Traceback (most recent call last): + ... + IndexError: matrix index out of range + sage: M[-1, 0] + 4 + """ cdef size_t index CMR_CALL(CMRchrmatFindEntry(self._mat, i, j, &index)) if index == SIZE_MAX: @@ -216,12 +269,44 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return d def __copy__(self): + """ + Matrix_cmr_chr_sparse matrices are immutable. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]) + sage: copy(M) is M + True + """ return self def __deepcopy__(self, memo): + """ + Matrix_cmr_chr_sparse matrices are immutable. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]) + sage: deepcopy(M) is M + True + """ return self def __dealloc__(self): + """ + Frees all the memory allocated for this matrix. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]) + sage: del M + """ if self._root is None or self._root is self: # We own it, so we have to free it. CMR_CALL(CMRchrmatFree(cmr, &self._mat)) @@ -230,6 +315,17 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return def _pickle(self): + """ + Utility function for pickling. + + TESTS:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), + ....: [[1, 2, 3], [4, 0, 6]]) + sage: loads(dumps(M)) == M + True + """ version = 0 return self._dict(), version @@ -243,6 +339,27 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): @staticmethod def _from_data(data, immutable=True): + """ + Create a matrix (:class:`Matrix_cmr_chr_sparse`) from data or a matrix. + + INPUT: + + - ``data`` -- a matrix or data to construct a matrix. + + - ``immutable`` -- (boolean) make the matrix immutable. By default, + the output matrix is mutable. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse._from_data([[1, 2, 3], [4, 0, 6]]); M + [1 2 3] + [4 0 6] + sage: N = matrix(ZZ, [[1, 2, 3], [4, 0, 6]]) + sage: Matrix_cmr_chr_sparse._from_data(N) + [1 2 3] + [4 0 6] + """ if not isinstance(data, Matrix): data = matrix(ZZ, data, sparse=True) if not isinstance(data, Matrix_cmr_chr_sparse): From 53014b9dd375b9f0bfd4660579983dda8d9da4dd Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 10:34:04 -0500 Subject: [PATCH 227/262] WIP add doctests for three_sum functions --- src/sage/matrix/matrix_cmr_sparse.pyx | 223 +++++++++++++++++++++++--- 1 file changed, 204 insertions(+), 19 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index e9d019a2cf9..aa8d7eaa906 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -611,13 +611,19 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def two_sum(first_mat, second_mat, first_index, second_index, nonzero_block="top_right"): r""" Return the 2-sum matrix constructed from the given matrices ``first_mat`` and - ``second_mat``, with column index of the first matrix ``column`` and row index - of the second matrix ``row``. - Suppose that ``column`` indicates the last column and ``row`` indicates the - first row, i.e, the first matrix is `M_1=\begin{bmatrix} A & a\end{bmatrix}` + ``second_mat``, with index of the first matrix ``first_index`` and index + of the second matrix ``second_index``. + Suppose that ``first_index`` indicates the last column of ``first_mat`` and + ``second_index`` indicates the first row of ``second_mat``, + i.e, the first matrix is `M_1=\begin{bmatrix} A & a\end{bmatrix}` and the second matrix is `M_2=\begin{bmatrix} b^T \\ B\end{bmatrix}`. Then the two sum `M_1 \oplus_2 M_2 =\begin{bmatrix}A & ab^T\\ 0 & B\end{bmatrix}`. + The terminology "2-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + .. SEEALSO:: :meth:`one_sum`, :meth:`three_sum` + INPUT: - ``first_mat`` -- the first integer matrix @@ -788,19 +794,96 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): first_index1, first_index2, second_index1, second_index2, three_sum_strategy="distributed_ranks"): r""" + Return the 3-sum matrix constructed from the two matrices + ``first_mat`` and ``second_index`` via + ``first_index1``, ``first_index2``, ``second_index1``, ``second_index2``. + + Suppose that ``three_sum_strategy="distributed_ranks"``. + If ``first_index1`` indexes a row vector `a_1^T` and + ``first_index2`` indexes a column vector `a_2` of ``first_mat``, + then ``second_index1`` indexes a column vector `b_1` and + ``second_index2`` indexes a row vector `b_2` of ``second_mat``. + In this case, + the first matrix is + `M_1=\begin{bmatrix} A & a_2 \\ a_1^T & *\end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} * & b_2^T\\ b_1 & B\end{bmatrix}`, + where the entry `*` is not relavant in the construction. + Then the Seymour/Schrijver 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & a_2 b_2^T \\ b_1 a_1^T & B\end{bmatrix}`. + + Suppose that ``three_sum_strategy="concentrated_rank"``. + If ``first_index1`` and ``first_index2`` both index row vectors + `a_1^T, a_2^T` of ``first_mat``, + then ``second_index1`` and ``second_index2`` must index column vectors + `b_1, b_2` of ``second_mat``. In this case, + the first matrix is + `M_1=\begin{bmatrix} A \\ a_1^T \\ a_2^T \end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} b_1 & b_2 & B\end{bmatrix}`. + Then the Truemper 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + + The terminology "3-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + .. SEEALSO:: :meth:`one_sum`, :meth:`two_sum`, + :meth:`three_sum_wide_wide`, :meth:`three_sum_mixed_mixed` + INPUT: + + - ``first_mat`` -- the first integer matrix + - ``second_mat`` -- the second integer matrix + - ``first_index1`` -- the column/row index of the first integer matrix + - ``first_index2`` -- the column/row index of the first integer matrix + - ``second_index1`` -- the row/column index of the second integer matrix + - ``second_index2`` -- the row/column index of the second integer matrix + - ``three_sum_strategy`` -- either ``"distributed_ranks"`` (default) + or ``"concentrated_rank"``. EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse - sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), - ....: [[1, 2, 3], [4, 5, 6]]); M1 - [1 2 3] - [4 5 6] - sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 3, sparse=True), - ....: [[7, 8, 9], [-1, -2, -3]]); M2 - [ 7 8 9] - [-1 -2 -3] + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 0, 0, 0], + ....: [1, 0, 1,-1, 1], + ....: [0,-1, 1, 0,-1], + ....: [0, 0,-1, 1, 0], + ....: [0, 1, 1, 0, 1]]); M1 + [ 1 1 0 0 0] + [ 1 0 1 -1 1] + [ 0 -1 1 0 -1] + [ 0 0 -1 1 0] + [ 0 1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1,-1, 1, 0, 0], + ....: [1, 1, 1, 1,-1], + ....: [0, 0,-1, 0, 1], + ....: [1, 0, 0,-1, 0], + ....: [0, 1, 0, 0, 1]]); M2 + [ 1 -1 1 0 0] + [ 1 1 1 1 -1] + [ 0 0 -1 0 1] + [ 1 0 0 -1 0] + [ 0 1 0 0 1] + sage: M1.three_sum_cmr(M2, 1, 2, 2, 4, three_sum_strategy="concentrated_rank") + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + sage: M1.three_sum_cmr(M2, 1, 2, 1, 1) + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] """ cdef Matrix_cmr_chr_sparse sum, first, second cdef CMR_CHRMAT *sum_mat = NULL @@ -833,9 +916,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): column1 = second_index1 column2 = second_index2 if row1 < 0 or row1 >= first._mat.numRows: - raise ValueError("First marker 1 should be a Row index of the first matrix") + raise ValueError("First marker 1 should be a row index of the first matrix") if row2 < 0 or row2 >= first._mat.numRows: - raise ValueError("First marker 2 should be a Row index of the first matrix") + raise ValueError("First marker 2 should be a row index of the first matrix") if column1 < 0 or column1 >= second._mat.numColumns: raise ValueError("Second marker 1 should be a column index of the second matrix") if column2 < 0 or column2 >= second._mat.numColumns: @@ -862,12 +945,51 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def three_sum_wide_wide(first_mat, second_mat): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and - ``second_mat``. + ``second_mat``, assume that ``three_sum_strategy="distributed_ranks"``. + The first matrix is + `M_1=\begin{bmatrix} A & a_2 & a_2\\ a_1^T & 0 & 1\end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} 1 & 0 & b_2^T\\ b_1 & b_1 & B\end{bmatrix}`. + Then the Seymour/Schrijver 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & a_2 b_2^T \\ b_1 a_1^T & B\end{bmatrix}`. - The first matrix is `M_1=\begin{bmatrix} A & a & a \\ c^T & 0 & \pm 1\end{bmatrix}` - and the second matrix is `M_2=\begin{bmatrix} \pm 1 & 0 & b^T \\ d & d & B\end{bmatrix}`. Then - the three sum is defined in [Sch1986]_, Ch. 19.4.:= - `M_1 \oplus_3 M_2 =\begin{bmatrix}A & ab^T\\ dc^T & B\end{bmatrix}`. + The terminology "3-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0,-1, 0,-1, 1, 1], + ....: [0, 0, 1, 0,-1,-1], + ....: [0, 1, 0, 1, 1, 1], + ....: [1, 0,-1, 1, 0, 1],]); M1 + [ 1 1 0 0 0 0] + [ 0 -1 0 -1 1 1] + [ 0 0 1 0 -1 -1] + [ 0 1 0 1 1 1] + [ 1 0 -1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[ 1, 0, 1, 1, 1,-1], + ....: [-1,-1, 1, 1, 0, 0], + ....: [ 0, 0, 0,-1, 0, 1], + ....: [ 0, 0, 1, 0,-1, 0], + ....: [ 1, 1, 0, 0, 0, 1]]); M2 + [ 1 0 1 1 1 -1] + [-1 -1 1 1 0 0] + [ 0 0 0 -1 0 1] + [ 0 0 1 0 -1 0] + [ 1 1 0 0 0 1] + sage: Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2) + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] """ m1 = first_mat.nrows() n1 = first_mat.ncols() @@ -900,6 +1022,69 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_list.append(r) return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + def three_sum_mixed_mixed(first_mat, second_mat): + r""" + Return the 3-sum matrix constructed from the given matrices ``first_mat`` and + ``second_mat``, assume that ``three_sum_strategy="concentrated_rank"``. + The first matrix is + `M_1=\begin{bmatrix} A & 0 \\ a_1^T & 1\\ a_2^T & 1\end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} 1 & 1 & 0\\ b_1 & b_2 & B\end{bmatrix}`. + Then the Truemper 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + + The terminology "3-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[ 1, 1, 0, 0, 0], + ....: [ 1, 0, 1,-1, 0], + ....: [ 1,-1, 1, 1, 1], + ....: [-1, 1, 0, 0, 0], + ....: [ 0, 0, 1, 0,-1], + ....: [ 0, 1, 0, 1, 0]]); M2 + [ 1 1 0 0 0] + [ 1 0 1 -1 0] + [ 1 -1 1 1 1] + [-1 1 0 0 0] + [ 0 0 1 0 -1] + [ 0 1 0 1 0] + sage: Matrix_cmr_chr_sparse.three_sum_mixed_mixed(M1, M2) + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + """ + m1 = first_mat.nrows() + n1 = first_mat.ncols() + m2 = second_mat.nrows() + n2 = second_mat.ncols() + first_submat = first_mat.matrix_from_rows_and_columns(range(m1), range(n1 - 1)) + second_submat = second_mat.matrix_from_rows_and_columns(range(1, m2), range(n2)) + + return Matrix_cmr_chr_sparse.three_sum_cmr(first_submat, second_submat, + m1 - 2, m1 -1, + 0, 1, + three_sum_strategy="concentrated_rank") + def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and From 1a6cded050c4579f784fcca4d945f53d02d7efe4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Oct 2024 16:06:10 -0700 Subject: [PATCH 228/262] add algorithm= to is_graphic in matroid --- src/doc/en/reference/references/index.rst | 5 + src/sage/matroids/graphic_matroid.pyx | 2 +- src/sage/matroids/linear_matroid.pxd | 6 +- src/sage/matroids/linear_matroid.pyx | 141 +++++++++++++++++++--- src/sage/matroids/matroid.pxd | 4 +- src/sage/matroids/matroid.pyx | 62 ++++++++-- 6 files changed, 185 insertions(+), 35 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 47038ce2a15..a0d4b980075 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1390,6 +1390,11 @@ REFERENCES: vol. 308, no. 1, July 1988. http://www.ams.org/journals/tran/1988-308-01/S0002-9947-1988-0946427-X/S0002-9947-1988-0946427-X.pdf +.. [BW1988b] Robert E. Bixby, Donald K. Wagner. + *An Almost Linear-Time Algorithm for Graph Realization*. + Mathematics of Operations Research, 1988. + :doi:`10.1287/moor.13.1.99` + .. [BW1993] Thomas Becker and Volker Weispfenning. *Groebner Bases - A Computational Approach To Commutative Algebra*. Springer, New York, 1993. diff --git a/src/sage/matroids/graphic_matroid.pyx b/src/sage/matroids/graphic_matroid.pyx index 5d0e15958d5..3361694df1e 100644 --- a/src/sage/matroids/graphic_matroid.pyx +++ b/src/sage/matroids/graphic_matroid.pyx @@ -1110,7 +1110,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_graphic(self) noexcept: + cpdef bint is_graphic(self, **kwds) except -1: r""" Return if ``self`` is graphic. diff --git a/src/sage/matroids/linear_matroid.pxd b/src/sage/matroids/linear_matroid.pxd index b0890a76148..c73db5e92ce 100644 --- a/src/sage/matroids/linear_matroid.pxd +++ b/src/sage/matroids/linear_matroid.pxd @@ -91,7 +91,9 @@ cdef class BinaryMatroid(LinearMatroid): cpdef _fast_isom_test(self, other) cpdef relabel(self, mapping) - cpdef bint is_graphic(self) noexcept + cpdef bint is_graphic(self, algorithm=*) except -1 + cpdef _is_graphic_GG(self) + cpdef _is_graphic_cmr(self) cpdef bint is_valid(self) noexcept @@ -173,5 +175,5 @@ cdef class RegularMatroid(LinearMatroid): cpdef _linear_extension_chains(self, F, fundamentals=*) cpdef bint is_regular(self) noexcept - cpdef bint is_graphic(self) noexcept + cpdef bint is_graphic(self, algorithm=*) except -1 cpdef bint is_valid(self) noexcept diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index e9e6af1208f..de70fc2b519 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -3793,8 +3793,61 @@ cdef class BinaryMatroid(LinearMatroid): keep_initial_representation=False) # graphicness test - cpdef bint is_graphic(self) noexcept: + cpdef is_graphic(self, algorithm=None): + r""" + Test if the binary matroid is graphic. + + A matroid is *graphic* if there exists a graph whose edge set equals + the groundset of the matroid, such that a subset of elements of the + matroid is independent if and only if the corresponding subgraph is + acyclic. + + INPUT: + + - ``algorithm`` -- (default: ``None``); specify which algorithm + to check graphicness: + + - ``None`` -- an algorithm based on [GG2012]_. + - ``"cmr"`` -- an algorithm based on [BW1988b]_. + the optional package "cmr" is required. + + OUTPUT: + + Boolean. + + .. SEEALSO:: + + :meth:`M.is_graphic() ` + :meth:`M.is_graphic() ` + + EXAMPLES:: + + sage: R10 = matroids.catalog.R10() + sage: M = Matroid(ring=GF(2), reduced_matrix=R10.representation( + ....: reduced=True, labels=False)) + sage: M.is_graphic(algorithm="cmr") # optional - cmr + False + sage: K5 = Matroid(graphs.CompleteGraph(5)) # needs sage.graphs + sage: K5.is_graphic(algorithm="cmr") # optional - cmr # needs sage.graphs + True + sage: K5 = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M = Matroid(ring=GF(2), reduced_matrix=K5.representation( # needs sage.graphs sage.rings.finite_rings + ....: reduced=True, labels=False)) + sage: M.is_graphic(algorithm="cmr") # optional - cmr # needs sage.graphs sage.rings.finite_rings + True + sage: M.dual().is_graphic(algorithm="cmr") # optional - cmr # needs sage.graphs + False """ + if algorithm is None: + return self._is_graphic_GG() + if algorithm == "cmr": + return self._is_graphic_cmr() + raise ValueError("Not a valid algorithm.") + + cpdef _is_graphic_GG(self): + r""" Test if the binary matroid is graphic. A matroid is *graphic* if there exists a graph whose edge set equals @@ -3809,14 +3862,14 @@ cdef class BinaryMatroid(LinearMatroid): sage: R10 = matroids.catalog.R10() sage: M = Matroid(ring=GF(2), reduced_matrix=R10.representation( ....: reduced=True, labels=False)) - sage: M.is_graphic() + sage: M._is_graphic_GG() False sage: K5 = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs sage: M = Matroid(ring=GF(2), reduced_matrix=K5.representation( # needs sage.graphs sage.rings.finite_rings ....: reduced=True, labels=False)) - sage: M.is_graphic() # needs sage.graphs sage.rings.finite_rings + sage: M._is_graphic_GG() # needs sage.graphs sage.rings.finite_rings True - sage: M.dual().is_graphic() # needs sage.graphs + sage: M.dual()._is_graphic_GG() # needs sage.graphs False ALGORITHM: @@ -3862,7 +3915,52 @@ cdef class BinaryMatroid(LinearMatroid): # now self is graphic iff there is a binary vector x so that M*x = 0 and x_0 = 1, so: return BinaryMatroid(m).corank(frozenset([0])) > 0 - cpdef bint is_valid(self) noexcept: + cpdef _is_graphic_cmr(self): + r""" + Test if the binary matroid is graphic. + + A matroid is *graphic* if there exists a graph whose edge set equals + the groundset of the matroid, such that a subset of elements of the + matroid is independent if and only if the corresponding subgraph is + acyclic. + + OUTPUT: + + Boolean. + + .. SEEALSO:: + + :meth:`M._is_binary_linear_matroid_graphic() ` + :meth:`M.is_network_matrix() ` + + EXAMPLES:: + + sage: R10 = matroids.catalog.R10() + sage: M = Matroid(ring=GF(2), reduced_matrix=R10.representation( + ....: reduced=True, labels=False)) + sage: M._is_graphic_cmr() # optional - cmr + False + sage: K5 = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M = Matroid(ring=GF(2), reduced_matrix=K5.representation( # needs sage.graphs sage.rings.finite_rings + ....: reduced=True, labels=False)) + sage: M._is_graphic_cmr() # optional - cmr # needs sage.graphs sage.rings.finite_rings + True + sage: M.dual()._is_graphic_cmr() # optional - cmr # needs sage.graphs + False + + ALGORITHM: + + The implemented recognition algorithm is based on [BW1988b]_, [An Almost Linear-Time Algorithm for Graph Realization](https://doi.org/10.1287/moor.13.1.99) by Robert E. Bixby and Donald K. Wagner (Mathematics of Operations Research, 1988). + For a matrix `M \in \{0,1\}^{m \times n}` with `k` nonzeros it runs in `\mathcal{O}( k \cdot \alpha(k, m) )` time, where `\alpha(\cdot)` denotes the inverse Ackerman function. + """ + from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + A = self.representation() + A_cmr = Matrix_cmr_chr_sparse(A.parent(), A) + return A_cmr._is_binary_linear_matroid_graphic() + + cpdef is_valid(self): r""" Test if the data obey the matroid axioms. @@ -6239,7 +6337,7 @@ cdef class RegularMatroid(LinearMatroid): fundamentals = set([1]) return LinearMatroid._linear_extension_chains(self, F, fundamentals) - cpdef bint is_graphic(self) noexcept: + cpdef bint is_graphic(self, algorithm=None) except -1: """ Test if the regular matroid is graphic. @@ -6248,27 +6346,36 @@ cdef class RegularMatroid(LinearMatroid): matroid is independent if and only if the corresponding subgraph is acyclic. + INPUT: + + - ``algorithm`` -- (default: ``None``); specify which algorithm + to check graphicness: + + - ``None`` -- an algorithm based on [GG2012]_. + - ``"cmr"`` -- an algorithm based on [BW1988b]_. + the optional package "cmr" is required. + OUTPUT: boolean + .. SEEALSO:: + + :meth:`M.is_graphic() ` + :meth:`M.is_graphic() ` + EXAMPLES:: sage: M = matroids.catalog.R10() - sage: M.is_graphic() + sage: M.is_graphic(algorithm="cmr") # optional - cmr False sage: M = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs - sage: M.is_graphic() # needs sage.graphs sage.rings.finite_rings + sage: M.is_graphic(algorithm="cmr") # optional - cmr # needs sage.graphs sage.rings.finite_rings True - sage: M.dual().is_graphic() # needs sage.graphs + sage: M.dual().is_graphic(algorithm="cmr") # optional - cmr # needs sage.graphs False - - ALGORITHM: - - In a recent paper, Geelen and Gerards [GG2012]_ reduced the problem to - testing if a system of linear equations has a solution. While not the - fastest method, and not necessarily constructive (in the presence of - 2-separations especially), it is easy to implement. """ - return BinaryMatroid(reduced_matrix=self._reduced_representation()).is_graphic() + return BinaryMatroid(reduced_matrix=self._reduced_representation()).is_graphic(algorithm=algorithm) cpdef bint is_valid(self) noexcept: r""" diff --git a/src/sage/matroids/matroid.pxd b/src/sage/matroids/matroid.pxd index 61432ef4cec..d97883ed631 100644 --- a/src/sage/matroids/matroid.pxd +++ b/src/sage/matroids/matroid.pxd @@ -195,8 +195,8 @@ cdef class Matroid(SageObject): cpdef _local_ternary_matroid(self, basis=*) cpdef ternary_matroid(self, randomized_tests=*, verify=*) cpdef is_ternary(self, randomized_tests=*) - cpdef bint is_regular(self, algorithm=*) noexcept - cpdef bint is_graphic(self) except -1 + cpdef bint is_regular(self, algorithm=*) except -1 + cpdef bint is_graphic(self, algorithm=*) except -1 # matroid k-closed cpdef is_k_closed(self, int k) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 631042c7de0..358a9b1fc7d 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -305,6 +305,7 @@ REFERENCES ========== - [BC1977]_ +- [BW1988b]_ - [Cun1986]_ - [CMO2011]_ - [CMO2012]_ @@ -6578,14 +6579,36 @@ cdef class Matroid(SageObject): """ return self.ternary_matroid(randomized_tests=randomized_tests, verify=True) is not None - cpdef bint is_graphic(self) noexcept: + cpdef bint is_graphic(self, algorithm=None) except -1: r""" Return if ``self`` is graphic. + A matroid is *graphic* if there exists a graph whose edge set equals + the groundset of the matroid, such that a subset of elements of the + matroid is independent if and only if the corresponding subgraph is + acyclic. A matroid is graphic if and only if it has no minor isomorphic to any of the matroids `U_{2, 4}`, `F_7`, `F_7^*`, `M^*(K_5)`, and `M^*(K_{3, 3})`. + INPUT: + + - ``algorithm`` -- (default: ``None``); specify which algorithm + to check graphicness: + + - ``None`` -- an algorithm based on excluded minors. + - ``"cmr"`` -- an algorithm based on [BW1988b]_, + the optional package "cmr" is required. + + .. SEEALSO:: + + :meth:`M._is_graphic_cmr() ` + :meth:`M.is_graphic() ` + :meth:`M.is_graphic() ` + EXAMPLES:: sage: M = matroids.catalog.Wheel4() @@ -6594,23 +6617,36 @@ cdef class Matroid(SageObject): sage: M = matroids.catalog.U24() sage: M.is_graphic() False + sage: M = matroids.catalog.Wheel4() + sage: M.is_graphic(algorithm="cmr") # optional - cmr + True + sage: M = matroids.catalog.U24() + sage: M.is_graphic(algorithm="cmr") # optional - cmr + False REFERENCES: [Oxl2011]_, p. 385. """ - from sage.matroids.database_matroids import ( - U24, - Fano, - FanoDual, - K5dual, - K33dual - ) - excluded_minors = [U24(), Fano(), FanoDual(), K5dual(), K33dual()] - for M in excluded_minors: - if self.has_minor(M): - return False - return True + M = self.binary_matroid() + if M is None: # equivalent to checking for a U24 minor + return False + if algorithm is None: + from sage.matroids.database_matroids import ( + U24, + Fano, + FanoDual, + K5dual, + K33dual + ) + excluded_minors = [U24(), Fano(), FanoDual(), K5dual(), K33dual()] + for M in excluded_minors: + if self.has_minor(M): + return False + return True + if algorithm == "cmr": + return M._is_graphic_cmr() + raise ValueError("Not a valid algorithm.") cpdef bint is_regular(self, algorithm=None) except -1: r""" From 84082362b776b7d2f6bbe3b4d4601080074260b1 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 11:15:17 -0500 Subject: [PATCH 229/262] WIP add doctests for pivot functions --- src/sage/matrix/matrix_cmr_sparse.pyx | 186 ++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index aa8d7eaa906..a1c68d4e4bd 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1227,6 +1227,55 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def binary_pivot(self, row, column): + r""" + Apply a pivot to ``self`` and returns the resulting matrix. + Calculations are done over the binary field. + + Suppose a matrix is `\begin{bmatrix} 1 & c^T \\ b & D\end{bmatrix}`. + Then the pivot of the matrix with respect to `1` is + `\begin{bmatrix} 1 & c^T \\ b & D - bc^T\end{bmatrix}`. + + The terminology "pivot" is defined in [Sch1986]_, Ch. 19.4. + + .. SEEALSO:: :meth:`binary_pivots`, :meth:`ternary_pivot`, :meth:`ternary_pivots` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ + ....: [1, 1, 0, 0, 0, 1, 0, 1, 0, 0], + ....: [1, 0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 0, 0, 0], + ....: [0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + ....: [1, 0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [1, 1, 0, 0, 0, 1, 0, 0, 0, 0] + ....: ]); M + [1 1 0 0 0 1 0 1 0 0] + [1 0 0 0 0 1 1 0 1 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 1 0 0 0 1] + [1 0 0 0 0 0 1 0 1 1] + [1 1 0 0 0 1 0 0 0 0] + sage: M.binary_pivot(0, 0) + [1 1 0 0 0 1 0 1 0 0] + [1 1 0 0 0 0 1 1 1 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 1 0 0 0 1] + [1 1 0 0 0 1 1 1 1 1] + [1 0 0 0 0 0 0 1 0 0] + """ cdef Matrix_cmr_chr_sparse result cdef size_t pivot_row = row cdef size_t pivot_column = column @@ -1237,6 +1286,49 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return result def binary_pivots(self, rows, columns): + r""" + Apply a sequence of pivots to ``self`` and returns the resulting matrix. + Calculations are done over the binary field. + + .. SEEALSO:: :meth:`binary_pivot`, :meth:`ternary_pivot`, :meth:`ternary_pivots` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ + ....: [1, 1, 0, 0, 0, 1, 0, 1, 0, 0], + ....: [1, 0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 0, 0, 0], + ....: [0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + ....: [1, 0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [1, 1, 0, 0, 0, 1, 0, 0, 0, 0] + ....: ]); M + [1 1 0 0 0 1 0 1 0 0] + [1 0 0 0 0 1 1 0 1 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 1 0 0 0 1] + [1 0 0 0 0 0 1 0 1 1] + [1 1 0 0 0 1 0 0 0 0] + sage: M.binary_pivots([5, 4, 3, 2], [2, 3, 4, 5]) + [1 0 1 1 1 1 0 1 0 0] + [1 1 1 1 1 1 1 0 1 0] + [0 1 1 1 1 1 0 0 0 0] + [0 1 1 1 1 0 0 0 0 0] + [0 1 1 1 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 1 0] + [0 1 1 1 1 1 0 0 0 1] + [1 0 0 0 0 0 1 0 1 1] + [1 0 1 1 1 1 0 0 0 0] + """ npivots = len(rows) if len(columns) != npivots: raise ValueError("The pivot rows and columns must have the same length") @@ -1257,6 +1349,94 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sig_free(pivot_columns) def ternary_pivot(self, row, column): + r""" + Apply a pivot to ``self`` and returns the resulting matrix. + Calculations are done over the ternary field. + + Suppose a matrix is `\begin{bmatrix} \epsilon & c^T \\ b & D\end{bmatrix}`, + where `\epsilon\in\{\pm 1\}`. + Then the pivot of the matrix with respect to `\epsilon` is + `\begin{bmatrix} -\epsilon & \epsilon c^T \\ \epsilon b & D-\epsilon bc^T\end{bmatrix}`. + + The terminology "pivot" is defined in [Sch1986]_, Ch. 19.4. + + .. SEEALSO:: :meth:`binary_pivot`, :meth:`binary_pivots`, :meth:`ternary_pivots` + + EXAMPLES:: + + Single pivot on a `1`-entry: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ + ....: [ 1, 1, 0, 0, 0, -1, 0, 1, 0, 0], + ....: [-1, 0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], + ....: [ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + ....: [ 1, 0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [ 1, 1, 0, 0, 0, 1, 0, 0, 0, 0] + ....: ]); M + [ 1 1 0 0 0 -1 0 1 0 0] + [-1 0 0 0 0 1 1 0 1 0] + [ 0 0 0 0 1 1 0 0 0 0] + [ 0 0 0 1 1 0 0 0 0 0] + [ 0 0 1 1 0 0 0 0 0 0] + [ 0 1 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0] + [ 0 0 0 0 0 1 0 0 0 1] + [ 1 0 0 0 0 0 1 0 1 1] + [ 1 1 0 0 0 1 0 0 0 0] + sage: M.ternary_pivot(0, 0) + [-1 1 0 0 0 -1 0 1 0 0] + [-1 1 0 0 0 0 1 1 1 0] + [ 0 0 0 0 1 1 0 0 0 0] + [ 0 0 0 1 1 0 0 0 0 0] + [ 0 0 1 1 0 0 0 0 0 0] + [ 0 1 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0] + [ 0 0 0 0 0 1 0 0 0 1] + [ 1 -1 0 0 0 1 1 -1 1 1] + [ 1 0 0 0 0 -1 0 -1 0 0] + + Single pivot on a `-1`-entry: + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ + ....: [-1, 1, 0, 0, 0, -1, 0, 1, 0, 0], + ....: [-1, 0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], + ....: [ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + ....: [ 1, 0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [ 1, 1, 0, 0, 0, 1, 0, 0, 0, 0] + ....: ]); M + [-1 1 0 0 0 -1 0 1 0 0] + [-1 0 0 0 0 1 1 0 1 0] + [ 0 0 0 0 1 1 0 0 0 0] + [ 0 0 0 1 1 0 0 0 0 0] + [ 0 0 1 1 0 0 0 0 0 0] + [ 0 1 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0] + [ 0 0 0 0 0 1 0 0 0 1] + [ 1 0 0 0 0 0 1 0 1 1] + [ 1 1 0 0 0 1 0 0 0 0] + sage: M.ternary_pivot(0, 0) + [ 1 -1 0 0 0 1 0 -1 0 0] + [ 1 -1 0 0 0 -1 1 -1 1 0] + [ 0 0 0 0 1 1 0 0 0 0] + [ 0 0 0 1 1 0 0 0 0 0] + [ 0 0 1 1 0 0 0 0 0 0] + [ 0 1 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0] + [ 0 0 0 0 0 1 0 0 0 1] + [-1 1 0 0 0 -1 1 1 1 1] + [-1 -1 0 0 0 0 0 1 0 0] + """ cdef size_t pivot_row = row cdef size_t pivot_column = column cdef CMR_CHRMAT *result_mat @@ -1265,6 +1445,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return Matrix_cmr_chr_sparse._from_cmr(result_mat) def ternary_pivots(self, rows, columns): + r""" + Apply a sequence of pivots to ``self`` and returns the resulting matrix. + Calculations are done over the ternary field. + + .. SEEALSO:: :meth:`binary_pivot`, :meth:`binary_pivots`, :meth:`ternary_pivot` + """ cdef size_t npivots = len(rows) if len(columns) != npivots: raise ValueError("The pivot rows and columns must have the same length") From 2501cab04ca2d2356a507c2d8baa4d5ba3ac8cb9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 12:41:52 -0500 Subject: [PATCH 230/262] add doctests for matrix_cmr_sparse --- src/sage/matrix/matrix_cmr_sparse.pyx | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index a1c68d4e4bd..399c28b0d70 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1784,6 +1784,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): This is an internal method because it should really be exposed as a method of :class:`Matroid`. + .. SEEALSO:: + + :meth:`M._is_graphic_cmr() ` + :meth:`M.is_graphic() ` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1954,6 +1961,29 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_network_matrix(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + + Let `D = (V,A)` be a digraph and let `T` be an (arbitrarily) directed + spanning forest of the underlying undirected graph. + The matrix `M(D,T) \in \{-1,0,1\}^{T \times (A \setminus T)}` defined via + ` + M(D,T)_{a,(v,w)} := \begin{cases} + +1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ forwardly}, \\ + -1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ backwardly}, \\ + 0 & \text{otherwise} + \end{cases} + ` + is called the network matrix of `D` with respect to `T`. + A matrix `M` is called network matrix if there exists a digraph `D` + with a directed spanning forest `T` such that `M = M(D,T)`. + Moreover, `M` is called conetwork matrix if `M^T` is a network matrix. + + ALGORITHM: + + The implemented recognition algorithm first tests the binary matroid of + the support matrix of `M` for being graphic and + uses camion for testing whether `M` is signed correctly. + EXAMPLES: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -2059,6 +2089,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_conetwork_matrix(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + + .. SEEALSO:: :meth:`is_network_matrix`, + EXAMPLES: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -2155,6 +2189,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): This is an internal method because it should really be exposed as a method of :class:`Matroid`. + .. SEEALSO:: + + :meth:`M.is_regular() ` + INPUT: - ``certificate``: ``False`` or ``True`` @@ -2517,6 +2556,93 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): cdef _set_cmr_seymour_parameters(CMR_SEYMOUR_PARAMS *params, dict kwds): + """ + Set the parameters for Seymour's decomposition from the dictionary ``kwds``. + + INPUT: + + - ``params`` -- the parameters object to be set + + Keyword arguments: + + - ``stop_when_irregular`` -- boolean + Whether to stop decomposing once irregularity is determined. + + - ``stop_when_nongraphic`` -- boolean + Whether to stop decomposing once non-graphicness (or being non-network) is determined. + + - ``stop_when_noncographic`` -- boolean + Whether to stop decomposing once non-cographicness (or being non-conetwork) is determined. + + - ``stop_when_nongraphic_and_noncographic`` -- boolean + Whether to stop decomposing once non-graphicness and non-cographicness + (or not being network and not being conetwork) is determined. + + - ``series_parallel_ok`` -- boolean (default: ``True``); + Whether to allow series-parallel operations in the decomposition tree. + + - ``check_graphic_minors_planar`` -- boolean (default: ``False``); + Whether minors identified as graphic should still be checked for cographicness. + + - ``use_direct_graphicness_test`` -- boolean (default: ``True``); + Whether to use fast graphicness routines. + + - ``prefer_graphicness`` -- boolean + Whether to first test for (co)graphicness (or being (co)network) + before applying series-parallel reductions + + - ``three_sum_pivot_children`` -- boolean + Whether pivots for 3-sums shall be applied such that the matrix contains + both child matrices as submatrices, if possible. + + - ``three_sum_strategy`` -- ``"Mixed_Mixed"`` or ``"Wide_Wide"`` or integer; + Whether to perform pivots to change the rank distribution, and how to construct the children. + + The value is a bit-wise or of three decisions. + + The first decision is that of the rank distribution: + - CMR_SEYMOUR_THREESUM_FLAG_NO_PIVOTS to not change the rank distribution (default), or + - CMR_SEYMOUR_THREESUM_FLAG_DISTRIBUTED_RANKS to enforce distributed ranks (1 + 1), or + - CMR_SEYMOUR_THREESUM_FLAG_CONCENTRATED_RANK to enforce concentrated ranks (2 + 0). + + The second decision determines the layout of the first child matrix: + - CMR_SEYMOUR_THREESUM_FLAG_FIRST_WIDE for a wide first child (default) + in case of distributed ranks, or + - CMR_SEYMOUR_THREESUM_FLAG_FIRST_TALL for a tall first child in that case. + - CMR_SEYMOUR_THREESUM_FLAG_FIRST_MIXED for a mixed first child (default) + in case of concentrated ranks, or + - CMR_SEYMOUR_THREESUM_FLAG_FIRST_ALLREPR for a first child + with all representing rows in that case. + + Similarly, the third decision determines the layout of the second child matrix: + - CMR_SEYMOUR_THREESUM_FLAG_SECOND_WIDE for a wide second child (default) + in case of distributed ranks, or + - CMR_SEYMOUR_THREESUM_FLAG_SECOND_TALL for a tall second child in that case. + - CMR_SEYMOUR_THREESUM_FLAG_SECOND_MIXED for a mixed second child (default) + in case of concentrated ranks, or + - CMR_SEYMOUR_THREESUM_FLAG_SECOND_ALLREPR for a first second + with all representing rows in that case. + + .. SEEALSO:: :meth:`three_sum_wide_wide`, :meth:`three_sum_mixed_mixed` + + .. NOTE:: + + A decomposition as described by Seymour can be selected via CMR_SEYMOUR_THREESUM_FLAG_SEYMOUR. + A decomposition as used by Truemper can be selected via CMR_SEYMOUR_THREESUM_FLAG_TRUEMPER. + + The default (``None``) is to not carry out any pivots and + choose Seymour's or Truemper's definition depending on the rank distribution. + + ``"Mixed_Mixed"`` is to allow pivots and choose CMR_SEYMOUR_THREESUM_FLAG_TRUEMPER + + ``"Wide_Wide"`` is to allow pivots and choose CMR_SEYMOUR_THREESUM_FLAG_SEYMOUR + + - ``construct_leaf_graphs`` -- boolean + Whether to construct (co)graphs for all leaf nodes that are (co)graphic or (co)network. + + - ``construct_all_graphs`` -- boolean + Whether to construct (co)graphs for all nodes that are (co)graphic or (co)network. + """ CMR_CALL(CMRseymourParamsInit(params)) params.stopWhenIrregular = kwds['stop_when_irregular'] params.stopWhenNongraphic = kwds['stop_when_nongraphic'] From 5354aa3bd96796723a7f70a6906b82be47de11fe Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 12:50:58 -0500 Subject: [PATCH 231/262] build/pkgs/cmr: Update to 66b5141ea955c5c43b8d82cf105554b627cd5424 --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index d2b69b73f1b..c99d57c96ee 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=b1ec972c1dbecf25841293ce8b0abdc0f174eba8 -sha256=735cb369799da59383a4c53fdd4c6972dfee86d7cd7726cb653c550513ba4ead +sha1=94cbb90279f2387a0ae870fa9d51110f6eb289f7 +sha256=cb7db56a86002beacef74de7cfa00617428a0b3ba6247663d7db6305eca45ab0 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 785d4a50283..cda6414a01f 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -c6ff00c615e6ee0e644912c84fe3c5bc2b5d29e6 +66b5141ea955c5c43b8d82cf105554b627cd5424 From b741d6c532cf67e8a64c3bafa4af225c9237c767 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 13:36:07 -0500 Subject: [PATCH 232/262] update cmr.pxd to 66b5141 --- src/sage/libs/cmr/cmr.pxd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/cmr/cmr.pxd b/src/sage/libs/cmr/cmr.pxd index d22398bd60e..7cbebd9fa9e 100644 --- a/src/sage/libs/cmr/cmr.pxd +++ b/src/sage/libs/cmr/cmr.pxd @@ -234,7 +234,7 @@ cdef extern from "cmr/separation.h": CMR_ERROR CMRsepaComputeSizes(CMR_SEPA* sepa, size_t* pnumRowsTopLeft, size_t* pnumColumnsTopLeft, size_t* pnumRowsBottomRight, size_t* pnumColumnsBottomRight) CMR_ERROR CMRsepaFindBinaryRepresentatives(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_CHRMAT* transpose, bool* pswapped, CMR_SUBMAT** pviolator) CMR_ERROR CMRsepaFindBinaryRepresentativesSubmatrix(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_CHRMAT* transpose, CMR_SUBMAT* submatrix, bool* pswapped, CMR_SUBMAT** pviolator) - CMR_ERROR CMRsepaGetRepresentatives(CMR* cmr, CMR_SEPA* sepa, size_t reprRows[2][3], size_t reprColumns[2][3]) + CMR_ERROR CMRsepaGetRepresentatives(CMR_SEPA* sepa, size_t reprRows[2][3], size_t reprColumns[2][3]) CMR_ERROR CMRsepaGetProjection(CMR_SEPA* sepa, size_t part, size_t* rowsToPart, size_t* columnsToPart, size_t* pnumPartRows, size_t* pnumPartColumns) CMR_ERROR CMRsepaCheckTernary(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, bool* pisTernary, CMR_SUBMAT** pviolator) CMR_ERROR CMRsepaCheckTernarySubmatrix(CMR* cmr, CMR_SEPA* sepa, CMR_CHRMAT* matrix, CMR_SUBMAT* submatrix, bool* pisTernary, CMR_SUBMAT** pviolator) @@ -449,6 +449,7 @@ cdef extern from "cmr/tu.h": CMR_SEYMOUR_PARAMS seymour bool ternary bool camionFirst + bool naiveSubmatrix CMR_ERROR CMRtuParamsInit(CMR_TU_PARAMS* params) From 37a535d73197c0a4b830a9a6f53459cd4384aa38 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 2 Sep 2024 13:52:09 -0500 Subject: [PATCH 233/262] add docstring for parameters in is_totally_unimodular --- src/sage/matrix/matrix_cmr_sparse.pyx | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 399c28b0d70..076a786234e 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -2197,6 +2197,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - ``certificate``: ``False`` or ``True`` + If ``True``, then return a :class:`DecompositionNode` + if the linear matroid of ``self`` over `\GF{2}` is regular; + If not, NotImplemented. + + - ``stop_when_irregular`` -- boolean (default: ``True``) + Whether to stop decomposing once irregularity is determined. + + For a description of other parameters, see :meth:`_set_cmr_seymour_parameters` + + - ``row_keys`` -- a finite or enumerated family of arbitrary objects + that index the rows of the matrix + + - ``column_keys`` -- a finite or enumerated family of arbitrary objects + that index the columns of the matrix EXAMPLES:: @@ -2376,6 +2390,20 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - ``certificate``: ``False`` or ``True`` + If ``True``, then return + a :class:`DecompositionNode` if ``self`` is totally unimodular; + a submatrix with determinant not in `\{0, \pm1\}` if not. + + - ``stop_when_nonTU`` -- boolean (default: ``True``) + Whether to stop decomposing once not TU is determined. + + For a description of other parameters, see :meth:`_set_cmr_seymour_parameters` + + - ``row_keys`` -- a finite or enumerated family of arbitrary objects + that index the rows of the matrix + + - ``column_keys`` -- a finite or enumerated family of arbitrary objects + that index the columns of the matrix EXAMPLES:: From 2ad2760745427c282076d3c81e47aefa5acecb69 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 8 Sep 2024 16:13:06 -0500 Subject: [PATCH 234/262] add is_three_sum with sign verification --- src/sage/matrix/matrix_cmr_sparse.pyx | 518 +++++++++++++++++++++++++- 1 file changed, 517 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 076a786234e..627de46bb27 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1081,10 +1081,526 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): second_submat = second_mat.matrix_from_rows_and_columns(range(1, m2), range(n2)) return Matrix_cmr_chr_sparse.three_sum_cmr(first_submat, second_submat, - m1 - 2, m1 -1, + m1 - 2, m1 - 1, 0, 1, three_sum_strategy="concentrated_rank") + def is_three_sum_wide_wide(first_mat, second_mat, three_sum_mat, + first_row_index=-1, + first_columns_index=[-2, -1], + second_row_index=0, + second_columns_index=[0, 1], + sign_verify=True): + r""" + Check whether ``first_mat`` and ``second_mat`` form ``three_sum_mat`` + via the 3-sum operation. + Assume that ``three_sum_strategy="distributed_ranks"`` or ``"Wide_Wide"``. + If ``sign_verify=True``, also check whether the 3-sum satisfies that + ``three_sum_mat`` is totally unimodular, if and only if, + ``first_mat`` and ``second_mat`` are both totally unimodular. + + The first matrix is + `M_1=\begin{bmatrix} A & a_2 & a_2\\ a_1^T & 0 & \epsilon_2\end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} \epsilon_1 & 0 & b_2^T\\ b_1 & b_1 & B\end{bmatrix}`, + where `\epsilon_1`, `\epsilon_2` are `1` or `-1`. + Then the Seymour/Schrijver 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & a_2 b_2^T \\ b_1 a_1^T & B\end{bmatrix}`. + + The terminology "3-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + The signs of `\epsilon_1` (`\epsilon_2`) are determined by + a shortest path between two sets of vertices in the bipartite graph, + where the sets of vertices corresponding to the nonzero + row and column indices of `a_1^T, a_2` (`b_2^T, b_1`), + and the bipartite graph consists of vertices corresponding to the rows + and columns of `M`, and edges corresponding to the nonzero entry. + between the rows and columns of `M`, see [Sch1986]_, Ch. 20.3. + + .. SEEALSO:: :meth:`three_sum_wide_wide`, :meth:`is_three_sum_mixed_mixed` + :meth:`is_totally_unimodular` + + INPUT: + + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``first_row_index`` -- the row index of `a_1^T` in `M_1` + - ``first_columns_index`` -- the column indices of `a_2` in `M_1` + - ``second_row_index`` -- the row index of `b_2^T` in `M_2` + - ``second_columns_index`` -- the column indices of `b_1` in `M_2` + - ``sign_verify`` -- boolean (default:``True``) + Whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. + + OUTPUT: boolean, or (boolean, string) + + If it is False only because of the sign, then also output the correct sign. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0,-1, 0,-1, 1, 1], + ....: [0, 0, 1, 0,-1,-1], + ....: [0, 1, 0, 1, 1, 1], + ....: [1, 0,-1, 1, 0, 1],]); M1 + [ 1 1 0 0 0 0] + [ 0 -1 0 -1 1 1] + [ 0 0 1 0 -1 -1] + [ 0 1 0 1 1 1] + [ 1 0 -1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[ 1, 0, 1, 1, 1,-1], + ....: [-1,-1, 1, 1, 0, 0], + ....: [ 0, 0, 0,-1, 0, 1], + ....: [ 0, 0, 1, 0,-1, 0], + ....: [ 1, 1, 0, 0, 0, 1]]); M2 + [ 1 0 1 1 1 -1] + [-1 -1 1 1 0 0] + [ 0 0 0 -1 0 1] + [ 0 0 1 0 -1 0] + [ 1 1 0 0 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2); M + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] + sage: Matrix_cmr_chr_sparse.is_three_sum_wide_wide(M1, M2, M) + (False, + 'sign_1 in second_mat should be -1. sign_2 in first_mat should be -1. ') + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[ 0, 0, 1,-1,-1], + ....: [ 1, 1, 1, 0, 0], + ....: [ 0, 1, 0, 1, 1], + ....: [-1, 0,-1, 0, 1]]); M1 + [ 0 0 1 -1 -1] + [ 1 1 1 0 0] + [ 0 1 0 1 1] + [-1 0 -1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[ 1, 0, 1,-1, 0], + ....: [ 0, 0, 1, 0, 1], + ....: [-1,-1, 0, 1, 1], + ....: [-1,-1, 0, 0, 1]]); M2 + [ 1 0 1 -1 0] + [ 0 0 1 0 1] + [-1 -1 0 1 1] + [-1 -1 0 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2); M + [ 0 0 1 -1 1 0] + [ 1 1 1 0 0 0] + [ 0 1 0 1 -1 0] + [ 0 0 0 1 0 1] + [ 1 0 1 0 1 1] + [ 1 0 1 0 0 1] + sage: Matrix_cmr_chr_sparse.is_three_sum_wide_wide(M1, M2, M) + True + """ + if not isinstance(first_columns_index, (list, tuple)) or len(first_columns_index) != 2: + raise ValueError('The index of two columns needs to be given!') + if not isinstance(second_columns_index, (list, tuple)) or len(second_columns_index) != 2: + raise ValueError('The index of two columns needs to be given!') + + m1 = first_mat.nrows() + n1 = first_mat.ncols() + m2 = second_mat.nrows() + n2 = second_mat.ncols() + m = three_sum_mat.nrows() + n = three_sum_mat.ncols() + if m != (m1 + m2 - 2): # The number of rows should match + return False + if n != (n1 + n2 - 4): # The number of columns should match + return False + + # Check the extra two columns for a2 and b1 + j1 = first_columns_index[0] + j2 = first_columns_index[1] + j1 = j1 if j1 >= 0 else n1 + j1 + j2 = j2 if j2 >= 0 else n1 + j2 + i1 = first_row_index + i1 = i1 if i1 >= 0 else m1 + i1 + row_index_1 = [i for i in range(m1) if i != i1] + for i in row_index_1: + if first_mat[i, j1] != first_mat[i, j2]: + return False + sign_2 = first_mat[i1, j2] if first_mat[i1, j1] == 0 else first_mat[i1, j1] + if sign_2 == 0: + return False + + k1 = second_columns_index[0] + k2 = second_columns_index[1] + k1 = k1 if k1 >= 0 else n2 + k1 + k2 = k2 if k2 >= 0 else n2 + k2 + i2 = second_row_index + i2 = i2 if i2 >= 0 else m2 + i2 + row_index_2 = [i for i in range(m2) if i != i2] + for i in row_index_2: + if second_mat[i, k1] != second_mat[i, k2]: + return False + sign_1 = second_mat[i2, k2] if second_mat[i2, k1] == 0 else second_mat[i2, k1] + if sign_1 == 0: + return False + + # Check whether the result comes from the three sum + column_index_1 = [j for j in range(n1) if j != j1 and j != j2] + for i in range(m1 - 1): + for j in range(n1 - 2): + if first_mat[row_index_1[i], column_index_1[j]] != three_sum_mat[i, j]: + return False + column_index_2 = [j for j in range(n2) if j != k1 and j != k2] + for i in range(m2 - 1): + for j in range(n2 - 2): + if second_mat[row_index_2[i], column_index_2[j]] != three_sum_mat[m1 - 1 + i, n1 - 2 + j]: + return False + for i in range(m1 - 1): + for j in range(n2 - 2): + rank1_entry = first_mat[row_index_1[i], j1] * second_mat[i2, column_index_2[j]] + if rank1_entry != three_sum_mat[i, n1 - 2 + j]: + return False + for i in range(m2 - 1): + for j in range(n1 - 2): + rank1_entry = first_mat[i1, column_index_1[j]] * second_mat[row_index_2[i], k1] + if rank1_entry != three_sum_mat[m1 - 1 + i, j]: + return False + + if sign_verify is not True: + return True + # Check the sign + + from sage.graphs.graph import Graph + G = Graph() + + rows = ['r' + str(i) for i in range(m)] + cols = ['c' + str(j) for j in range(n)] + G.add_vertices(rows + cols) + + for i in range(m): + for j in range(n): + if three_sum_mat[i, j] != 0: + G.add_edge('r' + str(i), 'c' + str(j)) + dist_dict = G.distance_all_pairs() + + R1 = ['r'+str(i) for i in range(m1 - 1) if first_mat[row_index_1[i], j1] != 0] + K1 = ['c'+str(j) for j in range(n1 - 2) if first_mat[i1, column_index_1[j]] != 0] + + min_distance = float('inf') + min_pair = None + for v1 in R1: + for v2 in K1: + if v2 in dist_dict[v1]: + if dist_dict[v1][v2] < min_distance: + min_distance = dist_dict[v1][v2] + min_pair = (v1, v2) + path_1 = G.shortest_path(min_pair[0], min_pair[1]) + path_1_num = [int(v[1:]) for v in path_1] + path_1_len = 0 + for i in range(len(path_1) - 1): + if path_1[i][0] == 'r': + r = path_1_num[i] + c = path_1_num[i + 1] + if path_1[i][0] == 'c': + c = path_1_num[i] + r = path_1_num[i + 1] + path_1_len += three_sum_mat[r, c] * first_mat[row_index_1[r], j1] * first_mat[i1, column_index_1[c]] + + R2 = ['r'+str(m1 - 1 + i) for i in range(m2 - 1) if second_mat[row_index_2[i], k1] != 0] + K2 = ['c'+str(n1 - 2 + j) for j in range(n2 - 2) if second_mat[i2, column_index_2[j]] != 0] + + min_distance = float('inf') + min_pair = None + for v1 in R2: + for v2 in K2: + if v2 in dist_dict[v1]: + if dist_dict[v1][v2] < min_distance: + min_distance = dist_dict[v1][v2] + min_pair = (v1, v2) + path_2 = G.shortest_path(min_pair[0], min_pair[1]) + path_2_num = [int(v[1:]) for v in path_2] + path_2_len = 0 + for i in range(len(path_2) - 1): + if path_2[i][0] == 'r': + r = path_2_num[i] + c = path_2_num[i + 1] + if path_2[i][0] == 'c': + c = path_2_num[i] + r = path_2_num[i + 1] + path_2_len += three_sum_mat[r, c] * second_mat[row_index_2[r - m1 + 1], k1] * second_mat[i2, column_index_2[c - n1 + 2]] + + msg = "" + if (sign_1 - path_1_len) % 4 != 0: + msg += f'sign_1 in second_mat should be {-sign_1}. ' + if (sign_2 - path_2_len) % 4 != 0: + msg += f'sign_2 in first_mat should be {-sign_2}. ' + if msg: + return False, msg + return True + + def is_three_sum_mixed_mixed(first_mat, second_mat, three_sum_mat, + first_rows_index=[-2, -1], + first_column_index=-1, + second_row_index=0, + second_columns_index=[0, 1], + sign_verify=True): + r""" + Check whether ``first_mat`` and ``second_mat`` form ``three_sum_mat`` + via the 3-sum operation. + Assume that ``three_sum_strategy="concentrated_ranks"`` or ``"Mixed_Mixed"``. + If ``sign_verify=True``, also check whether the 3-sum satisfies that + ``three_sum_mat`` is totally unimodular, if and only if, + ``first_mat`` and ``second_mat`` are both totally unimodular. + + The first matrix is + `M_1=\begin{bmatrix} A & 0 \\ a_1^T & 1\\ a_2^T & \epsilon_2\end{bmatrix}` + and the second matrix is + `M_2=\begin{bmatrix} \epsilon_1 & 1 & 0\\ b_1 & b_2 & B\end{bmatrix}`, + where `\epsilon_1`, `\epsilon_2` are `1` or `-1`. + Then the Truemper 3-sum is the matrix + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + + The terminology "3-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + + .. SEEALSO:: :meth:`is_three_sum_wide_wide`, :meth:`three_sum_mixed_mixed` + :meth:`is_totally_unimodular` + + INPUT: + + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``first_rows_index`` -- the indices of rows `a_1^T` and `a_2^T` in `M_1` + - ``first_column_index`` -- the index of the column with `\epsilon_2` in `M_1` + - ``second_row_index`` -- the index of the row with `\epsilon_1` in `M_2` + - ``second_columns_index`` -- the indices of columns `b_1` and `b_2` in `M_2` + - ``sign_verify`` -- boolean (default:``True``) + Whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. + + OUTPUT: boolean, or (boolean, string) + + If it is False only because of the sign, then also output the correct sign. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[ 1, 1, 0, 0, 0], + ....: [ 1, 0, 1,-1, 0], + ....: [ 1,-1, 1, 1, 1], + ....: [-1, 1, 0, 0, 0], + ....: [ 0, 0, 1, 0,-1], + ....: [ 0, 1, 0, 1, 0]]); M2 + [ 1 1 0 0 0] + [ 1 0 1 -1 0] + [ 1 -1 1 1 1] + [-1 1 0 0 0] + [ 0 0 1 0 -1] + [ 0 1 0 1 0] + sage: M = Matrix_cmr_chr_sparse.three_sum_mixed_mixed(M1, M2); M + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M, sign_verify=False) + True + sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M) + True + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[ 1, 0, 1, 1, 0], + ....: [ 0, 1, 1, 1, 0], + ....: [ 1, 0, 1, 0, 1], + ....: [ 0,-1, 0,-1, 1]]); M1 + [ 1 0 1 1 0] + [ 0 1 1 1 0] + [ 1 0 1 0 1] + [ 0 -1 0 -1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 4, sparse=True), + ....: [[ 1, 1, 0, 0], + ....: [ 1, 0, 1, 1], + ....: [ 0,-1, 1, 1], + ....: [ 1, 0, 1, 0], + ....: [ 0,-1, 0, 1]]); M2 + [ 1 1 0 0] + [ 1 0 1 1] + [ 0 -1 1 1] + [ 1 0 1 0] + [ 0 -1 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum_mixed_mixed(M1, M2); M + [1 0 1 1 0 0] + [0 1 1 1 0 0] + [1 0 1 0 1 1] + [0 1 0 1 1 1] + [1 0 1 0 1 0] + [0 1 0 1 0 1] + sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M) + True + """ + if not isinstance(first_rows_index, (list, tuple)) or len(first_rows_index) != 2: + raise ValueError('The index of two columns needs to be given!') + if not isinstance(second_columns_index, (list, tuple)) or len(second_columns_index) != 2: + raise ValueError('The index of two columns needs to be given!') + + m1 = first_mat.nrows() + n1 = first_mat.ncols() + m2 = second_mat.nrows() + n2 = second_mat.ncols() + m = three_sum_mat.nrows() + n = three_sum_mat.ncols() + if m != (m1 + m2 - 3): # The number of rows should match + return False + if n != (n1 + n2 - 3): # The number of columns should match + return False + + # Check whether the extra column of M1 is zero except the two extra rows + j1 = first_rows_index[0] + j2 = first_rows_index[1] + j1 = j1 if j1 >= 0 else m1 + j1 + j2 = j2 if j2 >= 0 else m1 + j2 + i1 = first_column_index + i1 = i1 if i1 >= 0 else n1 + i1 + row_index_1 = [i for i in range(m1) if i != j1 and i != j2] + for i in row_index_1: + if first_mat[i, i1] != 0: + return False + if first_mat[j1, i1] == 0 or first_mat[j2, i1] == 0: + return False + # Check whether the extra row of M2 is zero except the two extra columns + k1 = second_columns_index[0] + k2 = second_columns_index[1] + k1 = k1 if k1 >= 0 else n2 + k1 + k2 = k2 if k2 >= 0 else n2 + k2 + i2 = second_row_index + i2 = i2 if i2 >= 0 else m2 + i2 + column_index_2 = [j for j in range(n2) if j != k1 and j != k2] + for j in column_index_2: + if second_mat[i2, j] != 0: + return False + if second_mat[i2, k1] == 0 or second_mat[i2, k2] == 0: + return False + + # Check whether the result comes from the three sum + column_index_1 = [j for j in range(n1) if j != i1] + for i in range(m1 - 2): + for j in range(n1 - 1): + if first_mat[row_index_1[i], column_index_1[j]] != three_sum_mat[i, j]: + return False + row_index_2 = [i for i in range(m2) if i != i2] + for i in range(m2 - 1): + for j in range(n2 - 2): + if second_mat[row_index_2[i], column_index_2[j]] != three_sum_mat[m1 - 2 + i, n1 - 1 + j]: + return False + for i in range(m1 - 2): + for j in range(n2 - 2): + if three_sum_mat[i, n1 - 1 + j] != 0: + return False + for i in range(m2 - 1): + for j in range(n1 - 1): + rank2_entry = first_mat[j1, column_index_1[j]] * second_mat[row_index_2[i], k1] + first_mat[j2, column_index_1[j]] * second_mat[row_index_2[i], k2] + if rank2_entry != three_sum_mat[m1 - 2 + i, j]: + return False + + if sign_verify is not True: + return True + # Check the sign + sign_2 = first_mat[j1, i1] * first_mat[j2, i1] + sign_1 = second_mat[i2, k1] * second_mat[i2, k2] + + from sage.graphs.graph import Graph + G = Graph() + + rows = ['r' + str(i) for i in range(m)] + cols = ['c' + str(j) for j in range(n)] + G.add_vertices(rows + cols) + + for i in range(m): + for j in range(n): + if three_sum_mat[i, j] != 0: + G.add_edge('r' + str(i), 'c' + str(j)) + dist_dict = G.distance_all_pairs() + + K1 = [] + K2 = [] + b1 = second_mat.matrix_from_rows_and_columns(row_index_2, [k1]) + b2 = second_mat.matrix_from_rows_and_columns(row_index_2, [k2]) + for j in range(n1 - 1): + bb = three_sum_mat.matrix_from_rows_and_columns(range(m1 - 2, m), [j]) + if bb == b1 or bb == -b1: + K1.append('c'+str(j)) + elif bb == b2 or bb == -b2: + K2.append('c'+str(j)) + + min_distance = float('inf') + min_pair = None + for v1 in K1: + for v2 in K2: + if v2 in dist_dict[v1]: + if dist_dict[v1][v2] < min_distance: + min_distance = dist_dict[v1][v2] + min_pair = (v1, v2) + path_1 = G.shortest_path(min_pair[0], min_pair[1]) + path_1_num = [int(v[1:]) for v in path_1] + q = (len(path_1) + 1)/2 + path_1_len = (-1)**q + for i in range(q - 1): + path_1_len *= three_sum_mat[path_1_num[2*i + 1], path_1_num[2*i]] + path_1_len *= three_sum_mat[path_1_num[2*i + 1], path_1_num[2*i + 2]] + + R1 = [] + R2 = [] + a1 = first_mat.matrix_from_rows_and_columns([j1], column_index_1) + a2 = first_mat.matrix_from_rows_and_columns([j2], column_index_1) + for i in range(m2 - 1): + aa = three_sum_mat.matrix_from_rows_and_columns([m1 - 2 + i], range(n1 - 1)) + if aa == a1 or aa == -a1: + R1.append('r'+str(i)) + elif aa == a2 or aa == -a2: + R2.append('r'+str(i)) + + min_distance = float('inf') + min_pair = None + for v1 in R1: + for v2 in R2: + if v2 in dist_dict[v1]: + if dist_dict[v1][v2] < min_distance: + min_distance = dist_dict[v1][v2] + min_pair = (v1, v2) + path_2 = G.shortest_path(min_pair[0], min_pair[1]) + path_2_num = [int(v[1:]) for v in path_2] + p = (len(path_2) + 1)/2 + path_2_len = (-1)**p + for i in range(p - 1): + path_2_len *= three_sum_mat[path_2_num[2*i], path_2_num[2*i + 1]] + path_2_len *= three_sum_mat[path_2_num[2*i + 2], path_2_num[2*i + 1]] + + msg = "" + if (sign_1 - path_1_len) % 4 != 0: + msg += f'sign_1 in second_mat should be {-sign_1}. ' + if (sign_2 - path_2_len) % 4 != 0: + msg += f'sign_2 in first_mat should be {-sign_2}. ' + if msg: + return False, msg + return True + def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and From f05511b4df29847208947c5362b634343cc4aac6 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 8 Sep 2024 19:32:54 -0500 Subject: [PATCH 235/262] rewrite three_sum with added keywords: algorithm, verify, sign_verify --- src/sage/matrix/matrix_cmr_sparse.pyx | 746 ++++++++++++++++++++++++-- 1 file changed, 693 insertions(+), 53 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 627de46bb27..cbd4d7cdf85 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -538,6 +538,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``summands`` -- integer matrices or data from which integer matrices can be constructed + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + The terminology "1-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_. @@ -643,6 +645,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): The outer product of the corresponding row and column form the nonzero bottom left block of the 2-sum matrix. + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -790,7 +794,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum.set_immutable() return sum - def three_sum_cmr(first_mat, second_mat, + def _three_sum_cmr(first_mat, second_mat, first_index1, first_index2, second_index1, second_index2, three_sum_strategy="distributed_ranks"): r""" @@ -827,7 +831,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. - .. SEEALSO:: :meth:`one_sum`, :meth:`two_sum`, + .. SEEALSO:: :meth:`one_sum`, :meth:`two_sum`, :meth:`three_sum`, :meth:`three_sum_wide_wide`, :meth:`three_sum_mixed_mixed` INPUT: @@ -841,6 +845,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``three_sum_strategy`` -- either ``"distributed_ranks"`` (default) or ``"concentrated_rank"``. + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -866,7 +872,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 -1 0 1] [ 1 0 0 -1 0] [ 0 1 0 0 1] - sage: M1.three_sum_cmr(M2, 1, 2, 2, 4, three_sum_strategy="concentrated_rank") + sage: M1._three_sum_cmr(M2, 1, 2, 2, 4, three_sum_strategy="concentrated_rank") [ 1 1 0 0 0 0 0 0] [ 0 0 -1 1 0 0 0 0] [ 0 1 1 0 1 0 0 0] @@ -875,7 +881,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-1 -1 0 1 -2 0 0 0] [ 0 0 0 0 0 1 0 -1] [ 0 -1 1 0 -1 0 1 0] - sage: M1.three_sum_cmr(M2, 1, 2, 1, 1) + sage: M1._three_sum_cmr(M2, 1, 2, 1, 1) [ 1 1 0 0 0 0 0 0] [ 0 -1 0 -1 1 1 1 -1] [ 0 0 1 0 -1 -1 -1 1] @@ -942,7 +948,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sum = Matrix_cmr_chr_sparse._from_cmr(sum_mat) return sum - def three_sum_wide_wide(first_mat, second_mat): + def three_sum_wide_wide(first_mat, second_mat, + first_row_index=-1, + first_columns_index=[-2, -1], + second_row_index=0, + second_columns_index=[0, 1], + algorithm="cmr", + verify=True, + sign_verify=False): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, assume that ``three_sum_strategy="distributed_ranks"``. @@ -956,6 +969,30 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + .. SEEALSO:: :meth:`three_sum`, :meth:`is_three_sum`, + :meth:`three_sum_mixed_mixed` + + INPUT: + + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``first_row_index`` -- the row index of `a_1^T` in `M_1` + - ``first_columns_index`` -- the column indices of `a_2` in `M_1` + - ``second_row_index`` -- the row index of `b_2^T` in `M_2` + - ``second_columns_index`` -- the column indices of `b_1` in `M_2` + - ``algorithm`` -- ``"cmr"`` or ``"direct"`` + If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; + If ``algorithm="direct"``, then construct three sum directly. + - ``verify`` -- boolean (default:``True``) + Whether to check the give two matrices and the related indices + satisfying the requirements of 3-sum + by calling :meth:`is_three_sum_wide_wide`. + - ``sign_verify`` -- boolean (default:``False``) + Whether to check the sign correctness. + See :meth:`is_three_sum_wide_wide`. + + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -990,39 +1027,147 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 0 0 -1 0 1] [ 0 0 0 0 1 0 -1 0] [ 1 0 -1 1 0 0 0 1] + + Three sum can be computed for any row and column indices: + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [1, 0, 1,-1, 1, 0], + ....: [0,-1, 1, 0,-1, 1], + ....: [0, 0,-1, 1, 0,-1], + ....: [0, 1, 1, 0, 1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 1 0 1 -1 1 0] + [ 0 -1 1 0 -1 1] + [ 0 0 -1 1 0 -1] + [ 0 1 1 0 1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1,-1, 1, 0, 0,-1], + ....: [1, 1, 1, 1,-1, 0], + ....: [0, 0,-1, 0, 1, 0], + ....: [1, 0, 0,-1, 0, 0], + ....: [0, 1, 0, 0, 1, 1]]); M2 + [ 1 -1 1 0 0 -1] + [ 1 1 1 1 -1 0] + [ 0 0 -1 0 1 0] + [ 1 0 0 -1 0 0] + [ 0 1 0 0 1 1] + sage: M = M1.three_sum_wide_wide(M2, 1, [2,-1], 1, [1, -1]); M + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] + sage: N = M1.three_sum_wide_wide(M2, 1, [2,-1], 1, [1, -1], algorithm="direct") + sage: M == N + True + + sage: M1.three_sum_wide_wide(M2, 1, [2, 3], 1, [1, -1]) + Traceback (most recent call last): + ... + ValueError: The given two matrices and related indices do not satisfy the rule for three sum! + sage: M1.three_sum_wide_wide(M2, 1, [2, 3], 1, [1, -1], verify=False) + [ 1 1 0 0 0 0 0 0] + [ 0 -1 -1 1 1 1 1 -1] + [ 0 0 0 -1 -1 -1 -1 1] + [ 0 1 1 1 1 1 1 -1] + [-1 0 -1 0 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 1 0 0 0 0 1] """ m1 = first_mat.nrows() n1 = first_mat.ncols() m2 = second_mat.nrows() n2 = second_mat.ncols() - first_subcol = first_mat.matrix_from_rows_and_columns(range(m1 - 1), [n1 - 1]) - second_subcol = second_mat.matrix_from_rows_and_columns(range(1, m2), [0]) - - first_row = first_mat.matrix_from_rows_and_columns([m1 - 1], range(n1 - 2)) - second_row = second_mat.matrix_from_rows_and_columns([0], range(2, n2)) - - first_submat = first_mat.matrix_from_rows_and_columns(range(m1 - 1), range(n1 - 2)) - second_submat = second_mat.matrix_from_rows_and_columns(range(1, m2), range(2, n2)) - - first_subrows = first_submat.rows() - second_subrows = second_submat.rows() - upper_right_rows = first_subcol.tensor_product(second_row).rows() - lower_left_rows = second_subcol.tensor_product(first_row).rows() - - row_list = [] - for i in range(m1 - 1): - r = list(first_subrows[i]) - u = list(upper_right_rows[i]) - r.extend(u) - row_list.append(r) - for i in range(m2 - 1): - r = list(lower_left_rows[i]) - u = list(second_subrows[i]) - r.extend(u) - row_list.append(r) - return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) - - def three_sum_mixed_mixed(first_mat, second_mat): + j1 = first_columns_index[0] + j2 = first_columns_index[1] + j1 = j1 if j1 >= 0 else n1 + j1 + j2 = j2 if j2 >= 0 else n1 + j2 + i1 = first_row_index + i1 = i1 if i1 >= 0 else m1 + i1 + k1 = second_columns_index[0] + k2 = second_columns_index[1] + k1 = k1 if k1 >= 0 else n2 + k1 + k2 = k2 if k2 >= 0 else n2 + k2 + i2 = second_row_index + i2 = i2 if i2 >= 0 else m2 + i2 + if j1 > j2: + j2, j1 = j1, j2 + if k1 > k2: + k2, k1 = k1, k2 + + if algorithm not in ["cmr", "direct"]: + raise ValueError("Unknown algorithm", algorithm) + + if algorithm == "cmr": + column_index_1 = [j for j in range(n1) if j != j2] + column_index_2 = [j for j in range(n2) if j != k2] + first_submat = first_mat.matrix_from_rows_and_columns(range(m1), column_index_1) + second_submat = second_mat.matrix_from_rows_and_columns(range(m2), column_index_2) + M = Matrix_cmr_chr_sparse._three_sum_cmr(first_submat, second_submat, + i1, j1, + i2, k1, + three_sum_strategy="distributed_ranks") + if algorithm == "direct": + row_index_1 = [i for i in range(m1) if i != i1] + column_index_1 = [j for j in range(n1) if j != j1 and j != j2] + row_index_2 = [i for i in range(m2) if i != i2] + column_index_2 = [j for j in range(n2) if j != k1 and j != k2] + a2 = first_mat.matrix_from_rows_and_columns(row_index_1, [j1]) + b1 = second_mat.matrix_from_rows_and_columns(row_index_2, [k1]) + + a1 = first_mat.matrix_from_rows_and_columns([i1], column_index_1) + b2 = second_mat.matrix_from_rows_and_columns([i2], column_index_2) + + A = first_mat.matrix_from_rows_and_columns(row_index_1, column_index_1) + B = second_mat.matrix_from_rows_and_columns(row_index_2, column_index_2) + + first_subrows = A.rows() + second_subrows = B.rows() + upper_right_rows = a2.tensor_product(b2).rows() + lower_left_rows = b1.tensor_product(a1).rows() + + row_list = [] + for i in range(m1 - 1): + r = list(first_subrows[i]) + u = list(upper_right_rows[i]) + r.extend(u) + row_list.append(r) + for i in range(m2 - 1): + r = list(lower_left_rows[i]) + u = list(second_subrows[i]) + r.extend(u) + row_list.append(r) + M = Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + + if not verify: + return M + result = M.is_three_sum_wide_wide(first_mat, second_mat, + first_row_index=first_row_index, + first_columns_index=first_columns_index, + second_row_index=second_row_index, + second_columns_index=second_columns_index, + sign_verify=sign_verify) + if result is True: + return M + elif result is False: + raise ValueError('The given two matrices and related indices ' + 'do not satisfy the rule for three sum!') + else: + return result[1] + + def three_sum_mixed_mixed(first_mat, second_mat, + first_rows_index=[-2, -1], + first_column_index=-1, + second_row_index=0, + second_columns_index=[0, 1], + algorithm="cmr", + verify=True, + sign_verify=False): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, assume that ``three_sum_strategy="concentrated_rank"``. @@ -1036,6 +1181,30 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. + .. SEEALSO:: :meth:`three_sum`, :meth:`is_three_sum`, + :meth:`three_sum_mixed_mixed` + + INPUT: + + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``first_rows_index`` -- the indices of rows `a_1^T` and `a_2^T` in `M_1` + - ``first_column_index`` -- the index of the extra column in `M_1` + - ``second_row_index`` -- the index of the extra row in `M_2` + - ``second_columns_index`` -- the indices of columns `b_1` and `b_2` in `M_2` + - ``algorithm`` -- ``"cmr"`` or ``"direct"`` + If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; + If ``algorithm="direct"``, then construct three sum directly. + - ``verify`` -- boolean (default:``True``) + Whether to check the give two matrices and the related indices + satisfying the requirements of 3-sum + by calling :meth:`is_three_sum_mixed_mixed`. + - ``sign_verify`` -- boolean (default:``False``) + Whether to check the sign correctness. + See :meth:`is_three_sum_mixed_mixed`. + + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1072,20 +1241,347 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-1 -1 0 1 -2 0 0 0] [ 0 0 0 0 0 1 0 -1] [ 0 -1 1 0 -1 0 1 0] + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0]]); M1 + [ 1 1 0 0 0 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[0, 0, 1, 0, 1], + ....: [1,-1, 1, 0, 0], + ....: [1, 1, 1, 1,-1], + ....: [0, 0,-1, 0, 1], + ....: [1, 0, 0,-1, 0], + ....: [0, 1, 0, 0, 1]]); M2 + [ 0 0 1 0 1] + [ 1 -1 1 0 0] + [ 1 1 1 1 -1] + [ 0 0 -1 0 1] + [ 1 0 0 -1 0] + [ 0 1 0 0 1] + sage: M = M1.three_sum_mixed_mixed(M2, first_rows_index=[1, 2], + ....: second_columns_index=[2, 4]); M + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + sage: N = M1.three_sum_mixed_mixed(M2, first_rows_index=[1, 2], + ....: second_columns_index=[2, 4], algorithm="direct") + sage: M == N + True + sage: M1.three_sum_mixed_mixed(M2, first_rows_index=[1, 2], + ....: first_column_index=1, + ....: second_columns_index=[2, 4]) + Traceback (most recent call last): + ... + ValueError: The given two matrices and related indices do not satisfy the rule for three sum! + sage: M1.three_sum_mixed_mixed(M2, first_rows_index=[1, 2], + ....: first_column_index=1, + ....: second_columns_index=[2, 4], verify=False) + [ 1 0 0 0 0 0 0 0] + [ 0 -1 1 0 0 0 0 0] + [ 0 1 0 1 0 0 0 0] + [ 1 1 -1 1 1 1 -1 0] + [ 1 0 -1 2 0 1 1 1] + [-1 0 1 -2 0 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 1 0 -1 1 0 1 0] """ m1 = first_mat.nrows() n1 = first_mat.ncols() m2 = second_mat.nrows() n2 = second_mat.ncols() - first_submat = first_mat.matrix_from_rows_and_columns(range(m1), range(n1 - 1)) - second_submat = second_mat.matrix_from_rows_and_columns(range(1, m2), range(n2)) + j1 = first_rows_index[0] + j2 = first_rows_index[1] + j1 = j1 if j1 >= 0 else m1 + j1 + j2 = j2 if j2 >= 0 else m1 + j2 + i1 = first_column_index + i1 = i1 if i1 >= 0 else n1 + i1 + k1 = second_columns_index[0] + k2 = second_columns_index[1] + k1 = k1 if k1 >= 0 else n2 + k1 + k2 = k2 if k2 >= 0 else n2 + k2 + i2 = second_row_index + i2 = i2 if i2 >= 0 else m2 + i2 + if j1 > j2: + j2, j1 = j1, j2 + if k1 > k2: + k2, k1 = k1, k2 + + if algorithm not in ["cmr", "direct"]: + raise ValueError("Unknown algorithm", algorithm) + + if algorithm == "cmr": + column_index_1 = [j for j in range(n1) if j != i1] + row_index_2 = [i for i in range(m2) if i != i2] + first_submat = first_mat.matrix_from_rows_and_columns(range(m1), column_index_1) + second_submat = second_mat.matrix_from_rows_and_columns(row_index_2, range(n2)) + + M = Matrix_cmr_chr_sparse._three_sum_cmr(first_submat, second_submat, + j1, j2, + k1, k2, + three_sum_strategy="concentrated_rank") + if algorithm == "direct": + row_index_1 = [i for i in range(m1) if i != j1 and i != j2] + column_index_1 = [j for j in range(n1) if j != i1] + row_index_2 = [i for i in range(m2) if i != i2] + column_index_2 = [j for j in range(n2) if j != k1 and j != k2] + a1 = first_mat.matrix_from_rows_and_columns([j1], column_index_1) + a2 = first_mat.matrix_from_rows_and_columns([j2], column_index_1) + b1 = second_mat.matrix_from_rows_and_columns(row_index_2, [k1]) + b2 = second_mat.matrix_from_rows_and_columns(row_index_2, [k2]) + + A = first_mat.matrix_from_rows_and_columns(row_index_1, column_index_1) + B = second_mat.matrix_from_rows_and_columns(row_index_2, column_index_2) + + first_subrows = A.rows() + second_subrows = B.rows() + lower_left_rows = (b1.tensor_product(a1) + b2.tensor_product(a2)).rows() + + row_list = [] + for i in range(m1 - 2): + r = list(first_subrows[i]) + u = [0 for j in range(n2 - 2)] + r.extend(u) + row_list.append(r) + for i in range(m2 - 1): + r = list(lower_left_rows[i]) + u = list(second_subrows[i]) + r.extend(u) + row_list.append(r) + M = Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) + + if not verify: + return M + result = M.is_three_sum_mixed_mixed(first_mat, second_mat, + first_rows_index=first_rows_index, + first_column_index=first_column_index, + second_row_index=second_row_index, + second_columns_index=second_columns_index, + sign_verify=sign_verify) + if result is True: + return M + elif result is False: + raise ValueError('The given two matrices and related indices ' + 'do not satisfy the rule for three sum!') + else: + return result[1] + + def three_sum(first_mat, second_mat, + first_one_index=-1, + first_two_indices=[-2, -1], + second_one_index=0, + second_two_indices=[0, 1], + three_sum_strategy="distributed_ranks", + algorithm="cmr", + verify=True, + sign_verify=False): + r""" + Return the 3-sum matrix constructed from the given matrices + ``first_mat`` and ``second_mat``. + + .. SEEALSO:: :meth:`three_sum_wide_wide`, + :meth:`three_sum_mixed_mixed` + + INPUT: + + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``first_one_index`` -- the index of one extra row/column in `M_1` + - ``first_two_indices`` -- the indices of two extra rows/columns in `M_1` + - ``second_one_index`` -- the index of one extra row/column in `M_2` + - ``second_two_indices`` -- the indices of two extra rows/columns in `M_2` + - ``three_sum_strategy`` -- ``"distributed_ranks"`` or ``"Wide_Wide"`` or + ``concentrated_rank`` or ``"Mixed_Mixed"`` + - ``algorithm`` -- ``"cmr"`` or ``"direct"`` + If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; + If ``algorithm="direct"``, then construct three sum directly. + - ``verify`` -- boolean (default:``True``) + Whether to check the give two matrices and the related indices + satisfying the requirements of 3-sum + by calling :meth:`is_three_sum_wide_wide` or + :meth:`is_three_sum_mixed_mixed`. + - ``sign_verify`` -- boolean (default:``False``) + Whether to check the sign correctness. + See :meth:`is_three_sum`. + + OUTPUT: A :class:`Matrix_cmr_chr_sparse` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0,-1, 0,-1, 1, 1], + ....: [0, 0, 1, 0,-1,-1], + ....: [0, 1, 0, 1, 1, 1], + ....: [1, 0,-1, 1, 0, 1],]); M1 + [ 1 1 0 0 0 0] + [ 0 -1 0 -1 1 1] + [ 0 0 1 0 -1 -1] + [ 0 1 0 1 1 1] + [ 1 0 -1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[ 1, 0, 1, 1, 1,-1], + ....: [-1,-1, 1, 1, 0, 0], + ....: [ 0, 0, 0,-1, 0, 1], + ....: [ 0, 0, 1, 0,-1, 0], + ....: [ 1, 1, 0, 0, 0, 1]]); M2 + [ 1 0 1 1 1 -1] + [-1 -1 1 1 0 0] + [ 0 0 0 -1 0 1] + [ 0 0 1 0 -1 0] + [ 1 1 0 0 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum(M1, M2); M + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum(M1, M2) + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[ 1, 1, 0, 0, 0], + ....: [ 1, 0, 1,-1, 0], + ....: [ 1,-1, 1, 1, 1], + ....: [-1, 1, 0, 0, 0], + ....: [ 0, 0, 1, 0,-1], + ....: [ 0, 1, 0, 1, 0]]); M2 + [ 1 1 0 0 0] + [ 1 0 1 -1 0] + [ 1 -1 1 1 1] + [-1 1 0 0 0] + [ 0 0 1 0 -1] + [ 0 1 0 1 0] + sage: M = Matrix_cmr_chr_sparse.three_sum(M1, M2, three_sum_strategy="Mixed_Mixed"); M + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] - return Matrix_cmr_chr_sparse.three_sum_cmr(first_submat, second_submat, - m1 - 2, m1 - 1, - 0, 1, - three_sum_strategy="concentrated_rank") + sage: M1.three_sum(M2, three_sum_strategy="Wide_Mixed") + Traceback (most recent call last): + ... + ValueError: ('Unknown three sum mode', 'Wide_Mixed') - def is_three_sum_wide_wide(first_mat, second_mat, three_sum_mat, + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0]]); M1 + [ 1 1 0 0 0 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[0, 0, 1, 0, 1], + ....: [1,-1, 1, 0, 0], + ....: [1, 1, 1, 1,-1], + ....: [0, 0,-1, 0, 1], + ....: [1, 0, 0,-1, 0], + ....: [0, 1, 0, 0, 1]]); M2 + [ 0 0 1 0 1] + [ 1 -1 1 0 0] + [ 1 1 1 1 -1] + [ 0 0 -1 0 1] + [ 1 0 0 -1 0] + [ 0 1 0 0 1] + sage: M1.three_sum(M2, first_two_indices=[1, 2], + ....: second_two_indices=[2, 4], + ....: three_sum_strategy="concentrated_rank") + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [1, 0, 1,-1, 1, 0], + ....: [0,-1, 1, 0,-1, 1], + ....: [0, 0,-1, 1, 0,-1], + ....: [0, 1, 1, 0, 1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 1 0 1 -1 1 0] + [ 0 -1 1 0 -1 1] + [ 0 0 -1 1 0 -1] + [ 0 1 1 0 1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1,-1, 1, 0, 0,-1], + ....: [1, 1, 1, 1,-1, 0], + ....: [0, 0,-1, 0, 1, 0], + ....: [1, 0, 0,-1, 0, 0], + ....: [0, 1, 0, 0, 1, 1]]); M2 + [ 1 -1 1 0 0 -1] + [ 1 1 1 1 -1 0] + [ 0 0 -1 0 1 0] + [ 1 0 0 -1 0 0] + [ 0 1 0 0 1 1] + sage: M1.three_sum(M2, 1, [2,-1], 1, [1, -1]) + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] + """ + if three_sum_strategy in ["distributed_ranks", "Wide_Wide"]: + return first_mat.three_sum_wide_wide(second_mat, + first_row_index=first_one_index, + first_columns_index=first_two_indices, + second_row_index=second_one_index, + second_columns_index=second_two_indices, + algorithm=algorithm, + verify=verify, + sign_verify=sign_verify) + if three_sum_strategy in ["concentrated_rank", "Mixed_Mixed"]: + return first_mat.three_sum_mixed_mixed(second_mat, + first_rows_index=first_two_indices, + first_column_index=first_one_index, + second_row_index=second_one_index, + second_columns_index=second_two_indices, + algorithm=algorithm, + verify=verify, + sign_verify=sign_verify) + raise ValueError("Unknown three sum mode", three_sum_strategy) + + def is_three_sum_wide_wide(three_sum_mat, first_mat, second_mat, first_row_index=-1, first_columns_index=[-2, -1], second_row_index=0, @@ -1123,6 +1619,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: + - ``three_sum_mat`` -- the large integer matrix `M` - ``first_mat`` -- the first integer matrix `M_1` - ``second_mat`` -- the second integer matrix `M_2` - ``first_row_index`` -- the row index of `a_1^T` in `M_1` @@ -1170,7 +1667,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 0 0 -1 0 1] [ 0 0 0 0 1 0 -1 0] [ 1 0 -1 1 0 0 0 1] - sage: Matrix_cmr_chr_sparse.is_three_sum_wide_wide(M1, M2, M) + sage: M.is_three_sum_wide_wide(M1, M2, sign_verify=False) + True + sage: M.is_three_sum_wide_wide(M1, M2) (False, 'sign_1 in second_mat should be -1. sign_2 in first_mat should be -1. ') @@ -1199,7 +1698,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 0 1 0 1] [ 1 0 1 0 1 1] [ 1 0 1 0 0 1] - sage: Matrix_cmr_chr_sparse.is_three_sum_wide_wide(M1, M2, M) + sage: Matrix_cmr_chr_sparse.is_three_sum_wide_wide(M, M1, M2) True """ if not isinstance(first_columns_index, (list, tuple)) or len(first_columns_index) != 2: @@ -1341,12 +1840,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, msg return True - def is_three_sum_mixed_mixed(first_mat, second_mat, three_sum_mat, - first_rows_index=[-2, -1], - first_column_index=-1, - second_row_index=0, - second_columns_index=[0, 1], - sign_verify=True): + def is_three_sum_mixed_mixed(three_sum_mat, first_mat, second_mat, + first_rows_index=[-2, -1], + first_column_index=-1, + second_row_index=0, + second_columns_index=[0, 1], + sign_verify=True): r""" Check whether ``first_mat`` and ``second_mat`` form ``three_sum_mat`` via the 3-sum operation. @@ -1371,6 +1870,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: + - ``three_sum_mat`` -- the large integer matrix `M` - ``first_mat`` -- the first integer matrix `M_1` - ``second_mat`` -- the second integer matrix `M_2` - ``first_rows_index`` -- the indices of rows `a_1^T` and `a_2^T` in `M_1` @@ -1420,9 +1920,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-1 -1 0 1 -2 0 0 0] [ 0 0 0 0 0 1 0 -1] [ 0 -1 1 0 -1 0 1 0] - sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M, sign_verify=False) + sage: M.is_three_sum_mixed_mixed(M1, M2, sign_verify=False) True - sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M) + sage: M.is_three_sum_mixed_mixed(M1, M2) True sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), @@ -1452,7 +1952,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [0 1 0 1 1 1] [1 0 1 0 1 0] [0 1 0 1 0 1] - sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M1, M2, M) + sage: Matrix_cmr_chr_sparse.is_three_sum_mixed_mixed(M, M1, M2) True """ if not isinstance(first_rows_index, (list, tuple)) or len(first_rows_index) != 2: @@ -1601,7 +2101,141 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return False, msg return True - def three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): + def is_three_sum(three_sum_mat, first_mat, second_mat, + three_sum_strategy="distributed_ranks", + first_one_index=-1, + first_two_indices=[-2, -1], + second_one_index=0, + second_two_indices=[0, 1], + sign_verify=True): + r""" + Check whether ``first_mat`` and ``second_mat`` form ``three_sum_mat`` + via the 3-sum operation. + If ``sign_verify=True``, also check whether the 3-sum satisfies that + ``three_sum_mat`` is totally unimodular, if and only if, + ``first_mat`` and ``second_mat`` are both totally unimodular. + + .. SEEALSO:: :meth:`is_three_sum_wide_wide`, + :meth:`is_three_sum_mixed_mixed` + + INPUT: + + - ``three_sum_mat`` -- the large integer matrix `M` + - ``first_mat`` -- the first integer matrix `M_1` + - ``second_mat`` -- the second integer matrix `M_2` + - ``three_sum_strategy`` -- ``"distributed_ranks"`` or ``"Wide_Wide"`` or + ``concentrated_rank`` or ``"Mixed_Mixed"`` + - ``first_one_index`` -- the index of one extra row/column in `M_1` + - ``first_two_indices`` -- the indices of two extra rows/columns in `M_1` + - ``second_one_index`` -- the index of one extra row/column in `M_2` + - ``second_two_indices`` -- the indices of two extra rows/columns in `M_2` + - ``sign_verify`` -- boolean (default:``True``) + Whether to check the sign correctness. + + OUTPUT: boolean, or (boolean, string) + + If it is False only because of the sign, then also output the correct sign. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0,-1, 0,-1, 1, 1], + ....: [0, 0, 1, 0,-1,-1], + ....: [0, 1, 0, 1, 1, 1], + ....: [1, 0,-1, 1, 0, 1],]); M1 + [ 1 1 0 0 0 0] + [ 0 -1 0 -1 1 1] + [ 0 0 1 0 -1 -1] + [ 0 1 0 1 1 1] + [ 1 0 -1 1 0 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[ 1, 0, 1, 1, 1,-1], + ....: [-1,-1, 1, 1, 0, 0], + ....: [ 0, 0, 0,-1, 0, 1], + ....: [ 0, 0, 1, 0,-1, 0], + ....: [ 1, 1, 0, 0, 0, 1]]); M2 + [ 1 0 1 1 1 -1] + [-1 -1 1 1 0 0] + [ 0 0 0 -1 0 1] + [ 0 0 1 0 -1 0] + [ 1 1 0 0 0 1] + sage: M = Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2); M + [ 1 1 0 0 0 0 0 0] + [ 0 -1 0 -1 1 1 1 -1] + [ 0 0 1 0 -1 -1 -1 1] + [ 0 1 0 1 1 1 1 -1] + [-1 0 1 -1 1 1 0 0] + [ 0 0 0 0 0 -1 0 1] + [ 0 0 0 0 1 0 -1 0] + [ 1 0 -1 1 0 0 0 1] + sage: M.is_three_sum(M1, M2, sign_verify=False) + True + sage: M.is_three_sum(M1, M2) + (False, + 'sign_1 in second_mat should be -1. sign_2 in first_mat should be -1. ') + + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), + ....: [[1, 1, 0, 0, 0, 0], + ....: [0, 0,-1, 1, 0, 0], + ....: [0, 1, 1, 0, 1, 0], + ....: [1, 0, 1,-1, 1, 1], + ....: [0,-1, 1, 0,-1, 1]]); M1 + [ 1 1 0 0 0 0] + [ 0 0 -1 1 0 0] + [ 0 1 1 0 1 0] + [ 1 0 1 -1 1 1] + [ 0 -1 1 0 -1 1] + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 5, sparse=True), + ....: [[ 1, 1, 0, 0, 0], + ....: [ 1, 0, 1,-1, 0], + ....: [ 1,-1, 1, 1, 1], + ....: [-1, 1, 0, 0, 0], + ....: [ 0, 0, 1, 0,-1], + ....: [ 0, 1, 0, 1, 0]]); M2 + [ 1 1 0 0 0] + [ 1 0 1 -1 0] + [ 1 -1 1 1 1] + [-1 1 0 0 0] + [ 0 0 1 0 -1] + [ 0 1 0 1 0] + sage: M = Matrix_cmr_chr_sparse.three_sum_mixed_mixed(M1, M2); M + [ 1 1 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0] + [ 0 1 1 0 1 0 0 0] + [ 1 0 1 -1 1 1 -1 0] + [ 1 1 0 -1 2 1 1 1] + [-1 -1 0 1 -2 0 0 0] + [ 0 0 0 0 0 1 0 -1] + [ 0 -1 1 0 -1 0 1 0] + sage: M.is_three_sum(M1, M2, three_sum_strategy="Mixed_Mixed", sign_verify=False) + True + sage: M.is_three_sum(M1, M2, three_sum_strategy="Mixed_Mixed") + True + + sage: M.is_three_sum(M1, M2, three_sum_strategy="Wide_Mixed") + Traceback (most recent call last): + ... + ValueError: ('Unknown three sum mode', 'Wide_Mixed') + """ + if three_sum_strategy in ["distributed_ranks", "Wide_Wide"]: + return three_sum_mat.is_three_sum_wide_wide(first_mat, second_mat, + first_row_index=first_one_index, + first_columns_index=first_two_indices, + second_row_index=second_one_index, + second_columns_index=second_two_indices, + sign_verify=sign_verify) + if three_sum_strategy in ["concentrated_rank", "Mixed_Mixed"]: + return three_sum_mat.is_three_sum_mixed_mixed(first_mat, second_mat, + first_rows_index=first_two_indices, + first_column_index=first_one_index, + second_row_index=second_one_index, + second_columns_index=second_two_indices, + sign_verify=sign_verify) + raise ValueError("Unknown three sum mode", three_sum_strategy) + + def _three_sum(first_mat, second_mat, first_col_index1, first_col_index2, second_col_index1, second_col_index2): r""" Return the 3-sum matrix constructed from the given matrices ``first_mat`` and ``second_mat``, with ``first_col_index1`` and ``first_col_index2`` being the @@ -1644,7 +2278,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [1 0 1 1 0] [0 0 0 1 1] [1 1 0 0 1] - sage: M3 = Matrix_cmr_chr_sparse.three_sum(M, M, 0, 1, 0, 1); M3 + sage: M3 = Matrix_cmr_chr_sparse._three_sum(M, M, 0, 1, 0, 1); M3 [1 1 1 1 1 0] [1 0 0 1 1 0] [0 1 1 0 0 0] @@ -1722,12 +2356,18 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def delete_rows(self, indices): + r""" + Delete rows of the matrices ``self``. + """ rows = self.rows() n = len(rows) row_list = [rows[i] for i in range(n) if i not in indices] return Matrix_cmr_chr_sparse._from_data(row_list, immutable=False) def delete_columns(self, indices): + r""" + Delete columns of the matrices ``self``. + """ rows = self.rows() n = self.ncols() row_list = [] From 6a2b9d69d8cb2cba2d2e5657dc27da93c70ca6a2 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Sun, 8 Sep 2024 21:13:08 -0500 Subject: [PATCH 236/262] WIP: add doctests for seymour_decomposition --- src/sage/matrix/seymour_decomposition.pyx | 177 ++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 206541dd57f..7a252c2545f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -36,9 +36,59 @@ cdef class DecompositionNode(SageObject): """ def __cinit__(self, *args, **kwds): + r""" + Initialize the internal decomposition, a ``CMR_SEYMOUR_NODE``. + """ self._dec = NULL def __init__(self, matrix=None, row_keys=None, column_keys=None, base_ring=None): + r""" + Create a node in Seymour's decomposition. + + INPUT: + + - ``matrix`` -- the internal matrix representing the node. + Convert to a :class:`Matrix_cmr_chr_sparse`. + + - ``row_keys`` -- a finite or enumerated family of arbitrary objects + that index the rows of the matrix + + - ``column_keys`` -- a finite or enumerated family of arbitrary objects + that index the columns of the matrix + + - ``base_ring`` -- the base ring of ``matrix`` representing the node. + For Seymour decomposition node, the base ring is `\GF{2}` or `\GF{3}` or ``ZZ``. + If the base ring is `\GF{2}`, the node and the matrix deal with + the underlying binary linear matroid; + if the base ring is `\GF(3)` or ``ZZ``, the node deals with + the matrix decomposition. + + A :class:DecompositionNode is usually created with an internal decomposition, + ``self._dec``, see :meth:create_DecompositionNode + Such decomposition comes from the certificate of the + totally unimodularity test, see + :meth:`matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_totally_unimodular` + + Another usage is to create a :class:UnknownNode from a matrix. + A root dummy decomposition is created before completing + the decomposition, see :meth:_set_root_dec, :meth:complete_decomposition + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + """ if matrix is None: self._matrix = None elif isinstance(matrix, Matrix_cmr_chr_sparse): @@ -67,6 +117,10 @@ cdef class DecompositionNode(SageObject): self._base_ring = base_ring cdef _set_dec(self, CMR_SEYMOUR_NODE *dec): + r""" + Set the decomposition ``self._dec`` to ``dec``. + If the value was previously set, then free it first. + """ if self._dec != NULL: # We own it, so we have to free it. CMR_CALL(CMRseymourRelease(cmr, &self._dec)) @@ -75,6 +129,10 @@ cdef class DecompositionNode(SageObject): self._dec = dec cdef _set_root_dec(self): + r""" + Set the decomposition by creating a root ``CMR_SEYMOUR_NODE`` + based on the internal matrix representation ``self._matrix``. + """ cdef CMR_SEYMOUR_NODE *root cdef Matrix_cmr_chr_sparse matrix try: @@ -125,12 +183,45 @@ cdef class DecompositionNode(SageObject): self._column_keys = column_keys def __dealloc__(self): + """ + Frees all the memory allocated for this node. + """ self._set_dec(NULL) def __hash__(self): + """ + Return a hash of this node. It is the hash of the decomposition. + """ return self._dec def nrows(self): + r""" + Return the number of rows of the internal matrix representing this node. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.nrows() + 3 + sage: certificate.ncols() + 2 + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + sage: node.nrows() + 2 + sage: node.ncols() + 2 + """ if self._row_keys is not None: return len(self._row_keys) if self._dec != NULL: @@ -140,6 +231,33 @@ cdef class DecompositionNode(SageObject): raise RuntimeError('nrows undefined') def ncols(self): + r""" + Return the number of columns of the internal matrix representing this node. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.nrows() + 3 + sage: certificate.ncols() + 2 + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + sage: node.nrows() + 2 + sage: node.ncols() + 2 + """ if self._column_keys is not None: return len(self._column_keys) if self._dec != NULL: @@ -149,9 +267,35 @@ cdef class DecompositionNode(SageObject): raise RuntimeError('ncols undefined') def dimensions(self): + r""" + Return the number of rows and columns of this node. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.dimensions() + (3, 2) + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + sage: node.dimensions() + (2, 2) + """ return self.nrows(), self.ncols() def base_ring(self): + r""" + Return the base ring of the matrix representing the node. + """ return self._base_ring def matrix(self): @@ -173,6 +317,13 @@ cdef class DecompositionNode(SageObject): [ 1 0] [-1 1] [ 0 1] + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode([[1, 1], [0, 1]]); node + UnknownNode (2×2) + sage: node.matrix() + [1 1] + [0 1] """ if self._matrix is not None: return self._matrix @@ -200,6 +351,11 @@ cdef class DecompositionNode(SageObject): return self._column_keys def set_default_keys(self): + r""" + Set default row and column keys. + + .. SEEALSO:: :class:ElementKey + """ row_keys = self.row_keys() column_keys = self.column_keys() if row_keys is None or column_keys is None: @@ -214,7 +370,25 @@ cdef class DecompositionNode(SageObject): @cached_method def morphism(self): r""" + Create the matrix in the distinguished bases of the domain and codomain + to build the module morphism. + + See also: :class:`sage.modules.with_basis.morphism.ModuleMorphismFromMatrix`. + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node.matrix() + [1 0 1] + [0 1 1] + sage: node.morphism()._unicode_art_matrix() + 0 1 2 + a⎛1 0 1⎞ + b⎝0 1 1⎠ """ return Matrix(self.matrix(), row_keys=self.row_keys(), @@ -2118,6 +2292,9 @@ cdef class ElementKey: return self._key def __hash__(self): + """ + Return a hash of this element key + """ return hash(self._key) def __eq__(self, other): From eddb0f9dd2d3610875407c8647889a59f9fe0b7f Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Mon, 16 Sep 2024 16:39:40 -0700 Subject: [PATCH 237/262] WIP: add doctests for seymour_decomposition --- src/sage/matrix/seymour_decomposition.pyx | 193 ++++++++++++++++++++-- 1 file changed, 181 insertions(+), 12 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 7a252c2545f..f8a0b32ef3b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -340,13 +340,37 @@ cdef class DecompositionNode(SageObject): def row_keys(self): r""" + Return the row keys of this node. + OUTPUT: a tuple or ``None`` + + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node.row_keys() + ('a', 'b') """ return self._row_keys def column_keys(self): r""" + Return the column keys of this node. + OUTPUT: a tuple or ``None`` + + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node.column_keys() + (0, 1, 2) """ return self._column_keys @@ -355,6 +379,23 @@ cdef class DecompositionNode(SageObject): Set default row and column keys. .. SEEALSO:: :class:ElementKey + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.row_keys() is None + True + sage: certificate.set_default_keys() + sage: certificate.row_keys() + (r0, r1, r2) """ row_keys = self.row_keys() column_keys = self.column_keys() @@ -377,18 +418,18 @@ cdef class DecompositionNode(SageObject): EXAMPLES:: - sage: from sage.matrix.seymour_decomposition import UnknownNode - sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), - ....: row_keys='ab', - ....: column_keys=range(3)); node - UnknownNode (2×3) - sage: node.matrix() - [1 0 1] - [0 1 1] - sage: node.morphism()._unicode_art_matrix() - 0 1 2 - a⎛1 0 1⎞ - b⎝0 1 1⎠ + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node.matrix() + [1 0 1] + [0 1 1] + sage: node.morphism()._unicode_art_matrix() + 0 1 2 + a⎛1 0 1⎞ + b⎝0 1 1⎠ """ return Matrix(self.matrix(), row_keys=self.row_keys(), @@ -396,6 +437,8 @@ cdef class DecompositionNode(SageObject): def as_ordered_tree(self): r""" + Return the decomposition tree rooted at ``self``. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -440,12 +483,51 @@ cdef class DecompositionNode(SageObject): def is_ternary(self): r""" Returns true iff the decomposition is over `\mathbb{F}_3`. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.is_ternary() + True + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [1, 1], [0, 1]]); M + [1 0] + [1 1] + [0 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.is_ternary() + False """ return CMRseymourIsTernary(self._dec) def nchildren(self): r""" Return the number of children of the node. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0, 1]]); M + [ 1 0] + [-1 1] + [ 0 1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.nchildren() + 0 """ if self._child_nodes is not None: return len(self._child_nodes) @@ -454,6 +536,10 @@ cdef class DecompositionNode(SageObject): return CMRseymourNumChildren(self._dec) cdef _CMRelement_to_key(self, CMR_ELEMENT element): + r""" + Transform a ``CMRelement`` (row or column index implemented in cmr) + to a row key or a column key. + """ if not CMRelementIsValid(element): raise ValueError('CMRelement index not valid. Extra row or column is detected.') if self.row_keys() is None or self.column_keys() is None: @@ -464,6 +550,12 @@ cdef class DecompositionNode(SageObject): return self.column_keys()[CMRelementToColumnIndex(element)] def _create_child_node(self, index): + r""" + Return the child node of ``self`` corresponding to the ``index``, + and the corresponding row and column keys in the parent node. + + OUTPUT: a tuple of (child node, child row keys, child column keys) + """ row_keys = self.row_keys() column_keys = self.column_keys() cdef CMR_SEYMOUR_NODE *child_dec = CMRseymourChild(self._dec, index) @@ -501,6 +593,11 @@ cdef class DecompositionNode(SageObject): return child, child_row_keys, child_column_keys def _children(self): + r""" + Return a tuple of the tuples of children and their row and column keys. + The underlying implementation of :meth:`child_nodes` + and :meth:`child_indices`. + """ if self._child_nodes is not None: return self._child_nodes children_tuple = tuple(self._create_child_node(index) @@ -551,6 +648,13 @@ cdef class DecompositionNode(SageObject): def child_indices(self): r""" + Return a tuple of the tuples of the row and column keys of children + in the parent node. + + OUTPUT: a tuple of (row keys, column keys) + + If the number of children is 1, then output (row keys, column keys). + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -603,6 +707,15 @@ cdef class DecompositionNode(SageObject): ThreeSumNode (9×12) with 2 children sage: certificate.child_indices() ((r1, i, r3, r4, r5, r6, r7, r8, r9), (a, b, c, d, e, f, g, h, r2, j, k, l)) + + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 2, 2, sparse=True), + ....: [[1, 1], [-1, 0]]); M2 + [ 1 1] + [-1 0] + sage: result, certificate = M2.is_totally_unimodular(certificate=True); certificate + GraphicNode (2×2) + sage: certificate.child_indices() + () """ if self.nchildren() == 1: child = self._children()[0] @@ -610,13 +723,69 @@ cdef class DecompositionNode(SageObject): return tuple((child[1], child[2]) for child in self._children()) def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(6), + ....: column_keys='abcdef') + sage: print(certificate) + PivotsNode (6×6) + """ nrows, ncols = self.dimensions() return f'{self.__class__.__name__} ({nrows}×{ncols})' def _unicode_art_(self): + r""" + Return a unicode art representation of the decomposition tree rooted at ``self``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(6), + ....: column_keys='abcdef') + sage: unicode_art(certificate) + PivotsNode (6×6) + │ + ╭─────────────ThreeSumNode (6×6) with 2 children + │ │ + CographicNode (4×5) GraphicNode (4×5) + """ return self.as_ordered_tree()._unicode_art_() def _ascii_art_(self): + r""" + Return a ascii art representation of the decomposition tree rooted at ``self``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), + ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Wide_Wide", + ....: row_keys=range(6), + ....: column_keys='abcdef') + sage: ascii_art(certificate) + PivotsNode (6×6) + | + _________ThreeSumNode (6×6) with 2 children + / / + CographicNode (4×5) GraphicNode (4×5) + """ return self.as_ordered_tree()._ascii_art_() def one_sum(*summands, **kwds): From 12d0e5d8a900719d78744e5492ded3fd52dad0c1 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 17 Sep 2024 11:49:35 -0700 Subject: [PATCH 238/262] WIP: add doctests for seymour_decomposition: one_sum and pivot node --- src/sage/matrix/seymour_decomposition.pyx | 249 ++++++++++++++++++++++ 1 file changed, 249 insertions(+) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index f8a0b32ef3b..ce8f44ad00f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -790,6 +790,123 @@ cdef class DecompositionNode(SageObject): def one_sum(*summands, **kwds): r""" + Return a :class:OneSumNode constructed from the given nodes (summands). + + INPUT: + + - ``summands`` -- decomposition nodes :class:DecompositionNode + + - ``summand_ids`` -- a tuple or list of ids for summands + + - ``row_keys`` -- a finite or enumerated family of arbitrary objects + that index the rows of the result. + Must be consistent with the row keys of the summands + + - ``column_keys`` -- a finite or enumerated family of arbitrary objects + that index the columns of the result. + Must be consistent with the column keys of the summands + + Note that ``row_keys``, ``column_keys`` of ``summands`` are disjoint + + OUTPUT: A :class:`OneSumNode` + + The terminology "1-sum" is used in the context of Seymour's decomposition + of totally unimodular matrices and regular matroids, see [Sch1986]_. + + .. SEEALSO:: :meth:`two_sum`, :meth:`three_sum` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(4), + ....: column_keys='abcd') + sage: certificate + OneSumNode (4×4) with 2 children + sage: certificate.summand_matrices() + ( + [ 1 0] [ 1 1] + [-1 1], [-1 0] + ) + sage: certificate.child_indices() + (((0, 1), ('a', 'b')), ((2, 3), ('c', 'd'))) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: node.summand_matrices() + ( + [ 1 0] [ 1 1] + [-1 1], [-1 0] + ) + sage: node.child_indices() + (((0, 1), ('a', 'b')), ((2, 3), ('c', 'd'))) + + sage: M3 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1]], [[-1]]) + sage: result, certificate = M3.is_totally_unimodular(certificate=True, + ....: row_keys=range(4), + ....: column_keys='abcd') + sage: certificate + OneSumNode (4×4) with 3 children + sage: certificate.summand_matrices() + ( + [ 1 0] + [-1 1], [1], [-1] + ) + sage: certificate.child_indices() + (((0, 1), ('a', 'b')), ((2,), ('c',)), ((3,), ('d',))) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: node.summand_matrices() + ( + [ 1 0] + [-1 1], [1], [-1] + ) + sage: node.child_indices() + (((0, 1), ('a', 'b')), ((2,), ('c',)), ((3,), ('d',))) + + sage: from sage.matrix.seymour_decomposition import UnknownNode + sage: node = UnknownNode(matrix(ZZ, [[1, 0, 1], [0, 1, 1]]), + ....: row_keys='ab', + ....: column_keys=range(3)); node + UnknownNode (2×3) + sage: node = DecompositionNode.one_sum(certificate, node, summand_ids=range(2)) + sage: node.summand_matrices() + ( + [ 1 0| 0| 0] + [-1 1| 0| 0] + [-----+--+--] + [ 0 0| 1| 0] + [-----+--+--] [1 0 1] + [ 0 0| 0|-1], [0 1 1] + ) + sage: node.child_indices() + ((((0, 0), (0, 1), (0, 2), (0, 3)), ((0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'))), + (((1, 'a'), (1, 'b')), ((1, 0), (1, 1), (1, 2)))) + + ``row_keys``, ``column_keys`` of ``summands`` are disjoint: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys='aefg', + ....: column_keys='abcd') + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + Traceback (most recent call last): + ... + ValueError: keys must be disjoint, got summand_row_keys=('a', 'e'), summand_column_keys=('a', 'b') + + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(4), + ....: column_keys='abcd') + sage: node = DecompositionNode.one_sum(*certificate.child_nodes(), + ....: row_keys=range(4), + ....: column_keys='abce') + Traceback (most recent call last): + ... + ValueError: inconsistent column_keys, got column_keys=('a', 'b', 'c', 'e'), should be a permutation of ['a', 'b', 'c', 'd'] """ summand_ids = kwds.pop('summand_ids', None) row_keys = kwds.pop('row_keys', None) @@ -1585,6 +1702,20 @@ cdef class SumNode(DecompositionNode): """ def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(4), + ....: column_keys='abcd') + sage: print(certificate) + OneSumNode (4×4) with 2 children + """ result = super()._repr_() result += f' with {self.nchildren()} children' return result @@ -1596,6 +1727,23 @@ cdef class SumNode(DecompositionNode): summands = DecompositionNode.child_nodes def summand_matrices(self): + r""" + Return a tuple of matrices representing the child nodes. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [-1, 1]], + ....: [[1, 1], [-1, 0]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(4), + ....: column_keys='abcd') + sage: certificate.summand_matrices() + ( + [ 1 0] [ 1 1] + [-1 1], [-1 0] + ) + """ return tuple(s.matrix() for s in self.summands()) @@ -1603,6 +1751,8 @@ cdef class OneSumNode(SumNode): def block_matrix_form(self): r""" + Return the block matrix representing the one sum node. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1701,6 +1851,8 @@ cdef class TwoSumNode(SumNode): def block_matrix_form(self): r""" + Return the block matrix representing the two sum node. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1815,6 +1967,13 @@ cdef class ThreeSumNode(SumNode): def _children(self): r""" + Return a tuple of the tuples of the two children + and their row and column keys. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.three_sum` + TESTS: This is test ``WideWideR12`` and ``MixedMixedR12`` in CMR's ``test_tu.cpp``:: @@ -2097,6 +2256,24 @@ cdef class ThreeSumNode(SumNode): def is_distributed_ranks(self): r""" + Check whether the three sum node ``self`` is formed with + ``three_sum_strategy="distributed_ranks"`` or ``"Wide_Wide"``. + + The matrix representing the first child is + `M_1=\begin{bmatrix} A & a_2 & a_2\\ a_1^T & 0 & \epsilon_2\end{bmatrix}` + and the matrix representing the second child is + `M_2=\begin{bmatrix} \epsilon_1 & 0 & b_2^T\\ b_1 & b_1 & B\end{bmatrix}`, + where `\epsilon_1`, `\epsilon_2` are `1` or `-1`. + And the matrix representing ``self`` is a permutation of + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & a_2 b_2^T \\ b_1 a_1^T & B\end{bmatrix}`. + + ``distributed_ranks`` is named after the two rank 1 off-diagonal blocks. + ``Wide_Wide`` is named after the structure of the two children. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.three_sum_wide_wide` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -2125,6 +2302,8 @@ cdef class ThreeSumNode(SumNode): def block_matrix_form(self): r""" + Return the block matrix constructed from the three sum of children. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -2341,11 +2520,35 @@ cdef class R10Node(DecompositionNode): cdef class PivotsNode(DecompositionNode): def npivots(self): + r""" + Return the number of pivots in ``self``. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: certificate + PivotsNode (9×12) + sage: certificate.npivots() + 1 + """ return CMRseymourNumPivots(self._dec) @cached_method def pivot_rows_and_columns(self): r""" + Return a tuple of the row and column indices of all pivot entries. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -2372,6 +2575,34 @@ cdef class PivotsNode(DecompositionNode): def _children(self): r""" + Return a tuple of the tuples of children and their row and column keys. + The underlying implementation of :meth:`child_nodes` + and :meth:`child_indices`. + + If row and column keys are not given, set the default keys. + See alse :meth:set_default_keys + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12.is_totally_unimodular(certificate=True) + sage: certificate + PivotsNode (9×12) + sage: certificate.row_keys() + sage: certificate.child_nodes() + (ThreeSumNode (9×12) with 2 children,) + sage: certificate.row_keys() + (r0, r1, r2, r3, r4, r5, r6, r7, r8) """ if self._child_nodes is not None: return self._child_nodes @@ -2415,6 +2646,16 @@ cdef class SymbolicNode(DecompositionNode): self._symbol = symbol def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.matrix.seymour_decomposition import SymbolicNode + sage: X = SymbolicNode('X', row_keys='abc', column_keys=range(6)) + sage: print(X) + SymbolicNode X (3×6) + """ nrows, ncols = self.dimensions() symbol = self.symbol() return f'{self.__class__.__name__} {symbol} ({nrows}×{ncols})' @@ -2473,6 +2714,7 @@ cdef class ElementKey: def __repr__(self): """ + Return a string representation of ``self``. The composition key is sorted by the string of keys. """ if self._composition: @@ -2483,6 +2725,13 @@ cdef class ElementKey: cdef _class(CMR_SEYMOUR_NODE *dec): + r""" + Return the class of the decomposition `CMR_SEYMOUR_NODE`. + + INPUT: + + - ``dec`` -- a ``CMR_SEYMOUR_NODE`` + """ cdef CMR_SEYMOUR_NODE_TYPE typ = CMRseymourType(dec) if typ == CMR_SEYMOUR_NODE_TYPE_ONE_SUM: From c5e0b5cedb1d0d9e47539ed64f261925624795df Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 17 Sep 2024 11:50:12 -0700 Subject: [PATCH 239/262] a failed example for three sum mixed mixed --- src/sage/matrix/matrix_cmr_sparse.pyx | 21 +++++- src/sage/matrix/seymour_decomposition.pyx | 86 ++++++++++++++++++++++- 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index cbd4d7cdf85..9cb19307aee 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -826,7 +826,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): and the second matrix is `M_2=\begin{bmatrix} b_1 & b_2 & B\end{bmatrix}`. Then the Truemper 3-sum is the matrix - `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ C & B\end{bmatrix}`, + where `\begin{bmatrix}a_1^T \\ a_2^T\end{bmatrix}=\begin{bmatrix} C_1 & \bar{C}\end{bmatrix}`, + `\begin{bmatrix}b_1 & b_2\end{bmatrix}=\begin{bmatrix} \bar{C}\\ C_2\end{bmatrix}`, + `C_12 = C_2 \bar{C}^{-1} C_1`, + `C=\begin{bmatrix} C_1 & \bar{C} \\ C_{12} & C_2\end{bmatrix}`, i.e., + `C=\begin{bmatrix}b_1 & b_2\end{bmatrix}\bar{C}^{-1}\begin{bmatrix}a_1^T\\ a_2^T\end{bmatrix}` The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. @@ -1176,7 +1181,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): and the second matrix is `M_2=\begin{bmatrix} 1 & 1 & 0\\ b_1 & b_2 & B\end{bmatrix}`. Then the Truemper 3-sum is the matrix - `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ C & B\end{bmatrix}`, + where `\begin{bmatrix}a_1^T \\ a_2^T\end{bmatrix}=\begin{bmatrix} C_1 & \bar{C}\end{bmatrix}`, + `\begin{bmatrix}b_1 & b_2\end{bmatrix}=\begin{bmatrix} \bar{C}\\ C_2\end{bmatrix}`, + `C_12 = C_2 \bar{C}^{-1} C_1`, + `C=\begin{bmatrix} C_1 & \bar{C} \\ C_{12} & C_2\end{bmatrix}`, i.e., + `C=\begin{bmatrix}b_1 & b_2\end{bmatrix}\bar{C}^{-1}\begin{bmatrix}a_1^T\\ a_2^T\end{bmatrix}` The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. @@ -1860,7 +1870,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): `M_2=\begin{bmatrix} \epsilon_1 & 1 & 0\\ b_1 & b_2 & B\end{bmatrix}`, where `\epsilon_1`, `\epsilon_2` are `1` or `-1`. Then the Truemper 3-sum is the matrix - `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ b_1 a_1^T + b_2 a_2^T & B\end{bmatrix}`. + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ C & B\end{bmatrix}`, + where `\begin{bmatrix}a_1^T \\ a_2^T\end{bmatrix}=\begin{bmatrix} C_1 & \bar{C}\end{bmatrix}`, + `\begin{bmatrix}b_1 & b_2\end{bmatrix}=\begin{bmatrix} \bar{C}\\ C_2\end{bmatrix}`, + `C_12 = C_2 \bar{C}^{-1} C_1`, + `C=\begin{bmatrix} C_1 & \bar{C} \\ C_{12} & C_2\end{bmatrix}`, i.e., + `C=\begin{bmatrix}b_1 & b_2\end{bmatrix}\bar{C}^{-1}\begin{bmatrix}a_1^T\\ a_2^T\end{bmatrix}` The terminology "3-sum" is used in the context of Seymour's decomposition of totally unimodular matrices and regular matroids, see [Sch1986]_, Ch. 19.4. diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index ce8f44ad00f..bba7d0c86b8 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -2298,6 +2298,52 @@ cdef class ThreeSumNode(SumNode): return CMRseymourThreeSumDistributedRanks(self._dec) def is_concentrated_rank(self): + r""" + Check whether the three sum node ``self`` is formed with + ``three_sum_strategy="concentrated_rank"`` or ``"Mixed_Mixed"``. + + The matrix representing the first child is + `M_1=\begin{bmatrix} A & 0 \\ a_1^T & 1\\ a_2^T & \epsilon_2\end{bmatrix}` + and the matrix representing the second child is + `M_2=\begin{bmatrix} \epsilon_1 & 1 & 0\\ b_1 & b_2 & B\end{bmatrix}`, + where `\epsilon_1`, `\epsilon_2` are `1` or `-1`. + And the matrix representing ``self`` is a permutation of + `M_1 \oplus_3 M_2 = \begin{bmatrix} A & 0 \\ C & B\end{bmatrix}`, + where `\begin{bmatrix}a_1^T \\ a_2^T\end{bmatrix}=\begin{bmatrix} C_1 & \bar{C}\end{bmatrix}`, + `\begin{bmatrix}b_1 & b_2\end{bmatrix}=\begin{bmatrix} \bar{C}\\ C_2\end{bmatrix}`, + `C_12 = C_2 \bar{C}^{-1} C_1`, + `C=\begin{bmatrix} C_1 & \bar{C} \\ C_{12} & C_2\end{bmatrix}`, i.e., + `C=\begin{bmatrix}b_1 & b_2\end{bmatrix}\bar{C}^{-1}\begin{bmatrix}a_1^T\\ a_2^T\end{bmatrix}` + + ``concentrated_rank`` is named after the rank 2 off-diagonal block. + ``Mixed_Mixed`` is named after the structure of the two children. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.three_sum_mixed_mixed` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), + ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + sage: result, certificate = R12_large.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Mixed_Mixed") + sage: C = certificate; C + ThreeSumNode (9×12) with 2 children + sage: C.is_distributed_ranks() + False + sage: C.is_concentrated_rank() + True + """ return CMRseymourThreeSumConcentratedRank(self._dec) def block_matrix_form(self): @@ -2341,11 +2387,45 @@ cdef class ThreeSumNode(SumNode): [ 0 0 0 1 0 1] [ 1 0 1 0 1 1] [ 1 0 1 0 0 1] + + sage: result, certificate = R12.is_totally_unimodular(certificate=True, + ....: three_sum_strategy="Mixed_Mixed") + sage: C = certificate; C + ThreeSumNode (6×6) with 2 children + sage: C.matrix() + [ 1 0 1 1 0 0] + [ 0 1 1 1 0 0] + [ 1 0 1 0 1 1] + [ 0 -1 0 -1 1 1] + [ 1 0 1 0 1 0] + [ 0 -1 0 -1 0 1] + sage: C.summand_matrices() + ( + [ 1 1 0 0] + [ 1 0 1 1 0] [ 1 0 1 1] + [ 0 1 1 1 0] [ 0 -1 1 1] + [ 1 0 1 0 1] [ 1 0 1 0] + [ 0 -1 0 -1 1], [ 0 -1 0 1] + ) + sage: C.child_indices() + (((r0, r1, r2, r3), (c0, c1, c2, c3, +r2+r3)), + ((+c0+c3, r2, r3, r4, r5), (c0, c3, c4, c5))) + sage: C.block_matrix_form() + [ 1 0 1 1 0 0] + [ 0 1 1 1 0 0] + [ 1 0 1 0 1 1] + [ 0 -1 0 -1 1 1] + [ 1 0 1 0 1 0] + [ 0 -1 0 -1 0 1] """ M1, M2 = self.summand_matrices() - x = M1.ncols() - # return Matrix_cmr_chr_sparse.three_sum(M1, M2, x - 2, x - 1, 0, 1) - return Matrix_cmr_chr_sparse.three_sum_wide_wide(M1, M2) + if self.is_distributed_ranks(): + three_sum_strategy = 'distributed_ranks' + else: + three_sum_strategy = 'concentrated_rank' + return Matrix_cmr_chr_sparse.three_sum(M1, M2, + three_sum_strategy=three_sum_strategy, + sign_verify=True) cdef class BaseGraphicNode(DecompositionNode): From abcbaba4300134968e8f997a970c72e29b3cdd24 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 17 Sep 2024 12:01:29 -0700 Subject: [PATCH 240/262] build/pkgs/cmr: Update to d6ff9e5d6666b2dc32e2f95b705b4d7b96a265f9 --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index c99d57c96ee..d12cacf04b5 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=94cbb90279f2387a0ae870fa9d51110f6eb289f7 -sha256=cb7db56a86002beacef74de7cfa00617428a0b3ba6247663d7db6305eca45ab0 +sha1=18afa0c161f93394edd78689bce68c88c2c48cab +sha256=1db01188152758efeea61635524391501cfb2d02824a29e579137bc43637f3a4 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index cda6414a01f..75b72448db6 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -66b5141ea955c5c43b8d82cf105554b627cd5424 +d6ff9e5d6666b2dc32e2f95b705b4d7b96a265f9 From 78c78c3aa747fb956f015501a0d4f322a6e17167 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 17 Sep 2024 18:01:24 -0700 Subject: [PATCH 241/262] WIP: add doctests for seymour_decomposition: complete decomposition and graphicness --- src/sage/matrix/matrix_cmr_sparse.pyx | 47 ++- src/sage/matrix/seymour_decomposition.pyx | 340 ++++++++++++++++++++-- 2 files changed, 362 insertions(+), 25 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 9cb19307aee..b76077776ec 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -2951,6 +2951,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_keys=None, column_keys=None): r""" Return whether the linear matroid of ``self`` over `\GF{2}` is graphic. + If there is some entry not in `\{0, 1\}`, return ``False``. This is an internal method because it should really be exposed as a method of :class:`Matroid`. @@ -2971,6 +2972,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [-1 1] [ 0 -1] sage: M._is_binary_linear_matroid_graphic() + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [1, 1], [0, 1]]); M + [1 0] + [1 1] + [0 1] + sage: M._is_binary_linear_matroid_graphic() True sage: result, certificate = M._is_binary_linear_matroid_graphic(certificate=True) sage: graph, forest_edges, coforest_edges = certificate @@ -3058,6 +3066,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_keys=None, column_keys=None): r""" Return whether the linear matroid of ``self`` over `\GF{2}` is cographic. + If there is some entry not in `\{0, 1\}`, return ``False``. This is an internal method because it should really be exposed as a method of :class:`Matroid`. @@ -3075,6 +3084,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 0 0 1 0 0 0 1 -1 1] [ 0 0 0 1 1 0 0 1 -1] sage: M._is_binary_linear_matroid_cographic() + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 4, 9, sparse=True), + ....: M); M + [1 0 0 0 1 1 1 0 0] + [0 1 0 0 0 1 1 1 0] + [0 0 1 0 0 0 1 1 1] + [0 0 0 1 1 0 0 1 1] + sage: M._is_binary_linear_matroid_cographic() True sage: C3 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 3, sparse=True), ....: [[1, 1, 0], @@ -3133,6 +3150,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): row_keys=None, column_keys=None): r""" Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. Let `D = (V,A)` be a digraph and let `T` be an (arbitrarily) directed spanning forest of the underlying undirected graph. @@ -3159,6 +3177,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [2, 1], [0, -1]]); M + [ 1 0] + [ 2 1] + [ 0 -1] + sage: M.is_network_matrix() + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), ....: [[1, 0], [-1, 1], [0, -1]]); M [ 1 0] [-1 1] @@ -3260,7 +3285,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_conetwork_matrix(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a conetwork matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. + + A matrix is conetwork if and only if its transpose is network. .. SEEALSO:: :meth:`is_network_matrix`, @@ -3356,6 +3384,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): column_keys=None): r""" Return whether the linear matroid of ``self`` over `\GF{2}` is regular. + If there is some entry not in `\{0, 1\}`, return ``False``. This is an internal method because it should really be exposed as a method of :class:`Matroid`. @@ -3387,7 +3416,14 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), - ....: [[1, 0], [1, 1], [0, 1]]); M + ....: [[1, 0], [-1, 1], [0, -1]]); M + [ 1 0] + [-1 1] + [ 0 -1] + sage: M._is_binary_linear_matroid_regular() + False + sage: M = Matrix_cmr_chr_sparse(M.parent().change_ring(GF(2)), + ....: M); M [1 0] [1 1] [0 1] @@ -3580,6 +3616,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [2, 1], [0, 1]]); M + [1 0] + [2 1] + [0 1] + sage: M.is_totally_unimodular() + False + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), ....: [[1, 0], [-1, 1], [0, 1]]); M [ 1 0] [-1 1] diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index bba7d0c86b8..194d802140d 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -327,6 +327,10 @@ cdef class DecompositionNode(SageObject): """ if self._matrix is not None: return self._matrix + if self._dec is NULL: + if isinstance(self, SumNode): + return self.block_matrix_form() + raise ValueError('Matrix and decomposition are both missing') cdef Matrix_cmr_chr_sparse result cdef CMR_CHRMAT *mat = CMRseymourGetMatrix(self._dec) if mat == NULL: @@ -966,26 +970,108 @@ cdef class DecompositionNode(SageObject): return result def _regularity(self): - cdef int8_t regularity = CMRseymourRegularity(self._dec) - if regularity: - return regularity > 0 + r""" + Return whether the decomposition node is regular (binary) or TU (ternary). + If it is not determined, raise ValueError. + """ + cdef int8_t regularity + if self._dec != NULL: + regularity = CMRseymourRegularity(self._dec) + if regularity: + return regularity > 0 raise ValueError('It is not determined whether the decomposition node is regular/TU') def _graphicness(self): - cdef int8_t graphicness = CMRseymourGraphicness(self._dec) - if graphicness: - return graphicness > 0 + r""" + Return whether the decomposition node is graphic (binary) or network (ternary). + If it is not determined, raise ValueError. + """ + cdef int8_t graphicness + if self._dec != NULL: + graphicness = CMRseymourGraphicness(self._dec) + if graphicness: + return graphicness > 0 raise ValueError('It is not determined whether the decomposition node is graphic/network') def _cographicness(self): - cdef int8_t cographicness = CMRseymourCographicness(self._dec) - if cographicness: - return cographicness > 0 + r""" + Return whether the decomposition node is cographic (binary) or conetwork (ternary). + If it is not determined, raise ValueError. + """ + cdef int8_t cographicness + if self._dec != NULL: + cographicness = CMRseymourCographicness(self._dec) + if cographicness: + return cographicness > 0 raise ValueError('It is not determined whether the decomposition node is cographic/conetwork') def _is_binary_linear_matroid_graphic(self, *, decomposition=False, **kwds): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is graphic. + If there is some entry not in `\{0, 1\}`, return ``False``. + + This method is based on Seymour's decomposition. + The decomposition will stop once nongraphicness is detected. + For direct graphicness check, + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` + :meth:`UnknownNode._is_binary_linear_matroid_graphic` + :meth:`_binary_linear_matroid_complete_decomposition` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [1, 1], [0, 1]], + ....: [[1, 1, 0], [0, 1, 1]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(5), + ....: column_keys='abcde') + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: node._graphicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is graphic/network + sage: result, decomposition = node._is_binary_linear_matroid_graphic(decomposition=True) + sage: result + True + sage: unicode_art(decomposition) + ╭──────────OneSumNode (5×5) with 2 children + │ │ + PlanarNode (3×2) PlanarNode (2×3) + sage: decomposition._graphicness() + True + sage: node._is_binary_linear_matroid_graphic(certificate=True) + Traceback (most recent call last): + ... + NotImplementedError + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(9)], + ....: column_keys=[f'c{i}' for i in range(9)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node._is_binary_linear_matroid_graphic(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: decomposition.child_nodes()[1]._graphicness() + False """ certificate = kwds.get('certificate', False) try: @@ -1009,7 +1095,69 @@ cdef class DecompositionNode(SageObject): def _is_binary_linear_matroid_cographic(self, *, decomposition=False, **kwds): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is cographic. + If there is some entry not in `\{0, 1\}`, return ``False``. + + This method is based on Seymour's decomposition. + The decomposition will stop once noncographicness is detected. + For direct cographicness check, + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` + :meth:`UnknownNode._is_binary_linear_matroid_cographic` + :meth:`_binary_linear_matroid_complete_decomposition` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: M2 = Matrix_cmr_chr_sparse.one_sum([[1, 0], [1, 1], [0, 1]], + ....: [[1, 1, 0], [0, 1, 1]]) + sage: result, certificate = M2.is_totally_unimodular(certificate=True, + ....: row_keys=range(5), + ....: column_keys='abcde') + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: node._graphicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is graphic/network + sage: result, decomposition = node._is_binary_linear_matroid_cographic(decomposition=True) + sage: result + True + sage: unicode_art(decomposition) + ╭──────────OneSumNode (5×5) with 2 children + │ │ + PlanarNode (3×2) PlanarNode (2×3) + sage: decomposition._cographicness() + True + sage: node._is_binary_linear_matroid_cographic(certificate=True) + Traceback (most recent call last): + ... + NotImplementedError + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [1, 1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 1, 0, 0], + ....: [0, 0, 0, 0, 1, 1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0, 1, 1], + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(9)], + ....: column_keys=[f'c{i}' for i in range(9)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node._is_binary_linear_matroid_cographic(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) """ certificate = kwds.get('certificate', False) try: @@ -1033,6 +1181,15 @@ cdef class DecompositionNode(SageObject): def _is_binary_linear_matroid_regular(self, *, decomposition=False, **kwds): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is regular. + If there is some entry not in `\{0, 1\}`, return ``False``. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse._is_binary_linear_matroid_regular` + :meth:`_binary_linear_matroid_complete_decomposition` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1048,6 +1205,12 @@ cdef class DecompositionNode(SageObject): ....: [0, 0, 0, 0, 0, 0, 1, 1, 1]]) sage: from sage.matrix.seymour_decomposition import UnknownNode sage: node = UnknownNode(M) + sage: node._regularity() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is regular/TU + sage: node._is_binary_linear_matroid_regular() + True sage: C0 = node._binary_linear_matroid_complete_decomposition() sage: C0 OneSumNode (9×9) with 2 children @@ -1114,6 +1277,26 @@ cdef class DecompositionNode(SageObject): construct_leaf_graphs=False, construct_all_graphs=False): r""" + Complete the Seymour's decomposition of ``self`` over `\GF{2}`. + + INPUT: + + - ``stop_when_irregular`` -- boolean + Whether to stop decomposing once irregularity is determined. + + - ``stop_when_nongraphic`` -- boolean + Whether to stop decomposing once non-graphicness is determined. + + - ``stop_when_noncographic`` -- boolean + Whether to stop decomposing once non-cographicness is determined. + + - ``stop_when_nongraphic_and_noncographic`` -- boolean + Whether to stop decomposing once non-graphicness and non-cographicness + is determined. + + For a description of other parameters, see + :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1222,7 +1405,10 @@ cdef class DecompositionNode(SageObject): if self._dec == NULL: base_ring = self.base_ring() - if base_ring.characteristic() != 2: + if base_ring is None: + from sage.rings.finite_rings.finite_field_constructor import GF + self._base_ring = GF(2) + elif base_ring.characteristic() != 2: raise ValueError(f'only defined over binary, got {base_ring}') self._set_root_dec() @@ -1320,13 +1506,45 @@ cdef class DecompositionNode(SageObject): return CMRseymourNumMinors(self._dec) def _create_minor(self, index): + r""" + A minor of a represented matroid is another one obtained + by deleting or contracting elements. In the reduced matrix representation, + an element associated with a row (resp. column) can be contracted (resp. deleted) + by removing the corresponding matrix row (resp. column). + In order to delete a row element or contract a column element, + one must first pivot such that the element type (row/column) is changed. + + A minor of a matroid represented by matrix `M` is represented + by means of a ``CMR_MINOR`` object. + It consists of a (potentially empty) array of pivots and a ``CMR_SUBMAT`` object + indicating a submatrix `M'` of the matrix obtained from `M` after applying the pivots. + Moreover, the type field indicates a certain structure of `M'`: + + - A determinant ``CMR_MINOR_TYPE_DETERMINANT`` + indicates that `M'` is a submatrix of `M` with `|\det(M')| \geq 2`. + In particular, no pivots are applied. + - A Fano ``CMR_MINOR_TYPE_FANO`` + indicates that `M'` represents the Fano matroid `F_7`. + - A Fano-dual ``CMR_MINOR_TYPE_FANO_DUAL`` + indicates that `M'` represents the dual `F_7^\star` of the Fano matroid. + - A K5 ``CMR_MINOR_TYPE_K5`` + indicates that `M'` represents the graphic matroid `M(K_5)` of the complete graph `K_5`. + - A K5-dual ``CMR_MINOR_TYPE_K5_DUAL`` + indicates that `M'` represents the dual matroid `M(K_5)^\star` of the complete graph `K_5`. + - A K33 ``CMR_MINOR_TYPE_K33`` + indicates that `M'` represents the graphic matroid `M(K_{3,3})` + of the complete bipartite graph `K_{3,3}`. + - A K33-dual ``CMR_MINOR_TYPE_K33_DUAL`` + indicates that `M'` represents the dual matroid `M(K_{3,3})^\star` + of the complete bipartite graph `K_{3,3}`. + """ cdef CMR_MINOR * minor = CMRseymourMinor(self._dec, index) cdef CMR_MINOR_TYPE typ = CMRminorType(minor) cdef size_t npivots = CMRminorNumPivots(minor) cdef size_t *pivot_rows = CMRminorPivotRows(minor) cdef size_t *pivot_columns = CMRminorPivotColumns(minor) cdef CMR_SUBMAT *submat = CMRminorSubmatrix(minor) - + # TODO: consider the pivots information and the corresponding keys? pivots_tuple = tuple((pivot_rows[i], pivot_columns[i]) for i in range(npivots)) submat_tuple = (tuple(submat.rows[i] for i in range(submat.numRows)), tuple(submat.columns[i] for i in range(submat.numColumns))) @@ -1357,6 +1575,10 @@ cdef class DecompositionNode(SageObject): def minors(self): r""" + Return a tuple of minors of ``self``. + + Currently, it only handles determinant 2 submatrix. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1399,6 +1621,26 @@ cdef class DecompositionNode(SageObject): construct_leaf_graphs=False, construct_all_graphs=False): r""" + Complete the Seymour's decomposition of ``self`` over `\GF{3}` or `\ZZ`. + + INPUT: + + - ``stop_when_nonTU`` -- boolean + Whether to stop decomposing once being non-TU is determined. + + - ``stop_when_nonnetwork`` -- boolean + Whether to stop decomposing once being non-network is determined. + + - ``stop_when_nonconetwork`` -- boolean + Whether to stop decomposing once being non-conetwork is determined. + + - ``stop_when_nonnetwork_and_nonconetwork`` -- boolean + Whether to stop decomposing once not being network + and not being conetwork is determined. + + For a description of other parameters, see + :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters` + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse @@ -1539,15 +1781,26 @@ cdef class UnknownNode(DecompositionNode): def _is_binary_linear_matroid_graphic(self, *, decomposition=False, certificate=False, **kwds): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is graphic. + If there is some entry not in `\{0, 1\}`, return ``False``. + + This is an internal method because it should really be exposed + as a method of :class:`Matroid`. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` + EXAMPLES:: sage: from sage.matrix.seymour_decomposition import UnknownNode - sage: node = UnknownNode([[1, 0], [-1, 1], [0, -1]]); node + sage: node = UnknownNode([[1, 0], [1, 1], [0, 1]]); node UnknownNode (3×2) sage: node.matrix() - [ 1 0] - [-1 1] - [ 0 -1] + [1 0] + [1 1] + [0 1] sage: node._is_binary_linear_matroid_graphic() True sage: result, certificate = node._is_binary_linear_matroid_graphic(certificate=True) @@ -1578,14 +1831,25 @@ cdef class UnknownNode(DecompositionNode): def _is_binary_linear_matroid_cographic(self, *, decomposition=False, certificate=False, **kwds): r""" + Return whether the linear matroid of ``self`` over `\GF{2}` is cographic. + If there is some entry not in `\{0, 1\}`, return ``False``. + + This is an internal method because it should really be exposed + as a method of :class:`Matroid`. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` + EXAMPLES:: sage: from sage.matrix.seymour_decomposition import UnknownNode - sage: node = UnknownNode([[1, -1, 0], [0, 1, -1]]); node + sage: node = UnknownNode([[1, 1, 0], [0, 1, 1]]); node UnknownNode (2×3) sage: node.matrix() - [ 1 -1 0] - [ 0 1 -1] + [1 1 0] + [0 1 1] sage: node._is_binary_linear_matroid_cographic() True sage: result, certificate = node._is_binary_linear_matroid_cographic(certificate=True) @@ -1616,6 +1880,14 @@ cdef class UnknownNode(DecompositionNode): def is_network_matrix(self, *, decomposition=False, certificate=False, **kwds): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse.is_network_matrix` + EXAMPLES:: sage: from sage.matrix.seymour_decomposition import UnknownNode @@ -1657,6 +1929,14 @@ cdef class UnknownNode(DecompositionNode): def is_conetwork_matrix(self, *, decomposition=False, certificate=False, **kwds): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a conetwork matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse.is_conetwork_matrix` + EXAMPLES:: sage: from sage.matrix.seymour_decomposition import UnknownNode @@ -2483,16 +2763,16 @@ cdef class BaseGraphicNode(DecompositionNode): Starting with a morphism:: sage: from sage.matrix.seymour_decomposition import UnknownNode - sage: phi = matrix(ZZ, [[1, 0], [-1, 1], [0, 1]], + sage: phi = matrix(ZZ, [[1, 0], [1, 1], [0, 1]], ....: row_keys=['a', 'b', 'c'], column_keys=['v', 'w']) sage: phi; phi._unicode_art_matrix() Generic morphism: From: Free module generated by {'v', 'w'} over Integer Ring To: Free module generated by {'a', 'b', 'c'} over Integer Ring - v w - a⎛ 1 0⎞ - b⎜-1 1⎟ - c⎝ 0 1⎠ + v w + a⎛1 0⎞ + b⎜1 1⎟ + c⎝0 1⎠ sage: phi_node = UnknownNode(phi) sage: is_graphic, rephined_node = phi_node._is_binary_linear_matroid_graphic(decomposition=True) sage: is_graphic, rephined_node @@ -2537,6 +2817,9 @@ cdef class CographicNode(BaseGraphicNode): cdef class PlanarNode(BaseGraphicNode): @cached_method def cograph(self): + r""" + Return the cograph of matrix. + """ return _sage_graph(CMRseymourCograph(self._dec)) @@ -2544,6 +2827,17 @@ cdef class SeriesParallelReductionNode(DecompositionNode): def core(self): r""" + Return the core of ``self``. + + A :class:SeriesParallelReductionNode indicates that `M` + arises from a smaller matrix `M'` (called the core) + by successively adding zero rows/columns, + unit rows/columns or duplicates of existing rows/columns + (potentially scaled with `-1`). + + Note that such series-parallel reductions preserve total unimodularity + and binary regularity. + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse From 6b20a5d827560acd76b06c671369a5a54b61c6cb Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 17 Sep 2024 21:15:01 -0700 Subject: [PATCH 242/262] WIP: add doctests for seymour_decomposition: R10 --- src/sage/matrix/seymour_decomposition.pyx | 86 ++++++++++++++++++++--- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 194d802140d..31747c2b01b 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -2864,6 +2864,78 @@ cdef class SeriesParallelReductionNode(DecompositionNode): cdef class R10Node(DecompositionNode): + r""" + Special R10 Node. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1], + ....: [0, 1, 1, 0, 1], + ....: [0, 0, 1, 1, 1], + ....: [1, 1, 1, 1, 1]]); R10 + [1 0 0 1 1] + [1 1 0 0 1] + [0 1 1 0 1] + [0 0 1 1 1] + [1 1 1 1 1] + sage: result, certificate = R10.is_totally_unimodular(certificate=True) + sage: result + True + sage: R10.is_network_matrix() + False + sage: R10.is_conetwork_matrix() + False + sage: result, certificate = R10._is_binary_linear_matroid_regular(certificate=True) + sage: result + True + sage: certificate._is_binary_linear_matroid_graphic() + False + sage: certificate._is_binary_linear_matroid_cographic() + False + + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 0, 0, 1], + ....: [1, 1,-1, 0, 0], + ....: [0, 1,-1,-1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); R10 + [ 1 1 0 0 1] + [ 1 1 -1 0 0] + [ 0 1 -1 -1 0] + [ 0 0 1 1 1] + [ 1 0 0 1 1] + sage: result, certificate = R10.is_totally_unimodular(certificate=True) + sage: result + True + sage: R10.is_network_matrix() + False + sage: R10.is_conetwork_matrix() + False + + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 5, 5, sparse=True), + ....: [[1, 1, 0, 0, 1], + ....: [1, 1,-1, 0, 0], + ....: [0, 1,-1,-1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); R10 + [1 1 0 0 1] + [1 1 1 0 0] + [0 1 1 1 0] + [0 0 1 1 1] + [1 0 0 1 1] + sage: result, certificate = R10._is_binary_linear_matroid_regular(certificate=True) + sage: result + True + sage: certificate + R10Node (5×5) isomorphic to a minor of R10: Regular matroid of rank 5 on 10 elements with 162 bases + sage: certificate._is_binary_linear_matroid_graphic() + False + sage: certificate._is_binary_linear_matroid_cographic() + False + """ @cached_method def _matroid(self): @@ -2878,17 +2950,9 @@ cdef class R10Node(DecompositionNode): assert False, 'special leaf node with unknown type' def _repr_(self): - return f'Isomorphic to a minor of {self._matroid()}' - - def rep_matrix(self): - r""" - WIP - """ - assert NotImplementedError - - # cdef int representation_matrix - # cdef CMR_SEYMOUR_NODE_TYPE typ = CMRdecIsSpecialLeaf(self._dec, &representation_matrix) - # return Matrix_cmr_chr_sparse._from_data(representation_matrix, immutable=False) + result = super()._repr_() + result += f' isomorphic to a minor of {self._matroid()}' + return result cdef class PivotsNode(DecompositionNode): From b5157c57605172883df1e1c746436d9360b8934b Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 18 Sep 2024 09:34:58 -0700 Subject: [PATCH 243/262] build/pkgs/cmr: Update to e405fce633c4119a53249a5d0cade8a41fba081e --- build/pkgs/cmr/checksums.ini | 4 ++-- build/pkgs/cmr/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cmr/checksums.ini b/build/pkgs/cmr/checksums.ini index d12cacf04b5..9daba5c59cf 100644 --- a/build/pkgs/cmr/checksums.ini +++ b/build/pkgs/cmr/checksums.ini @@ -1,4 +1,4 @@ tarball=cmr-0+VERSION.tar.gz -sha1=18afa0c161f93394edd78689bce68c88c2c48cab -sha256=1db01188152758efeea61635524391501cfb2d02824a29e579137bc43637f3a4 +sha1=05a74a210ff6ed105595c6ccd4b70ce232dc5674 +sha256=3c4d7bfd4391a2e50491b1d259465892d4a040e3355a256b85090af6787272e4 upstream_url=https://github.com/discopt/cmr/archive/VERSION.tar.gz diff --git a/build/pkgs/cmr/package-version.txt b/build/pkgs/cmr/package-version.txt index 75b72448db6..bcda2cd4917 100644 --- a/build/pkgs/cmr/package-version.txt +++ b/build/pkgs/cmr/package-version.txt @@ -1 +1 @@ -d6ff9e5d6666b2dc32e2f95b705b4d7b96a265f9 +e405fce633c4119a53249a5d0cade8a41fba081e From 6c51f2119f4380bc4ab4d5025008e3eb70365a96 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 19 Sep 2024 13:43:27 -0700 Subject: [PATCH 244/262] add matroid and isomorphism to R10 --- src/sage/matrix/matrix_cmr_sparse.pyx | 2 +- src/sage/matrix/seymour_decomposition.pyx | 125 ++++++++++++++++++++-- 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index b76077776ec..88e224b8c68 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -812,7 +812,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): `M_1=\begin{bmatrix} A & a_2 \\ a_1^T & *\end{bmatrix}` and the second matrix is `M_2=\begin{bmatrix} * & b_2^T\\ b_1 & B\end{bmatrix}`, - where the entry `*` is not relavant in the construction. + where the entry `*` is not relevant in the construction. Then the Seymour/Schrijver 3-sum is the matrix `M_1 \oplus_3 M_2 = \begin{bmatrix} A & a_2 b_2^T \\ b_1 a_1^T & B\end{bmatrix}`. diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 31747c2b01b..c6836d3276f 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -2866,6 +2866,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): cdef class R10Node(DecompositionNode): r""" Special R10 Node. + Only two possible 5 by 5 matrices up to row and column permutations and negations. EXAMPLES:: @@ -2896,6 +2897,25 @@ cdef class R10Node(DecompositionNode): sage: certificate._is_binary_linear_matroid_cographic() False + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[ 1,-1, 0, 0,-1], + ....: [-1, 1,-1, 0, 0], + ....: [ 0,-1, 1,-1, 0], + ....: [ 0, 0,-1, 1,-1], + ....: [-1, 0, 0,-1, 1]]); R10 + [ 1 -1 0 0 -1] + [-1 1 -1 0 0] + [ 0 -1 1 -1 0] + [ 0 0 -1 1 -1] + [-1 0 0 -1 1] + sage: result, certificate = R10.is_totally_unimodular(certificate=True) + sage: result + True + sage: R10.is_network_matrix() + False + sage: R10.is_conetwork_matrix() + False + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), ....: [[1, 1, 0, 0, 1], ....: [1, 1,-1, 0, 0], @@ -2930,7 +2950,7 @@ cdef class R10Node(DecompositionNode): sage: result True sage: certificate - R10Node (5×5) isomorphic to a minor of R10: Regular matroid of rank 5 on 10 elements with 162 bases + R10Node (5×5) a reduced matrix representation of R10 matroid sage: certificate._is_binary_linear_matroid_graphic() False sage: certificate._is_binary_linear_matroid_cographic() @@ -2940,18 +2960,109 @@ cdef class R10Node(DecompositionNode): @cached_method def _matroid(self): r""" + Return the R10 matroid represented by ``self``. + ``self.matrix()`` is the reduced matrix representation of the matroid. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[1, 1, 1, 1, 1], + ....: [1, 1, 1, 0, 0], + ....: [1, 0, 1, 1, 0], + ....: [1, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1]]); R10 + [1 1 1 1 1] + [1 1 1 0 0] + [1 0 1 1 0] + [1 0 0 1 1] + [1 1 0 0 1] + sage: result, certificate = R10.is_totally_unimodular(certificate=True, + ....: row_keys=range(5), + ....: column_keys='abcde') + sage: certificate._matroid() + R10: Regular matroid of rank 5 on 10 elements with 162 bases + sage: certificate._isomorphism() + {'a': 0, + 'b': 1, + 'c': 2, + 'd': 'a', + 'e': 'b', + 'f': 4, + 'g': 'c', + 'h': 'e', + 'i': 3, + 'j': 'd'} + sage: result, certificate = R10.is_totally_unimodular(certificate=True) + sage: certificate._matroid() + R10: Regular matroid of rank 5 on 10 elements with 162 bases + sage: certificate._isomorphism() + {'a': 0, + 'b': 1, + 'c': 2, + 'd': 5, + 'e': 6, + 'f': 4, + 'g': 7, + 'h': 9, + 'i': 3, + 'j': 8} + + sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), + ....: [[ 1,-1, 0, 0,-1], + ....: [-1, 1,-1, 0, 0], + ....: [ 0,-1, 1,-1, 0], + ....: [ 0, 0,-1, 1,-1], + ....: [-1, 0, 0,-1, 1]]); R10 + [ 1 -1 0 0 -1] + [-1 1 -1 0 0] + [ 0 -1 1 -1 0] + [ 0 0 -1 1 -1] + [-1 0 0 -1 1] + sage: result, certificate = R10.is_totally_unimodular(certificate=True, + ....: row_keys=range(5), + ....: column_keys='abcde') + sage: certificate._matroid() + R10: Regular matroid of rank 5 on 10 elements with 162 bases + sage: certificate._isomorphism() # The isomorphism is not unique + {'a': 0, + 'b': 1, + 'c': 2, + 'd': 'c', + 'e': 'a', + 'f': 4, + 'g': 'b', + 'h': 3, + 'i': 'e', + 'j': 'd'} + """ + from sage.matroids.constructor import Matroid + if self.row_keys() is None or self.column_keys() is None: + M = Matroid(reduced_matrix=self.matrix(), regular=True) + else: + M = Matroid(reduced_morphism=self.morphism(), regular=True) + M.rename("R10: " + repr(M)) + return M + def _isomorphism(self): + r""" + Return one isomorphism between the R10 matroid + and ``self._matroid()``. """ - cdef CMR_SEYMOUR_NODE_TYPE typ = CMRseymourType(self._dec) import sage.matroids.matroids_catalog as matroids - - if typ == CMR_SEYMOUR_NODE_TYPE_R10: - return matroids.catalog.R10() - assert False, 'special leaf node with unknown type' + M0 = matroids.catalog.R10() + result, isomorphism = M0.is_isomorphic(self._matroid(), certificate=True) + if result is False: + raise ValueError("This is not a R10 node") + else: + return isomorphism def _repr_(self): + r""" + Return a string representation of ``self``. + """ result = super()._repr_() - result += f' isomorphic to a minor of {self._matroid()}' + result += f' a reduced matrix representation of R10 matroid' return result From f97885902fb6411df53690b39acbdcba251604f9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Thu, 19 Sep 2024 17:06:54 -0700 Subject: [PATCH 245/262] add doctests for BaseGraphicNode and include digraph case --- src/sage/matrix/matrix_cmr_sparse.pyx | 20 +- src/sage/matrix/seymour_decomposition.pxd | 4 +- src/sage/matrix/seymour_decomposition.pyx | 607 +++++++++++++++++++++- 3 files changed, 600 insertions(+), 31 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 88e224b8c68..74815f5a750 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -2956,6 +2956,22 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): This is an internal method because it should really be exposed as a method of :class:`Matroid`. + Equivalently, we also define the graphic matrix as follows. + + Let `G = (V,E)` be a graph and let `T` be a spanning forest. + The matrix `M(G,T) \in \{0,1\}^{T \times (E \setminus T)}` defined via + ` + M(D,T)_{e, f} := \begin{cases} + 1 & \text{if $e$ is contained in the unique cycle of $T\cup\{f\}$}, \\ + 0 & \text{otherwise} + \end{cases} + ` + is called the graphic matrix of `G` with respect to `T`. + A binary matrix `M` is called graphic if there exists a graph `G` + with a spanning forest `T` such that `M = M(G,T)`. + Moreover, `M` is called cographic if `M^T` is graphic, and + it is called planar if it is graphic and cographic. + .. SEEALSO:: :meth:`M._is_graphic_cmr() result_bool if not certificate: return result - node = create_DecompositionNode(dec, self, row_keys, column_keys) + node = create_DecompositionNode(dec, self, row_keys, column_keys, base_ring=GF2) if result: return result, node @@ -3771,7 +3787,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): result = result_bool if not certificate: return result - node = create_DecompositionNode(dec, self, row_keys, column_keys) + node = create_DecompositionNode(dec, self, row_keys, column_keys, base_ring=ZZ) if result: return result, node diff --git a/src/sage/matrix/seymour_decomposition.pxd b/src/sage/matrix/seymour_decomposition.pxd index b314f25827e..6d4018628e8 100644 --- a/src/sage/matrix/seymour_decomposition.pxd +++ b/src/sage/matrix/seymour_decomposition.pxd @@ -35,7 +35,9 @@ cdef class CographicNode(BaseGraphicNode): cdef class PlanarNode(BaseGraphicNode): - pass + cdef object _cograph + cdef object _cograph_forest_edges + cdef object _cograph_coforest_edges cdef class SymbolicNode(DecompositionNode): diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index c6836d3276f..5a16ae4a8c7 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -27,6 +27,7 @@ from sage.structure.sage_object cimport SageObject from .constructor import Matrix from .matrix_cmr_sparse cimport Matrix_cmr_chr_sparse, _sage_edges, _sage_graph, _set_cmr_seymour_parameters +from .matrix_cmr_sparse cimport _sage_arcs, _sage_digraph from .matrix_space import MatrixSpace @@ -1119,10 +1120,10 @@ cdef class DecompositionNode(SageObject): ....: row_keys=range(5), ....: column_keys='abcde') sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) - sage: node._graphicness() + sage: node._cographicness() Traceback (most recent call last): ... - ValueError: It is not determined whether the decomposition node is graphic/network + ValueError: It is not determined whether the decomposition node is cographic/conetwork sage: result, decomposition = node._is_binary_linear_matroid_cographic(decomposition=True) sage: result True @@ -1440,7 +1441,71 @@ cdef class DecompositionNode(SageObject): def is_network_matrix(self, *, decomposition=False, **kwds): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. + + This method is based on Seymour's decomposition. + The decomposition will stop once being nonnetwork is detected. + For direct network matrix check, + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse.is_network_matrix` + :meth:`UnknownNode.is_network_matrix` + :meth:`complete_decomposition` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: A = matrix(ZZ, [[-1, 0, 0, 0, 1,-1, 0], + ....: [ 1, 0, 0, 1,-1, 1, 0], + ....: [ 0,-1, 0,-1, 1,-1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1,-1, 1, 0, 1], + ....: [ 0, 0,-1, 1,-1, 0, 0]]) + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 7, sparse=True), A) + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 7, 6, sparse=True), A.transpose()) + sage: M = Matrix_cmr_chr_sparse.one_sum(M1, M2) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(13)], + ....: column_keys=[f'c{i}' for i in range(13)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + + sage: result, decomposition = node.is_network_matrix(decomposition=True) + sage: unicode_art(decomposition) + ╭─────────OneSumNode (13×13) with 2 children + │ │ + PlanarNode (6×7) PlanarNode (7×6) + sage: node._graphicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is graphic/network + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [-1,-1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1,-1,-1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 1, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0,-1, 1], + ....: [0, 0, 0, 0, 0, 0, 1,-1, 1]]) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(9)], + ....: column_keys=[f'c{i}' for i in range(9)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node.is_network_matrix(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: decomposition.child_nodes()[1]._graphicness() + False """ certificate = kwds.get('certificate', False) try: @@ -1455,11 +1520,82 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("Network Not Determined") + full_dec = self.complete_decomposition( + stop_when_nonnetwork=True, + check_graphic_minors_planar=True) + return full_dec.is_network_matrix( + decomposition=decomposition, + certificate=certificate) def is_conetwork_matrix(self, *, decomposition=False, **kwds): r""" + Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a conetwork matrix. + If there is some entry not in `\{-1, 0, 1\}`, return ``False``. + + This method is based on Seymour's decomposition. + The decomposition will stop once being nonconetwork is detected. + For direct conetwork matrix check, + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse.is_conetwork_matrix` + :meth:`UnknownNode.is_conetwork_matrix` + :meth:`complete_decomposition` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: A = matrix(ZZ, [[-1, 0, 0, 0, 1,-1, 0], + ....: [ 1, 0, 0, 1,-1, 1, 0], + ....: [ 0,-1, 0,-1, 1,-1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1,-1, 1, 0, 1], + ....: [ 0, 0,-1, 1,-1, 0, 0]]) + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 7, sparse=True), A) + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 7, 6, sparse=True), A.transpose()) + sage: M = Matrix_cmr_chr_sparse.one_sum(M1, M2) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(13)], + ....: column_keys=[f'c{i}' for i in range(13)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + + sage: result, decomposition = node.is_conetwork_matrix(decomposition=True) + sage: unicode_art(decomposition) + ╭─────────OneSumNode (13×13) with 2 children + │ │ + PlanarNode (6×7) PlanarNode (7×6) + sage: node._cographicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is cographic/conetwork + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [-1,-1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1,-1,-1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 1, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0,-1, 1], + ....: [0, 0, 0, 0, 0, 0, 1,-1, 1]]) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(9)], + ....: column_keys=[f'c{i}' for i in range(9)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node.is_conetwork_matrix(decomposition=True) + sage: result + False + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) UnknownNode (4×5) + sage: decomposition.child_nodes()[1]._graphicness() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is graphic/network """ certificate = kwds.get('certificate', False) try: @@ -1474,11 +1610,74 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("Conetwork Not Determined") + full_dec = self.complete_decomposition( + stop_when_nonconetwork=True, + check_graphic_minors_planar=True) + return full_dec.is_conetwork_matrix( + decomposition=decomposition, + certificate=certificate) def is_totally_unimodular(self, *, decomposition=False, **kwds): r""" + Return whether ``self`` is a totally unimodular matrix. + + A matrix is totally unimodular if every subdeterminant is `0`, `1`, or `-1`. + + .. SEEALSO:: + + :meth:`sage.matrix.matrix_cmr_sparse. + Matrix_cmr_chr_sparse.is_totally_unimodular` + :meth:`complete_decomposition` + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: from sage.matrix.seymour_decomposition import DecompositionNode + sage: A = matrix(ZZ, [[-1, 0, 0, 0, 1,-1, 0], + ....: [ 1, 0, 0, 1,-1, 1, 0], + ....: [ 0,-1, 0,-1, 1,-1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1,-1, 1, 0, 1], + ....: [ 0, 0,-1, 1,-1, 0, 0]]) + sage: M1 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 7, sparse=True), A) + sage: M2 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 7, 6, sparse=True), A.transpose()) + sage: M = Matrix_cmr_chr_sparse.one_sum(M1, M2) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(13)], + ....: column_keys=[f'c{i}' for i in range(13)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node.is_totally_unimodular(decomposition=True) + sage: unicode_art(decomposition) + ╭─────────OneSumNode (13×13) with 2 children + │ │ + PlanarNode (6×7) PlanarNode (7×6) + sage: node._regularity() + Traceback (most recent call last): + ... + ValueError: It is not determined whether the decomposition node is regular/TU + + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), + ....: [[1, 1, 0, 0, 0, 0, 0, 0, 0], + ....: [-1,-1, 1, 0, 0, 0, 0, 0, 0], + ....: [1, 0, 0, 1, 0, 0, 0, 0, 0], + ....: [0, 1,-1,-1, 0, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 0, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 1, 0, 0], + ....: [0, 0, 0, 0, 1,-1, 0, 1, 0], + ....: [0, 0, 0, 0, 0, 1, 0,-1, 1], + ....: [0, 0, 0, 0, 0, 0, 1,-1, 1]]) + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: row_keys=[f'r{i}' for i in range(9)], + ....: column_keys=[f'c{i}' for i in range(9)]) + sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) + sage: result, decomposition = node.is_totally_unimodular(decomposition=True) + sage: result + True + sage: unicode_art(decomposition) + ╭───────────OneSumNode (9×9) with 2 children + │ │ + GraphicNode (5×4) CographicNode (4×5) """ certificate = kwds.get('certificate', False) try: @@ -1493,7 +1692,12 @@ cdef class DecompositionNode(SageObject): return result except ValueError: # compute it... wait for CMR functions - raise NotImplementedError("TU Not Determined") + full_dec = self.complete_decomposition( + stop_when_nonTU=True, + check_graphic_minors_planar=True) + return full_dec.is_totally_unimodular( + decomposition=decomposition, + certificate=certificate) def nminors(self): r""" @@ -1701,6 +1905,8 @@ cdef class DecompositionNode(SageObject): cdef CMR_SEYMOUR_NODE **pclone = &clone if self._dec == NULL: + if self.base_ring() is None: + self._base_ring = ZZ self._set_root_dec() cdef dict kwds = dict(use_direct_graphicness_test=use_direct_graphicness_test, @@ -2713,6 +2919,32 @@ cdef class BaseGraphicNode(DecompositionNode): def __init__(self, matrix=None, graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None, base_ring=None): + r""" + Base class for :class:GraphicNode, :class:CographicNode, and :class:PlanarNode + + If ``base_ring`` is `\GF{2}`, then it represents a graphic/cographic/planar matroid. + + Suppose that ``self.matrix()`` is a graphic matrix of a graph `G` + with respect to `T`, a spanning forest of the graph `G`. + + - ``self._graph`` is the graph `G = (V,E)`. + + - ``self._forest_edges`` is the edges of `T`. + + - ``self._coforest_edges`` is the edges of `E \setminus T`. + + If ``base_ring`` is `\GF{3}` or `\ZZ`, then it represents a network/conetwork + or a both network and conetwork matrix. + + Suppose that ``self.matrix()`` is a network matrix of a digraph `D` + with respect to `T`, a directed spanning forest of the underlying undirected graph. + + - ``self._graph`` is the digraph `D = (V,A)`. + + - ``self._forest_edges`` is the arcs of `T`. + + - ``self._coforest_edges`` is the arcs of `A \setminus T`. + """ super().__init__(matrix=matrix, row_keys=row_keys, column_keys=column_keys, base_ring=base_ring) self._graph = graph @@ -2721,44 +2953,99 @@ cdef class BaseGraphicNode(DecompositionNode): def graph(self): r""" + Return the graph representing ``self``. + + If ``self.base_ring()`` is `\GF{2}`, then return an undirected graph. + If ``self.base_ring()`` is `\GF{3}` or `\ZZ`, then return directed graph. + EXAMPLES:: + Undirected graph: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), - ....: [[1, 0], [-1, 1], [0, 1]]); M + ....: [[1, 0], [1, 1], [0,1]]); M + [1 0] + [1 1] + [0 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: G = certificate.graph(); G + Graph on 4 vertices + sage: G.vertices(sort=True) + [1, 2, 7, 12] + sage: G.edges(sort=True) + [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] + + Directed graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0,-1]]); M [ 1 0] [-1 1] - [ 0 1] + [ 0 -1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate (True, GraphicNode (3×2)) sage: G = certificate.graph(); G - Graph on 4 vertices + Digraph on 4 vertices sage: G.vertices(sort=True) [1, 2, 7, 12] sage: G.edges(sort=True) - [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] + [(2, 1, None), (2, 7, None), (7, 1, None), (7, 12, None), (12, 1, None)] """ if self._graph is not None: return self._graph - self._graph = _sage_graph(CMRseymourGraph(self._dec)) + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._graph = _sage_graph(CMRseymourGraph(self._dec)) + else: + self._graph = _sage_digraph(CMRseymourGraph(self._dec), + CMRseymourGraphArcsReversed(self._dec)) return self._graph def forest_edges(self): r""" + Return the forest edges of ``self``. + + If ``self.base_ring()`` is `\GF{2}`, then return edges. + If ``self.base_ring()`` is `\GF{3}` or `\ZZ`, then arcs. + EXAMPLES:: + Undirected graph: + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), - ....: [[1, 0], [-1, 1], [0, 1]]); M + ....: [[1, 0], [1, 1], [0,1]]); M + [1 0] + [1 1] + [0 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True) + sage: result, certificate + (True, GraphicNode (3×2)) + sage: certificate.forest_edges() + ((1, 2), (7, 1), (12, 7)) + sage: certificate.coforest_edges() + ((2, 7), (1, 12)) + + Directed graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0,-1]]); M [ 1 0] [-1 1] - [ 0 1] + [ 0 -1] sage: result, certificate = M.is_totally_unimodular(certificate=True) sage: result, certificate (True, GraphicNode (3×2)) sage: certificate.forest_edges() - ((1, 2), (7, 1), (12, 7)) + ((2, 1), (7, 1), (7, 12)) + sage: certificate.coforest_edges() + ((2, 7), (12, 1)) Starting with a morphism:: @@ -2787,16 +3074,61 @@ cdef class BaseGraphicNode(DecompositionNode): cdef CMR_GRAPH *graph = CMRseymourGraph(self._dec) cdef size_t num_edges = CMRseymourGraphSizeForest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRseymourGraphForest(self._dec) - self._forest_edges = _sage_edges(graph, edges, num_edges, self.row_keys()) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._forest_edges = _sage_edges(graph, edges, num_edges, self.row_keys()) + else: + arcs_reversed = CMRseymourGraphArcsReversed(self._dec) + self._forest_edges = _sage_arcs(graph, edges, arcs_reversed, num_edges, self.row_keys()) return self._forest_edges def coforest_edges(self): + r""" + Return the forest edges of ``self``. + + If ``self.base_ring()`` is `\GF{2}`, then return edges. + If ``self.base_ring()`` is `\GF{3}` or `\ZZ`, then arcs. + + EXAMPLES:: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 7, sparse=True), + ....: [[-1, 0, 0, 0, 1, -1, 0], + ....: [ 1, 0, 0, 1, -1, 1, 0], + ....: [ 0, -1, 0, -1, 1, -1, 0], + ....: [ 0, 1, 0, 0, 0, 0, 1], + ....: [ 0, 0, 1, -1, 1, 0, 1], + ....: [ 0, 0, -1, 1, -1, 0, 0]]) + sage: M.is_network_matrix() + True + sage: result, certificate = M.is_network_matrix(certificate=True) + sage: result, certificate + (True, + (Digraph on 7 vertices, + ((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)), + ((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6)))) + sage: digraph, forest_arcs, coforest_arcs = certificate + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: certificate.graph() == digraph + True + sage: certificate.forest_edges() == forest_arcs + True + sage: certificate.coforest_edges() == coforest_arcs + True + """ if self._coforest_edges is not None: return self._coforest_edges cdef CMR_GRAPH *graph = CMRseymourGraph(self._dec) cdef size_t num_edges = CMRseymourGraphSizeCoforest(self._dec) cdef CMR_GRAPH_EDGE *edges = CMRseymourGraphCoforest(self._dec) - self._coforest_edges = _sage_edges(graph, edges, num_edges, self.column_keys()) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._coforest_edges = _sage_edges(graph, edges, num_edges, self.column_keys()) + else: + arcs_reversed = CMRseymourGraphArcsReversed(self._dec) + self._coforest_edges = _sage_arcs(graph, edges, arcs_reversed, num_edges, self.column_keys()) return self._coforest_edges @@ -2810,8 +3142,144 @@ cdef class CographicNode(BaseGraphicNode): def graph(self): r""" Actually the cograph of matrix, in the case where it is not graphic. + + EXAMPLES:: + + Undirected graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[1, 1, 1, 0, 0], + ....: [0, 1, 1, 1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); M + [1 1 1 0 0] + [0 1 1 1 0] + [0 0 1 1 1] + [1 0 0 1 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True) + sage: certificate + CographicNode (4×5) + sage: certificate.base_ring() + Finite Field of size 2 + sage: G = certificate.graph(); G + Graph on 6 vertices + sage: G.vertices(sort=True) + [0, 1, 2, 5, 7, 8] + sage: G.edges(sort=True) + [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] + + Directed graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[1, -1, 1, 0, 0], + ....: [0, 1, -1, 1, 0], + ....: [0, 0, 1, -1, 1], + ....: [1, 0, 0, 1, -1]]); M + [ 1 -1 1 0 0] + [ 0 1 -1 1 0] + [ 0 0 1 -1 1] + [ 1 0 0 1 -1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: certificate + CographicNode (4×5) + sage: G = certificate.graph(); G + Digraph on 6 vertices + sage: G.vertices(sort=True) + [0, 1, 2, 5, 7, 8] + sage: G.edges(sort=True) + [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] + """ + if self._graph is not None: + return self._graph + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._graph = _sage_graph(CMRseymourCograph(self._dec)) + else: + self._graph = _sage_digraph(CMRseymourCograph(self._dec), + CMRseymourCographArcsReversed(self._dec)) + return self._graph + + @cached_method + def forest_edges(self): + r""" + Return the forest edges of the cograph of ``self``. + + EXAMPLES:: + + Undirected graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[1, 1, 1, 0, 0], + ....: [0, 1, 1, 1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); M + [1 1 1 0 0] + [0 1 1 1 0] + [0 0 1 1 1] + [1 0 0 1 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True) + sage: result, certificate + (True, CographicNode (4×5)) + sage: certificate.forest_edges() + ((7, 8), (5, 0), (0, 7), (1, 7), (2, 1)) + sage: certificate.coforest_edges() + ((5, 8), (5, 1), (0, 2), (2, 8)) + + Directed graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), + ....: [[1, -1, 1, 0, 0], + ....: [0, 1, -1, 1, 0], + ....: [0, 0, 1, -1, 1], + ....: [1, 0, 0, 1, -1]]); M + [ 1 -1 1 0 0] + [ 0 1 -1 1 0] + [ 0 0 1 -1 1] + [ 1 0 0 1 -1] + sage: result, certificate = M.is_totally_unimodular(certificate=True) + sage: result, certificate + (True, CographicNode (4×5)) + sage: certificate.forest_edges() + ((7, 8), (0, 5), (0, 7), (1, 7), (1, 2)) + sage: certificate.coforest_edges() + ((5, 8), (1, 5), (0, 2), (2, 8)) + """ + if self._forest_edges is not None: + return self._forest_edges + cdef CMR_GRAPH *graph = CMRseymourCograph(self._dec) + cdef size_t num_edges = CMRseymourCographSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourCographForest(self._dec) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._forest_edges = _sage_edges(graph, edges, num_edges, self.row_keys()) + else: + arcs_reversed = CMRseymourCographArcsReversed(self._dec) + self._forest_edges = _sage_arcs(graph, edges, arcs_reversed, num_edges, self.row_keys()) + return self._forest_edges + + @cached_method + def coforest_edges(self): + r""" + Return the forest edges of the cograph of ``self``. """ - return _sage_graph(CMRseymourCograph(self._dec)) + if self._coforest_edges is not None: + return self._coforest_edges + cdef CMR_GRAPH *graph = CMRseymourCograph(self._dec) + cdef size_t num_edges = CMRseymourCographSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourCographCoforest(self._dec) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._coforest_edges = _sage_edges(graph, edges, num_edges, self.column_keys()) + else: + arcs_reversed = CMRseymourCographArcsReversed(self._dec) + self._coforest_edges = _sage_arcs(graph, edges, arcs_reversed, num_edges, self.column_keys()) + return self._coforest_edges cdef class PlanarNode(BaseGraphicNode): @@ -2819,8 +3287,102 @@ cdef class PlanarNode(BaseGraphicNode): def cograph(self): r""" Return the cograph of matrix. + + EXAMPLES:: + + Undirected graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [1, 1], [0,1]]); M + [1 0] + [1 1] + [0 1] + sage: result, certificate = M._is_binary_linear_matroid_regular(certificate=True, + ....: check_graphic_minors_planar=True) + sage: result, certificate + (True, PlanarNode (3×2)) + sage: G = certificate.cograph(); G + Graph on 3 vertices + sage: G.vertices(sort=True) + [1, 2, 7] + sage: G.edges(sort=True) + [(1, 2, None), (1, 7, None), (2, 7, None)] + sage: certificate.cograph_forest_edges() + ((1, 2), (7, 1)) + sage: certificate.cograph_coforest_edges() + ((1, 2), (2, 7), (7, 1)) + + Directed graph: + + sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), + ....: [[1, 0], [-1, 1], [0,-1]]); M + [ 1 0] + [-1 1] + [ 0 -1] + sage: result, certificate = M.is_totally_unimodular(certificate=True, + ....: check_graphic_minors_planar=True) + sage: result, certificate + (True, PlanarNode (3×2)) + sage: G = certificate.cograph(); G + Digraph on 3 vertices + sage: G.vertices(sort=True) + [1, 2, 7] + sage: G.edges(sort=True) + [(1, 2, None), (1, 7, None), (2, 7, None), (7, 1, None)] + sage: certificate.cograph_forest_edges() + ((1, 2), (1, 7)) + sage: certificate.cograph_coforest_edges() + ((1, 2), (2, 7), (7, 1)) + """ + if self._cograph is not None: + return self._cograph + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._cograph = _sage_graph(CMRseymourCograph(self._dec)) + else: + self._cograph = _sage_digraph(CMRseymourCograph(self._dec), + CMRseymourCographArcsReversed(self._dec)) + return self._cograph + + @cached_method + def cograph_forest_edges(self): + r""" + Return the forest edges of the cograph of ``self``. """ - return _sage_graph(CMRseymourCograph(self._dec)) + if self._cograph_forest_edges is not None: + return self._cograph_forest_edges + cdef CMR_GRAPH *cograph = CMRseymourCograph(self._dec) + cdef size_t num_edges = CMRseymourCographSizeForest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourCographForest(self._dec) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._cograph_forest_edges = _sage_edges(cograph, edges, num_edges, self.row_keys()) + else: + arcs_reversed = CMRseymourCographArcsReversed(self._dec) + self._cograph_forest_edges = _sage_arcs(cograph, edges, arcs_reversed, num_edges, self.row_keys()) + return self._cograph_forest_edges + + @cached_method + def cograph_coforest_edges(self): + r""" + Return the forest edges of the cograph of ``self``. + """ + if self._cograph_coforest_edges is not None: + return self._cograph_coforest_edges + cdef CMR_GRAPH *cograph = CMRseymourCograph(self._dec) + cdef size_t num_edges = CMRseymourCographSizeCoforest(self._dec) + cdef CMR_GRAPH_EDGE *edges = CMRseymourCographCoforest(self._dec) + cdef bool *arcs_reversed + base_ring = self.base_ring() + if base_ring.characteristic() == 2: + self._cograph_coforest_edges = _sage_edges(cograph, edges, num_edges, self.column_keys()) + else: + arcs_reversed = CMRseymourCographArcsReversed(self._dec) + self._cograph_coforest_edges = _sage_arcs(cograph, edges, arcs_reversed, num_edges, self.column_keys()) + return self._cograph_coforest_edges cdef class SeriesParallelReductionNode(DecompositionNode): @@ -3024,17 +3586,6 @@ cdef class R10Node(DecompositionNode): ....: column_keys='abcde') sage: certificate._matroid() R10: Regular matroid of rank 5 on 10 elements with 162 bases - sage: certificate._isomorphism() # The isomorphism is not unique - {'a': 0, - 'b': 1, - 'c': 2, - 'd': 'c', - 'e': 'a', - 'f': 4, - 'g': 'b', - 'h': 3, - 'i': 'e', - 'j': 'd'} """ from sage.matroids.constructor import Matroid if self.row_keys() is None or self.column_keys() is None: From e2f619250174fa69fbfa7be87c3100e01b8464e2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Oct 2024 16:50:36 -0700 Subject: [PATCH 246/262] build/pkgs/googletest: Update to 1.15.2 --- build/pkgs/googletest/checksums.ini | 5 ++--- build/pkgs/googletest/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/build/pkgs/googletest/checksums.ini b/build/pkgs/googletest/checksums.ini index 91398fb19fb..f1855410d55 100644 --- a/build/pkgs/googletest/checksums.ini +++ b/build/pkgs/googletest/checksums.ini @@ -1,5 +1,4 @@ tarball=googletest-VERSION.tar.gz -sha1=bfa4b5131b6eaac06962c251742c96aab3f7aa78 -md5=95b29f0038ec84a611df951d74d99897 -cksum=719315074 +sha1=568d58e26bd4e838449ca7ab8ebc152b3cbd210d +sha256=7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926 upstream_url=https://github.com/google/googletest/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/googletest/package-version.txt b/build/pkgs/googletest/package-version.txt index feaae22bac7..42cf0675c56 100644 --- a/build/pkgs/googletest/package-version.txt +++ b/build/pkgs/googletest/package-version.txt @@ -1 +1 @@ -1.13.0 +1.15.2 From 3dd70785da06165f0519c30891b460d61c4dd589 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 16:19:34 -0700 Subject: [PATCH 247/262] build/pkgs/googletest/spkg-configure.m4: New --- build/pkgs/googletest/spkg-configure.m4 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 build/pkgs/googletest/spkg-configure.m4 diff --git a/build/pkgs/googletest/spkg-configure.m4 b/build/pkgs/googletest/spkg-configure.m4 new file mode 100644 index 00000000000..40914cddcee --- /dev/null +++ b/build/pkgs/googletest/spkg-configure.m4 @@ -0,0 +1,16 @@ +SAGE_SPKG_CONFIGURE([googletest], [dnl + AC_MSG_CHECKING([whether googletest is available]) + rm -rf conftest_srcdir + mkdir conftest_srcdir + cat > conftest_srcdir/CMakeLists.txt <& ]AS_MESSAGE_LOG_FD[ 2>&1], [dnl + AC_MSG_RESULT([yes]) + ], [dnl + AC_MSG_RESULT([no]) + AS_VAR_SET([sage_spkg_install_googletest], [yes]) + ]) +]) From e168962f386b7d24d0076798087cefa496f94771 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 16:57:04 -0700 Subject: [PATCH 248/262] Fix declarations of is_graphic, is_regular, is_valid --- ...ymour_internal.h-Add-missing-include.patch | 25 +++++++++++++++++++ src/sage/matroids/graphic_matroid.pxd | 4 +-- src/sage/matroids/graphic_matroid.pyx | 4 +-- src/sage/matroids/linear_matroid.pxd | 2 +- src/sage/matroids/linear_matroid.pyx | 6 ++--- 5 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 build/pkgs/cmr/patches/0001-src-cmr-seymour_internal.h-Add-missing-include.patch diff --git a/build/pkgs/cmr/patches/0001-src-cmr-seymour_internal.h-Add-missing-include.patch b/build/pkgs/cmr/patches/0001-src-cmr-seymour_internal.h-Add-missing-include.patch new file mode 100644 index 00000000000..c99374e6b1f --- /dev/null +++ b/build/pkgs/cmr/patches/0001-src-cmr-seymour_internal.h-Add-missing-include.patch @@ -0,0 +1,25 @@ +From 72a78493855add45a1ec8ddcd9c1e4d1d08e7028 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Sun, 13 Oct 2024 16:27:44 -0700 +Subject: [PATCH] src/cmr/seymour_internal.h: Add missing include + +--- + src/cmr/seymour_internal.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/cmr/seymour_internal.h b/src/cmr/seymour_internal.h +index 8abefea3..10fc4815 100644 +--- a/src/cmr/seymour_internal.h ++++ b/src/cmr/seymour_internal.h +@@ -1,6 +1,8 @@ + #ifndef CMR_SEYMOUR_INTERNAL_H + #define CMR_SEYMOUR_INTERNAL_H + ++#include ++ + #include "densematrix.h" + + #include +-- +2.42.0 + diff --git a/src/sage/matroids/graphic_matroid.pxd b/src/sage/matroids/graphic_matroid.pxd index 3684ab19f0d..b433d02dbd7 100644 --- a/src/sage/matroids/graphic_matroid.pxd +++ b/src/sage/matroids/graphic_matroid.pxd @@ -22,8 +22,8 @@ cdef class GraphicMatroid(Matroid): cpdef _is_isomorphic(self, other, certificate=*) cpdef _isomorphism(self, other) cpdef bint is_valid(self) noexcept - cpdef bint is_graphic(self) noexcept - cpdef bint is_regular(self) noexcept + cpdef bint is_graphic(self, algorithm=*) except -1 + cpdef bint is_regular(self, algorithm=*) except -1 cpdef graph(self) cpdef vertex_map(self) cpdef list groundset_to_edges(self, X) diff --git a/src/sage/matroids/graphic_matroid.pyx b/src/sage/matroids/graphic_matroid.pyx index 3361694df1e..f2c7c32987c 100644 --- a/src/sage/matroids/graphic_matroid.pyx +++ b/src/sage/matroids/graphic_matroid.pyx @@ -1110,7 +1110,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_graphic(self, **kwds) except -1: + cpdef bint is_graphic(self, algorithm=None) except -1: r""" Return if ``self`` is graphic. @@ -1124,7 +1124,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_regular(self, **kwds) except -1: + cpdef bint is_regular(self, algorithm=None) except -1: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/linear_matroid.pxd b/src/sage/matroids/linear_matroid.pxd index c73db5e92ce..8ae64598d99 100644 --- a/src/sage/matroids/linear_matroid.pxd +++ b/src/sage/matroids/linear_matroid.pxd @@ -174,6 +174,6 @@ cdef class RegularMatroid(LinearMatroid): cpdef has_line_minor(self, k, hyperlines=*, certificate=*) cpdef _linear_extension_chains(self, F, fundamentals=*) - cpdef bint is_regular(self) noexcept + cpdef bint is_regular(self, algorithm=*) except -1 cpdef bint is_graphic(self, algorithm=*) except -1 cpdef bint is_valid(self) noexcept diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index de70fc2b519..16cfc02ec69 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -3793,7 +3793,7 @@ cdef class BinaryMatroid(LinearMatroid): keep_initial_representation=False) # graphicness test - cpdef is_graphic(self, algorithm=None): + cpdef bint is_graphic(self, algorithm=None) except -1: r""" Test if the binary matroid is graphic. @@ -3960,7 +3960,7 @@ cdef class BinaryMatroid(LinearMatroid): A_cmr = Matrix_cmr_chr_sparse(A.parent(), A) return A_cmr._is_binary_linear_matroid_graphic() - cpdef is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -6406,7 +6406,7 @@ cdef class RegularMatroid(LinearMatroid): # representation - cpdef bint is_regular(self, **kwds) except -1: + cpdef bint is_regular(self, algorithm=None) except -1: r""" Return if ``self`` is regular. From 74490abd6a58d3dc19ffd8884f97449345a2ad13 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 17:19:30 -0700 Subject: [PATCH 249/262] src/sage/matroids/linear_matroid.pyx: Fix whitespace --- src/sage/matroids/linear_matroid.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 16cfc02ec69..6e833e9d369 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -3814,7 +3814,7 @@ cdef class BinaryMatroid(LinearMatroid): OUTPUT: Boolean. - + .. SEEALSO:: :meth:`M.is_graphic() Date: Sun, 13 Oct 2024 17:20:28 -0700 Subject: [PATCH 250/262] src/sage/matrix/seymour_decomposition.pyx: Replace bare except --- src/sage/matrix/seymour_decomposition.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 5a16ae4a8c7..e0ceb27f4be 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -138,7 +138,7 @@ cdef class DecompositionNode(SageObject): cdef Matrix_cmr_chr_sparse matrix try: matrix = self.matrix() - except: + except Exception: raise ValueError('no Matrix_cmr_chr_sparse matrix') base_ring = self.base_ring() if base_ring.characteristic() not in [0, 2, 3] : From 0084c337d3aed0ba3f87bd785df3144fd323d67e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 20:31:03 -0700 Subject: [PATCH 251/262] Docstring markup fixes --- src/sage/matrix/matrix_cmr_sparse.pyx | 53 +++++++++++++---------- src/sage/matrix/seymour_decomposition.pyx | 48 ++++++++++---------- src/sage/matroids/linear_matroid.pyx | 4 +- 3 files changed, 58 insertions(+), 47 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 74815f5a750..76e4edda6d5 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -2533,9 +2533,9 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): .. SEEALSO:: :meth:`binary_pivot`, :meth:`binary_pivots`, :meth:`ternary_pivots` - EXAMPLES:: + EXAMPLES: - Single pivot on a `1`-entry: + Single pivot on a `1`-entry:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ @@ -2572,7 +2572,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): [ 1 -1 0 0 0 1 1 -1 1 1] [ 1 0 0 0 0 -1 0 -1 0 0] - Single pivot on a `-1`-entry: + Single pivot on a `-1`-entry:: sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 10, 10, sparse=True), [ ....: [-1, 1, 0, 0, 0, -1, 0, 1, 0, 0], @@ -2744,8 +2744,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix `M` of rank `r` is equimodular with determinant gcd `k` if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. OUTPUT: @@ -2800,8 +2802,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): the same determinant gcd `k`. A matrix `M` of rank-`r` is `k`-modular if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. OUTPUT: @@ -2850,8 +2854,10 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix `M` of rank-`r` is `k`-equimodular if the following two conditions are satisfied: + - for some column basis `B` of `M`, the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `k`; + - the matrix `X` such that `M=BX` is totally unimodular. If the matrix has full row rank, it is `k`-equimodular if @@ -3165,19 +3171,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): def is_network_matrix(self, *, time_limit=60.0, certificate=False, row_keys=None, column_keys=None): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a network matrix. If there is some entry not in `\{-1, 0, 1\}`, return ``False``. Let `D = (V,A)` be a digraph and let `T` be an (arbitrarily) directed spanning forest of the underlying undirected graph. The matrix `M(D,T) \in \{-1,0,1\}^{T \times (A \setminus T)}` defined via - ` - M(D,T)_{a,(v,w)} := \begin{cases} - +1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ forwardly}, \\ - -1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ backwardly}, \\ - 0 & \text{otherwise} - \end{cases} - ` + + .. MATH:: + + M(D,T)_{a,(v,w)} := \begin{cases} + +1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ forwardly}, \\ + -1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ backwardly}, \\ + 0 & \text{otherwise} + \end{cases} + is called the network matrix of `D` with respect to `T`. A matrix `M` is called network matrix if there exists a digraph `D` with a directed spanning forest `T` such that `M = M(D,T)`. @@ -3189,7 +3197,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): the support matrix of `M` for being graphic and uses camion for testing whether `M` is signed correctly. - EXAMPLES: + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -3221,11 +3229,11 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: K33 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 4, sparse=True), - ....: [[-1, -1, -1, -1], - ....: [ 1, 1, 0, 0], - ....: [ 0, 0, 1, 1], - ....: [ 1, 0, 1, 0], - ....: [ 0, 1, 0, 1]]); K33 + ....: [[-1, -1, -1, -1], + ....: [ 1, 1, 0, 0], + ....: [ 0, 0, 1, 1], + ....: [ 1, 0, 1, 0], + ....: [ 0, 1, 0, 1]]); K33 [-1 -1 -1 -1] [ 1 1 0 0] [ 0 0 1 1] @@ -3612,21 +3620,21 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): INPUT: - - ``certificate``: ``False`` or ``True`` - If ``True``, then return + - ``certificate`` -- boolean (default: ``False``); + if ``True``, then return a :class:`DecompositionNode` if ``self`` is totally unimodular; a submatrix with determinant not in `\{0, \pm1\}` if not. - - ``stop_when_nonTU`` -- boolean (default: ``True``) + - ``stop_when_nonTU`` -- boolean (default: ``True``); Whether to stop decomposing once not TU is determined. For a description of other parameters, see :meth:`_set_cmr_seymour_parameters` - ``row_keys`` -- a finite or enumerated family of arbitrary objects - that index the rows of the matrix + that index the rows of the matrix - ``column_keys`` -- a finite or enumerated family of arbitrary objects - that index the columns of the matrix + that index the columns of the matrix EXAMPLES:: @@ -3685,6 +3693,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): If the matrix is totally unimodular, it always returns a full decomposition as a certificate:: + sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 9, sparse=True), ....: [[-1,-1,-1,-1, 0, 0, 0, 0, 0], ....: [1, 1, 0, 0, 0, 0, 0, 0, 0], diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index e0ceb27f4be..da18ad3e4e0 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -889,7 +889,7 @@ cdef class DecompositionNode(SageObject): ((((0, 0), (0, 1), (0, 2), (0, 3)), ((0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'))), (((1, 'a'), (1, 'b')), ((1, 0), (1, 1), (1, 2)))) - ``row_keys``, ``column_keys`` of ``summands`` are disjoint: + ``row_keys``, ``column_keys`` of ``summands`` are disjoint:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: from sage.matrix.seymour_decomposition import DecompositionNode @@ -901,7 +901,8 @@ cdef class DecompositionNode(SageObject): sage: node = DecompositionNode.one_sum(*certificate.child_nodes()) Traceback (most recent call last): ... - ValueError: keys must be disjoint, got summand_row_keys=('a', 'e'), summand_column_keys=('a', 'b') + ValueError: keys must be disjoint, got + summand_row_keys=('a', 'e'), summand_column_keys=('a', 'b') sage: result, certificate = M2.is_totally_unimodular(certificate=True, ....: row_keys=range(4), @@ -911,7 +912,8 @@ cdef class DecompositionNode(SageObject): ....: column_keys='abce') Traceback (most recent call last): ... - ValueError: inconsistent column_keys, got column_keys=('a', 'b', 'c', 'e'), should be a permutation of ['a', 'b', 'c', 'd'] + ValueError: inconsistent column_keys, got column_keys=('a', 'b', 'c', 'e'), + should be a permutation of ['a', 'b', 'c', 'd'] """ summand_ids = kwds.pop('summand_ids', None) row_keys = kwds.pop('row_keys', None) @@ -1829,21 +1831,21 @@ cdef class DecompositionNode(SageObject): INPUT: - - ``stop_when_nonTU`` -- boolean - Whether to stop decomposing once being non-TU is determined. + - ``stop_when_nonTU`` -- boolean; + whether to stop decomposing once being non-TU is determined. - - ``stop_when_nonnetwork`` -- boolean - Whether to stop decomposing once being non-network is determined. + - ``stop_when_nonnetwork`` -- boolean; + whether to stop decomposing once being non-network is determined. - - ``stop_when_nonconetwork`` -- boolean - Whether to stop decomposing once being non-conetwork is determined. + - ``stop_when_nonconetwork`` -- boolean; + whether to stop decomposing once being non-conetwork is determined. - - ``stop_when_nonnetwork_and_nonconetwork`` -- boolean - Whether to stop decomposing once not being network - and not being conetwork is determined. + - ``stop_when_nonnetwork_and_nonconetwork`` -- boolean; + whether to stop decomposing once not being network + and not being conetwork is determined. - For a description of other parameters, see - :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters` + For a description of other parameters, see + :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters`. EXAMPLES:: @@ -3013,9 +3015,9 @@ cdef class BaseGraphicNode(DecompositionNode): If ``self.base_ring()`` is `\GF{2}`, then return edges. If ``self.base_ring()`` is `\GF{3}` or `\ZZ`, then arcs. - EXAMPLES:: + EXAMPLES: - Undirected graph: + Undirected graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -3031,7 +3033,7 @@ cdef class BaseGraphicNode(DecompositionNode): sage: certificate.coforest_edges() ((2, 7), (1, 12)) - Directed graph: + Directed graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -3143,9 +3145,9 @@ cdef class CographicNode(BaseGraphicNode): r""" Actually the cograph of matrix, in the case where it is not graphic. - EXAMPLES:: + EXAMPLES: - Undirected graph: + Undirected graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), @@ -3169,7 +3171,7 @@ cdef class CographicNode(BaseGraphicNode): sage: G.edges(sort=True) [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] - Directed graph: + Directed graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), @@ -3288,9 +3290,9 @@ cdef class PlanarNode(BaseGraphicNode): r""" Return the cograph of matrix. - EXAMPLES:: + EXAMPLES: - Undirected graph: + Undirected graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -3313,7 +3315,7 @@ cdef class PlanarNode(BaseGraphicNode): sage: certificate.cograph_coforest_edges() ((1, 2), (2, 7), (7, 1)) - Directed graph: + Directed graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 6e833e9d369..554f4c5096a 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -3808,8 +3808,8 @@ cdef class BinaryMatroid(LinearMatroid): to check graphicness: - ``None`` -- an algorithm based on [GG2012]_. - - ``"cmr"`` -- an algorithm based on [BW1988b]_. - the optional package "cmr" is required. + - ``"cmr"`` -- an algorithm based on [BW1988b]_; + the optional package "cmr" is required. OUTPUT: From 82ec06012f5d7071478be5d0fe04bad3831c3abe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 20:41:31 -0700 Subject: [PATCH 252/262] src/doc/en/reference/matrices/index.rst: Conditionalize on feature sage.libs.cmr --- src/doc/en/reference/matrices/index.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/matrices/index.rst b/src/doc/en/reference/matrices/index.rst index e928bcf87fe..9de4c4c6bc6 100644 --- a/src/doc/en/reference/matrices/index.rst +++ b/src/doc/en/reference/matrices/index.rst @@ -85,7 +85,6 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/matrix_polynomial_dense sage/matrix/matrix_mpolynomial_dense sage/matrix/matrix_cyclo_dense - sage/matrix/matrix_cmr_sparse sage/matrix/operation_table @@ -99,8 +98,15 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/misc_flint sage/matrix/symplectic_basis sage/matrix/compute_J_ideal - sage/matrix/seymour_decomposition sage/matrix/benchmark +.. ONLY:: feature_sage_libs_cmr + + .. toctree:: + :maxdepth: 1 + + sage/matrix/seymour_decomposition + sage/matrix/matrix_cmr_sparse + .. include:: ../footer.txt From 92a091c938f01083f09d3e1bd9c95c696f727003 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 21:02:09 -0700 Subject: [PATCH 253/262] src/setup.py: Add cmr to optional distribs --- src/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup.py b/src/setup.py index dfa2e59b2e1..a10e7a59b4f 100755 --- a/src/setup.py +++ b/src/setup.py @@ -77,7 +77,7 @@ log.info("Discovering Python/Cython source code...") optional_packages = ['mcqd', 'bliss', 'tdlib', - 'coxeter3', 'sirocco', 'meataxe'] + 'coxeter3', 'sirocco', 'meataxe', 'cmr'] distributions_to_exclude = [f"sagemath-{pkg}" for pkg in optional_packages] files_to_exclude = filter_cython_sources(SAGE_SRC, distributions_to_exclude) From f9bb684622e61ca0a828d9d9b1b820500d4ebc7f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 21:26:15 -0700 Subject: [PATCH 254/262] More docstring markup fixes --- src/sage/matrix/seymour_decomposition.pyx | 12 ++++++------ src/sage/matroids/linear_matroid.pyx | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index da18ad3e4e0..81e33d842ea 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -2960,9 +2960,9 @@ cdef class BaseGraphicNode(DecompositionNode): If ``self.base_ring()`` is `\GF{2}`, then return an undirected graph. If ``self.base_ring()`` is `\GF{3}` or `\ZZ`, then return directed graph. - EXAMPLES:: + EXAMPLES: - Undirected graph: + Undirected graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -2980,7 +2980,7 @@ cdef class BaseGraphicNode(DecompositionNode): sage: G.edges(sort=True) [(1, 2, None), (1, 7, None), (1, 12, None), (2, 7, None), (7, 12, None)] - Directed graph: + Directed graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 3, 2, sparse=True), @@ -3208,9 +3208,9 @@ cdef class CographicNode(BaseGraphicNode): r""" Return the forest edges of the cograph of ``self``. - EXAMPLES:: + EXAMPLES: - Undirected graph: + Undirected graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), @@ -3230,7 +3230,7 @@ cdef class CographicNode(BaseGraphicNode): sage: certificate.coforest_edges() ((5, 8), (5, 1), (0, 2), (2, 8)) - Directed graph: + Directed graph:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 5, sparse=True), diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 554f4c5096a..96931539ef7 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -6352,8 +6352,8 @@ cdef class RegularMatroid(LinearMatroid): to check graphicness: - ``None`` -- an algorithm based on [GG2012]_. - - ``"cmr"`` -- an algorithm based on [BW1988b]_. - the optional package "cmr" is required. + - ``"cmr"`` -- an algorithm based on [BW1988b]_; + the optional package "cmr" is required. OUTPUT: boolean From 0264700b6555e3b29ab9e10bcd6989e3312bb19e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Oct 2024 21:26:29 -0700 Subject: [PATCH 255/262] Fix dependencies --- build/pkgs/sagelib/dependencies | 2 +- build/pkgs/sagemath_doc_html/dependencies_optional | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/sagelib/dependencies b/build/pkgs/sagelib/dependencies index c738b0072d4..b1ebfd0825e 100644 --- a/build/pkgs/sagelib/dependencies +++ b/build/pkgs/sagelib/dependencies @@ -1,4 +1,4 @@ -FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf sagemath_cmr singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran +FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw sage_conf singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sagemath_doc_html/dependencies_optional b/build/pkgs/sagemath_doc_html/dependencies_optional index e9b59e89755..91bb2e99598 100644 --- a/build/pkgs/sagemath_doc_html/dependencies_optional +++ b/build/pkgs/sagemath_doc_html/dependencies_optional @@ -1 +1 @@ -jupyter_sphinx +jupyter_sphinx sagemath_cmr From a27128aa734f9604054e0b2961e97ff01323df4f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 10:30:12 -0700 Subject: [PATCH 256/262] src/sage/matrix/seymour_decomposition.pyx: Markup fixes --- src/sage/matrix/seymour_decomposition.pyx | 59 +++++++++++------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 81e33d842ea..75b7989f8e0 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -64,13 +64,13 @@ cdef class DecompositionNode(SageObject): if the base ring is `\GF(3)` or ``ZZ``, the node deals with the matrix decomposition. - A :class:DecompositionNode is usually created with an internal decomposition, + A :class:`DecompositionNode` is usually created with an internal decomposition, ``self._dec``, see :meth:create_DecompositionNode Such decomposition comes from the certificate of the totally unimodularity test, see :meth:`matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_totally_unimodular` - Another usage is to create a :class:UnknownNode from a matrix. + Another usage is to create a :class:`UnknownNode` from a matrix. A root dummy decomposition is created before completing the decomposition, see :meth:_set_root_dec, :meth:complete_decomposition @@ -383,7 +383,7 @@ cdef class DecompositionNode(SageObject): r""" Set default row and column keys. - .. SEEALSO:: :class:ElementKey + .. SEEALSO:: :class:`ElementKey` EXAMPLES:: @@ -432,7 +432,7 @@ cdef class DecompositionNode(SageObject): [1 0 1] [0 1 1] sage: node.morphism()._unicode_art_matrix() - 0 1 2 + 0 1 2 a⎛1 0 1⎞ b⎝0 1 1⎠ """ @@ -487,7 +487,7 @@ cdef class DecompositionNode(SageObject): def is_ternary(self): r""" - Returns true iff the decomposition is over `\mathbb{F}_3`. + Return whether the decomposition is over `\GF{3}`. EXAMPLES:: @@ -614,8 +614,8 @@ cdef class DecompositionNode(SageObject): r""" Return a tuple of the children. - The children are sorted by the inherited ordering from cmr, which - is their appreance in the parent. + The children are sorted by the ordering inherited from cmr, which + is their appearance in the parent. In the case of :class:`SumNode`, this is the same as :meth:`~SumNode.summands`. @@ -795,11 +795,11 @@ cdef class DecompositionNode(SageObject): def one_sum(*summands, **kwds): r""" - Return a :class:OneSumNode constructed from the given nodes (summands). + Return a :class:`OneSumNode` constructed from the given nodes (summands). INPUT: - - ``summands`` -- decomposition nodes :class:DecompositionNode + - ``summands`` -- decomposition nodes :class:`DecompositionNode` - ``summand_ids`` -- a tuple or list of ids for summands @@ -1284,21 +1284,21 @@ cdef class DecompositionNode(SageObject): INPUT: - - ``stop_when_irregular`` -- boolean - Whether to stop decomposing once irregularity is determined. + - ``stop_when_irregular`` -- boolean; + whether to stop decomposing once irregularity is determined. - - ``stop_when_nongraphic`` -- boolean - Whether to stop decomposing once non-graphicness is determined. + - ``stop_when_nongraphic`` -- boolean; + whether to stop decomposing once non-graphicness is determined. - - ``stop_when_noncographic`` -- boolean - Whether to stop decomposing once non-cographicness is determined. + - ``stop_when_noncographic`` -- boolean; + whether to stop decomposing once non-cographicness is determined. - - ``stop_when_nongraphic_and_noncographic`` -- boolean - Whether to stop decomposing once non-graphicness and non-cographicness - is determined. + - ``stop_when_nongraphic_and_noncographic`` -- boolean; + whether to stop decomposing once non-graphicness and non-cographicness + is determined. - For a description of other parameters, see - :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters` + For a description of other parameters, see + :meth:`sage.matrix.matrix_cmr_sparse._set_cmr_seymour_parameters` EXAMPLES:: @@ -1443,7 +1443,7 @@ cdef class DecompositionNode(SageObject): def is_network_matrix(self, *, decomposition=False, **kwds): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a network matrix. If there is some entry not in `\{-1, 0, 1\}`, return ``False``. This method is based on Seymour's decomposition. @@ -1531,7 +1531,7 @@ cdef class DecompositionNode(SageObject): def is_conetwork_matrix(self, *, decomposition=False, **kwds): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a conetwork matrix. + Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a conetwork matrix. If there is some entry not in `\{-1, 0, 1\}`, return ``False``. This method is based on Seymour's decomposition. @@ -1540,10 +1540,9 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse.is_conetwork_matrix` - :meth:`UnknownNode.is_conetwork_matrix` - :meth:`complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_conetwork_matrix` + - :meth:`UnknownNode.is_conetwork_matrix` + - :meth:`complete_decomposition` EXAMPLES:: @@ -2088,7 +2087,7 @@ cdef class UnknownNode(DecompositionNode): def is_network_matrix(self, *, decomposition=False, certificate=False, **kwds): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a network matrix. + Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a network matrix. If there is some entry not in `\{-1, 0, 1\}`, return ``False``. .. SEEALSO:: @@ -2137,7 +2136,7 @@ cdef class UnknownNode(DecompositionNode): def is_conetwork_matrix(self, *, decomposition=False, certificate=False, **kwds): r""" - Return whether the matrix ``self`` over `\GF{3}` or `QQ` is a conetwork matrix. + Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a conetwork matrix. If there is some entry not in `\{-1, 0, 1\}`, return ``False``. .. SEEALSO:: @@ -2922,7 +2921,7 @@ cdef class BaseGraphicNode(DecompositionNode): graph=None, forest_edges=None, coforest_edges=None, row_keys=None, column_keys=None, base_ring=None): r""" - Base class for :class:GraphicNode, :class:CographicNode, and :class:PlanarNode + Base class for :class:`GraphicNode`, :class:`CographicNode`, and :class:`PlanarNode` If ``base_ring`` is `\GF{2}`, then it represents a graphic/cographic/planar matroid. @@ -3393,7 +3392,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): r""" Return the core of ``self``. - A :class:SeriesParallelReductionNode indicates that `M` + A :class:`SeriesParallelReductionNode` indicates that `M` arises from a smaller matrix `M'` (called the core) by successively adding zero rows/columns, unit rows/columns or duplicates of existing rows/columns From 9292b0b88eeeb050e420464328879d768ca7f365 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 11:48:04 -0700 Subject: [PATCH 257/262] build/pkgs/sagemath_cmr/dependencies: Add source files as dependencies --- build/pkgs/sagemath_cmr/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagemath_cmr/dependencies b/build/pkgs/sagemath_cmr/dependencies index dd820598115..ddc61e2969d 100644 --- a/build/pkgs/sagemath_cmr/dependencies +++ b/build/pkgs/sagemath_cmr/dependencies @@ -1 +1 @@ -$(PYTHON) cmr cysignals | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython +$(PYTHON) cmr cysignals $(SAGE_ROOT)/pkgs/sagemath-cmr/sage/libs/cmr/*.pxd $(SAGE_ROOT)/pkgs/sagemath-cmr/sage/matrix/matrix_cmr*.pyx $(SAGE_ROOT)/pkgs/sagemath-cmr/sage/matrix/seymour*.pyx | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython From aff6ca96cfd065bcc18d9e833e6b83035f436299 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 12:10:40 -0700 Subject: [PATCH 258/262] More docstring markup fixes --- src/sage/matrix/matrix_cmr_sparse.pyx | 98 +++++++++++------------ src/sage/matrix/seymour_decomposition.pyx | 43 ++++------ 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 76e4edda6d5..4f4a8173b66 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -988,12 +988,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``algorithm`` -- ``"cmr"`` or ``"direct"`` If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; If ``algorithm="direct"``, then construct three sum directly. - - ``verify`` -- boolean (default:``True``) - Whether to check the give two matrices and the related indices + - ``verify`` -- boolean (default: ``True``); + whether to check the given two matrices and the related indices satisfying the requirements of 3-sum by calling :meth:`is_three_sum_wide_wide`. - - ``sign_verify`` -- boolean (default:``False``) - Whether to check the sign correctness. + - ``sign_verify`` -- boolean (default: ``False``); + whether to check the sign correctness. See :meth:`is_three_sum_wide_wide`. OUTPUT: A :class:`Matrix_cmr_chr_sparse` @@ -1205,12 +1205,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``algorithm`` -- ``"cmr"`` or ``"direct"`` If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; If ``algorithm="direct"``, then construct three sum directly. - - ``verify`` -- boolean (default:``True``) - Whether to check the give two matrices and the related indices + - ``verify`` -- boolean (default: ``True``); + whether to check the give two matrices and the related indices satisfying the requirements of 3-sum by calling :meth:`is_three_sum_mixed_mixed`. - - ``sign_verify`` -- boolean (default:``False``) - Whether to check the sign correctness. + - ``sign_verify`` -- boolean (default: ``False``); + whether to check the sign correctness. See :meth:`is_three_sum_mixed_mixed`. OUTPUT: A :class:`Matrix_cmr_chr_sparse` @@ -1417,13 +1417,13 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``algorithm`` -- ``"cmr"`` or ``"direct"`` If ``algorithm="cmr"``, then use :meth:`_three_sum_cmr`; If ``algorithm="direct"``, then construct three sum directly. - - ``verify`` -- boolean (default:``True``) - Whether to check the give two matrices and the related indices + - ``verify`` -- boolean (default: ``True``); + whether to check the give two matrices and the related indices satisfying the requirements of 3-sum by calling :meth:`is_three_sum_wide_wide` or :meth:`is_three_sum_mixed_mixed`. - - ``sign_verify`` -- boolean (default:``False``) - Whether to check the sign correctness. + - ``sign_verify`` -- boolean (default: ``False``); + whether to check the sign correctness. See :meth:`is_three_sum`. OUTPUT: A :class:`Matrix_cmr_chr_sparse` @@ -1636,12 +1636,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``first_columns_index`` -- the column indices of `a_2` in `M_1` - ``second_row_index`` -- the row index of `b_2^T` in `M_2` - ``second_columns_index`` -- the column indices of `b_1` in `M_2` - - ``sign_verify`` -- boolean (default:``True``) - Whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. + - ``sign_verify`` -- boolean (default: ``True``); + whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. OUTPUT: boolean, or (boolean, string) - If it is False only because of the sign, then also output the correct sign. + If it is False only because of the sign, then also output the correct sign. EXAMPLES:: @@ -1892,12 +1892,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``first_column_index`` -- the index of the column with `\epsilon_2` in `M_1` - ``second_row_index`` -- the index of the row with `\epsilon_1` in `M_2` - ``second_columns_index`` -- the indices of columns `b_1` and `b_2` in `M_2` - - ``sign_verify`` -- boolean (default:``True``) - Whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. + - ``sign_verify`` -- boolean (default: ``True``); + whether to check the sign correctness of `\epsilon_1` and `\epsilon_2`. OUTPUT: boolean, or (boolean, string) - If it is False only because of the sign, then also output the correct sign. + If it is False only because of the sign, then also output the correct sign. EXAMPLES:: @@ -2144,12 +2144,12 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): - ``first_two_indices`` -- the indices of two extra rows/columns in `M_1` - ``second_one_index`` -- the index of one extra row/column in `M_2` - ``second_two_indices`` -- the indices of two extra rows/columns in `M_2` - - ``sign_verify`` -- boolean (default:``True``) - Whether to check the sign correctness. + - ``sign_verify`` -- boolean (default: ``True``); + whether to check the sign correctness. OUTPUT: boolean, or (boolean, string) - If it is False only because of the sign, then also output the correct sign. + If it is False only because of the sign, then also output the correct sign. EXAMPLES:: @@ -2658,7 +2658,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): the greatest common divisor of the determinants of all `r`-by-`r` submatrices of `B` is `1`. [Sch1986]_, Ch. 21.4. - .. SEEALSO:: :meth:`is_k_modular`, :meth:`is_strongly_unimodular`, :meth:`is_totally_unimodular` + .. SEEALSO:: :meth:`is_k_equimodular`, :meth:`is_strongly_unimodular`, :meth:`is_totally_unimodular` EXAMPLES:: @@ -2800,7 +2800,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): A matrix is strongly equimodular if ``self`` and ``self.transpose()`` are both equimodular, which implies that they are equimodular for the same determinant gcd `k`. - A matrix `M` of rank-`r` is `k`-modular if the following two conditions + A matrix `M` of rank-`r` is `k`-equimodular if the following two conditions are satisfied: - for some column basis `B` of `M`, the greatest common divisor of the @@ -3316,7 +3316,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): .. SEEALSO:: :meth:`is_network_matrix`, - EXAMPLES: + EXAMPLES:: sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 4, 9, sparse=True), @@ -3425,8 +3425,8 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): if the linear matroid of ``self`` over `\GF{2}` is regular; If not, NotImplemented. - - ``stop_when_irregular`` -- boolean (default: ``True``) - Whether to stop decomposing once irregularity is determined. + - ``stop_when_irregular`` -- boolean (default: ``True``); + whether to stop decomposing once irregularity is determined. For a description of other parameters, see :meth:`_set_cmr_seymour_parameters` @@ -3626,7 +3626,7 @@ cdef class Matrix_cmr_chr_sparse(Matrix_cmr_sparse): a submatrix with determinant not in `\{0, \pm1\}` if not. - ``stop_when_nonTU`` -- boolean (default: ``True``); - Whether to stop decomposing once not TU is determined. + whether to stop decomposing once not TU is determined. For a description of other parameters, see :meth:`_set_cmr_seymour_parameters` @@ -3832,40 +3832,40 @@ cdef _set_cmr_seymour_parameters(CMR_SEYMOUR_PARAMS *params, dict kwds): Keyword arguments: - - ``stop_when_irregular`` -- boolean - Whether to stop decomposing once irregularity is determined. + - ``stop_when_irregular`` -- boolean; + whether to stop decomposing once irregularity is determined. - - ``stop_when_nongraphic`` -- boolean - Whether to stop decomposing once non-graphicness (or being non-network) is determined. + - ``stop_when_nongraphic`` -- boolean; + whether to stop decomposing once non-graphicness (or being non-network) is determined. - - ``stop_when_noncographic`` -- boolean - Whether to stop decomposing once non-cographicness (or being non-conetwork) is determined. + - ``stop_when_noncographic`` -- boolean; + whether to stop decomposing once non-cographicness (or being non-conetwork) is determined. - - ``stop_when_nongraphic_and_noncographic`` -- boolean - Whether to stop decomposing once non-graphicness and non-cographicness + - ``stop_when_nongraphic_and_noncographic`` -- boolean; + whether to stop decomposing once non-graphicness and non-cographicness (or not being network and not being conetwork) is determined. - ``series_parallel_ok`` -- boolean (default: ``True``); - Whether to allow series-parallel operations in the decomposition tree. + whether to allow series-parallel operations in the decomposition tree. - ``check_graphic_minors_planar`` -- boolean (default: ``False``); - Whether minors identified as graphic should still be checked for cographicness. + whether minors identified as graphic should still be checked for cographicness. - ``use_direct_graphicness_test`` -- boolean (default: ``True``); - Whether to use fast graphicness routines. + whether to use fast graphicness routines. - - ``prefer_graphicness`` -- boolean - Whether to first test for (co)graphicness (or being (co)network) - before applying series-parallel reductions + - ``prefer_graphicness`` -- boolean; + whether to first test for (co)graphicness (or being (co)network) + before applying series-parallel reductions. - - ``three_sum_pivot_children`` -- boolean - Whether pivots for 3-sums shall be applied such that the matrix contains + - ``three_sum_pivot_children`` -- boolean; + whether pivots for 3-sums shall be applied such that the matrix contains both child matrices as submatrices, if possible. - ``three_sum_strategy`` -- ``"Mixed_Mixed"`` or ``"Wide_Wide"`` or integer; - Whether to perform pivots to change the rank distribution, and how to construct the children. + whether to perform pivots to change the rank distribution, and how to construct the children. - The value is a bit-wise or of three decisions. + The value is a bit-wise "or" of three decisions. The first decision is that of the rank distribution: - CMR_SEYMOUR_THREESUM_FLAG_NO_PIVOTS to not change the rank distribution (default), or @@ -3904,11 +3904,11 @@ cdef _set_cmr_seymour_parameters(CMR_SEYMOUR_PARAMS *params, dict kwds): ``"Wide_Wide"`` is to allow pivots and choose CMR_SEYMOUR_THREESUM_FLAG_SEYMOUR - - ``construct_leaf_graphs`` -- boolean - Whether to construct (co)graphs for all leaf nodes that are (co)graphic or (co)network. + - ``construct_leaf_graphs`` -- boolean; + whether to construct (co)graphs for all leaf nodes that are (co)graphic or (co)network. - - ``construct_all_graphs`` -- boolean - Whether to construct (co)graphs for all nodes that are (co)graphic or (co)network. + - ``construct_all_graphs`` -- boolean; + whether to construct (co)graphs for all nodes that are (co)graphic or (co)network. """ CMR_CALL(CMRseymourParamsInit(params)) params.stopWhenIrregular = kwds['stop_when_irregular'] diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 75b7989f8e0..53a282a9262 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1019,10 +1019,9 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` - :meth:`UnknownNode._is_binary_linear_matroid_graphic` - :meth:`_binary_linear_matroid_complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` + - :meth:`UnknownNode._is_binary_linear_matroid_graphic` + - :meth:`_binary_linear_matroid_complete_decomposition` EXAMPLES:: @@ -1107,10 +1106,9 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` - :meth:`UnknownNode._is_binary_linear_matroid_cographic` - :meth:`_binary_linear_matroid_complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` + - :meth:`UnknownNode._is_binary_linear_matroid_cographic` + - :meth:`_binary_linear_matroid_complete_decomposition` EXAMPLES:: @@ -1189,9 +1187,8 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse._is_binary_linear_matroid_regular` - :meth:`_binary_linear_matroid_complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse._is_binary_linear_matroid_regular` + - :meth:`_binary_linear_matroid_complete_decomposition` EXAMPLES:: @@ -1452,10 +1449,9 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse.is_network_matrix` - :meth:`UnknownNode.is_network_matrix` - :meth:`complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_network_matrix` + - :meth:`UnknownNode.is_network_matrix` + - :meth:`complete_decomposition` EXAMPLES:: @@ -1626,9 +1622,8 @@ cdef class DecompositionNode(SageObject): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse.is_totally_unimodular` - :meth:`complete_decomposition` + - :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_totally_unimodular` + - :meth:`complete_decomposition` EXAMPLES:: @@ -1996,8 +1991,7 @@ cdef class UnknownNode(DecompositionNode): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse._is_binary_linear_matroid_graphic` EXAMPLES:: @@ -2046,8 +2040,7 @@ cdef class UnknownNode(DecompositionNode): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse._is_binary_linear_matroid_cographic` EXAMPLES:: @@ -2092,8 +2085,7 @@ cdef class UnknownNode(DecompositionNode): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse.is_network_matrix` + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_network_matrix` EXAMPLES:: @@ -2141,8 +2133,7 @@ cdef class UnknownNode(DecompositionNode): .. SEEALSO:: - :meth:`sage.matrix.matrix_cmr_sparse. - Matrix_cmr_chr_sparse.is_conetwork_matrix` + :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse.is_conetwork_matrix` EXAMPLES:: From 7527f8e88fb7a77d6bed57f4317cabfa3494e9fe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 12:27:11 -0700 Subject: [PATCH 259/262] build/make/Makefile.in (PYPI_WHEEL_PACKAGES): Add sagemath_cmr --- build/make/Makefile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 420dadb9364..ef805f682c6 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -142,6 +142,7 @@ PYPI_WHEEL_PACKAGES = $(PYPI_NOARCH_WHEEL_PACKAGES) \ sagemath_repl \ sagemath_categories \ sagemath_bliss \ + sagemath_cmr \ sagemath_mcqd \ sagemath_tdlib \ sagemath_coxeter3 \ From 6b701b66ce7ff46be2822e8a506667f6b83ec115 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 12:40:06 -0700 Subject: [PATCH 260/262] src/sage/misc/sagedoc.py: Add :cmr: role --- src/doc/en/developer/sage_manuals.rst | 4 ++++ src/sage/misc/sagedoc.py | 1 + 2 files changed, 5 insertions(+) diff --git a/src/doc/en/developer/sage_manuals.rst b/src/doc/en/developer/sage_manuals.rst index 13f6a3da94a..74f60c23e86 100644 --- a/src/doc/en/developer/sage_manuals.rst +++ b/src/doc/en/developer/sage_manuals.rst @@ -204,6 +204,10 @@ by Sage, you can link toward it without specifying its full path: - ``:mathscinet:`MR0100971``` - :mathscinet:`MR0100971` + * - :ref:`CMR ` + - ``:cmr:`GraphNode ``` + - :cmr:`GraphNode ` + * - :ref:`ECL ` - ``:ecl:`Manipulating-Lisp-objects``` - :ecl:`Manipulating-Lisp-objects` diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 827fd77e811..9b377921708 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -516,6 +516,7 @@ def process_dollars(s): 'doi': ('https://doi.org/%s', 'doi:%s'), 'pari': ('https://pari.math.u-bordeaux.fr/dochtml/help/%s', 'pari:%s'), 'mathscinet': ('https://www.ams.org/mathscinet-getitem?mr=%s', 'MathSciNet %s'), + 'cmr': ('https://discopt.github.io/cmr/%s.html', 'CMR: %s'), 'common_lisp': ('https://www.lispworks.com/documentation/lw50/CLHS/Body/%s.htm', 'Common Lisp: %s'), 'ecl': ('https://ecl.common-lisp.dev/static/manual/%s.html', 'ECL: %s'), 'gap': ('https://docs.gap-system.org/doc/ref/%s_mj.html', 'GAP: %s'), From 7d44d9e1331ce0f41cf84c37c942a8758d93bb2e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 12:54:19 -0700 Subject: [PATCH 261/262] Link to spkg_sagemath_cmr --- pkgs/sagemath-cmr/README.rst | 11 ++++------- src/sage/matrix/matrix_cmr_sparse.pyx | 5 ++++- src/sage/matrix/seymour_decomposition.pyx | 3 +++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pkgs/sagemath-cmr/README.rst b/pkgs/sagemath-cmr/README.rst index 545ae16eb32..46d2baaad90 100644 --- a/pkgs/sagemath-cmr/README.rst +++ b/pkgs/sagemath-cmr/README.rst @@ -8,18 +8,15 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2023 The Sage Development Team + Copyright (C) 2005-2024 The Sage Development Team https://www.sagemath.org SageMath fully supports all major Linux distributions, recent versions of -macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +macOS, and Windows (Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via -Sage-the-distribution (https://www.sagemath.org/download-source.html). -Sage-the-distribution first builds a large number of open source packages from -source (unless it finds suitable versions installed in the system) and then -installs the Sage Library (sagelib, implemented in Python and Cython). +See https://doc.sagemath.org/html/en/installation/index.html +for general installation instructions. About this pip-installable source distribution diff --git a/src/sage/matrix/matrix_cmr_sparse.pyx b/src/sage/matrix/matrix_cmr_sparse.pyx index 4f4a8173b66..47746555eed 100644 --- a/src/sage/matrix/matrix_cmr_sparse.pyx +++ b/src/sage/matrix/matrix_cmr_sparse.pyx @@ -1,6 +1,9 @@ # sage_setup: distribution = sagemath-cmr +# sage.doctest: optional - sage.libs.cmr r""" -Sparse Matrices with CMR +Sparse Matrices from the Combinatorial Matrix Recognition Library + +This module is provided by the distribution :ref:`sagemath-cmr `. """ # **************************************************************************** diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 53a282a9262..2a8735a23ad 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -1,6 +1,9 @@ # sage_setup: distribution = sagemath-cmr +# sage.doctest: optional - sage.libs.cmr r""" Seymour's decomposition of totally unimodular matrices and regular matroids + +This module is provided by the distribution :ref:`sagemath-cmr `. """ # **************************************************************************** From 442caaa5870cd6d70339af99b31cd885bacb4154 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 14 Oct 2024 13:59:05 -0700 Subject: [PATCH 262/262] src/sage/matrix/seymour_decomposition.pyx: Reformat examples --- src/sage/matrix/seymour_decomposition.pyx | 230 +++++++++++----------- 1 file changed, 116 insertions(+), 114 deletions(-) diff --git a/src/sage/matrix/seymour_decomposition.pyx b/src/sage/matrix/seymour_decomposition.pyx index 2a8735a23ad..40ffe6d5a90 100644 --- a/src/sage/matrix/seymour_decomposition.pyx +++ b/src/sage/matrix/seymour_decomposition.pyx @@ -697,15 +697,15 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: row_keys=['r1', 'r2', 'r3', 'r4', 'r5', ....: 'r6', 'r7', 'r8', 'r9'], @@ -738,8 +738,8 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), - ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], - ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + ....: [[1,0,1,1,0,0], [0,1,1,1,0,0], [1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1], [1,0,1,0,1,0], [0,-1,0,-1,0,1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(6), @@ -758,8 +758,8 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), - ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], - ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + ....: [[1,0,1,1,0,0], [0,1,1,1,0,0], [1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1], [1,0,1,0,1,0], [0,-1,0,-1,0,1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(6), @@ -781,8 +781,8 @@ cdef class DecompositionNode(SageObject): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 6, 6, sparse=True), - ....: [[1,0,1,1,0,0],[0,1,1,1,0,0],[1,0,1,0,1,1], - ....: [0,-1,0,-1,1,1],[1,0,1,0,1,0],[0,-1,0,-1,0,1]]) + ....: [[1,0,1,1,0,0], [0,1,1,1,0,0], [1,0,1,0,1,1], + ....: [0,-1,0,-1,1,1], [1,0,1,0,1,0], [0,-1,0,-1,0,1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Wide_Wide", ....: row_keys=range(6), @@ -890,7 +890,7 @@ cdef class DecompositionNode(SageObject): ) sage: node.child_indices() ((((0, 0), (0, 1), (0, 2), (0, 3)), ((0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'))), - (((1, 'a'), (1, 'b')), ((1, 0), (1, 1), (1, 2)))) + (((1, 'a'), (1, 'b')), ((1, 0), (1, 1), (1, 2)))) ``row_keys``, ``column_keys`` of ``summands`` are disjoint:: @@ -2759,15 +2759,15 @@ cdef class ThreeSumNode(SumNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12_large.is_totally_unimodular(certificate=True) sage: C = certificate.child_nodes()[0]; C ThreeSumNode (9×12) with 2 children @@ -2807,15 +2807,15 @@ cdef class ThreeSumNode(SumNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12_large = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12_large.is_totally_unimodular(certificate=True, ....: three_sum_strategy="Mixed_Mixed") sage: C = certificate; C @@ -3162,7 +3162,8 @@ cdef class CographicNode(BaseGraphicNode): sage: G.vertices(sort=True) [0, 1, 2, 5, 7, 8] sage: G.edges(sort=True) - [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] + [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), + (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] Directed graph:: @@ -3184,7 +3185,8 @@ cdef class CographicNode(BaseGraphicNode): sage: G.vertices(sort=True) [0, 1, 2, 5, 7, 8] sage: G.edges(sort=True) - [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] + [(0, 2, None), (0, 5, None), (0, 7, None), (1, 2, None), (1, 5, None), + (1, 7, None), (2, 8, None), (5, 8, None), (7, 8, None)] """ if self._graph is not None: return self._graph @@ -3387,7 +3389,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): Return the core of ``self``. A :class:`SeriesParallelReductionNode` indicates that `M` - arises from a smaller matrix `M'` (called the core) + arises from a smaller matrix `M'` (called the *core*) by successively adding zero rows/columns, unit rows/columns or duplicates of existing rows/columns (potentially scaled with `-1`). @@ -3400,7 +3402,7 @@ cdef class SeriesParallelReductionNode(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: M = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 6, sparse=True), ....: [[1, 1, 1, 1, 1, 0], [1, 1, 1, 0, 0, 0], - ....: [1, 0, 1, 1, 0, 1] ,[1, 0, 0, 1, 1, 0], + ....: [1, 0, 1, 1, 0, 1], [1, 0, 0, 1, 1, 0], ....: [1, 1, 0, 0, 1, 0]]); M [1 1 1 1 1 0] [1 1 1 0 0 0] @@ -3429,11 +3431,11 @@ cdef class R10Node(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 0, 0, 1, 1], - ....: [1, 1, 0, 0, 1], - ....: [0, 1, 1, 0, 1], - ....: [0, 0, 1, 1, 1], - ....: [1, 1, 1, 1, 1]]); R10 + ....: [[1, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1], + ....: [0, 1, 1, 0, 1], + ....: [0, 0, 1, 1, 1], + ....: [1, 1, 1, 1, 1]]); R10 [1 0 0 1 1] [1 1 0 0 1] [0 1 1 0 1] @@ -3455,11 +3457,11 @@ cdef class R10Node(DecompositionNode): False sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[ 1,-1, 0, 0,-1], - ....: [-1, 1,-1, 0, 0], - ....: [ 0,-1, 1,-1, 0], - ....: [ 0, 0,-1, 1,-1], - ....: [-1, 0, 0,-1, 1]]); R10 + ....: [[ 1,-1, 0, 0,-1], + ....: [-1, 1,-1, 0, 0], + ....: [ 0,-1, 1,-1, 0], + ....: [ 0, 0,-1, 1,-1], + ....: [-1, 0, 0,-1, 1]]); R10 [ 1 -1 0 0 -1] [-1 1 -1 0 0] [ 0 -1 1 -1 0] @@ -3474,11 +3476,11 @@ cdef class R10Node(DecompositionNode): False sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 1, 0, 0, 1], - ....: [1, 1,-1, 0, 0], - ....: [0, 1,-1,-1, 0], - ....: [0, 0, 1, 1, 1], - ....: [1, 0, 0, 1, 1]]); R10 + ....: [[1, 1, 0, 0, 1], + ....: [1, 1,-1, 0, 0], + ....: [0, 1,-1,-1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); R10 [ 1 1 0 0 1] [ 1 1 -1 0 0] [ 0 1 -1 -1 0] @@ -3493,11 +3495,11 @@ cdef class R10Node(DecompositionNode): False sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(GF(2), 5, 5, sparse=True), - ....: [[1, 1, 0, 0, 1], - ....: [1, 1,-1, 0, 0], - ....: [0, 1,-1,-1, 0], - ....: [0, 0, 1, 1, 1], - ....: [1, 0, 0, 1, 1]]); R10 + ....: [[1, 1, 0, 0, 1], + ....: [1, 1,-1, 0, 0], + ....: [0, 1,-1,-1, 0], + ....: [0, 0, 1, 1, 1], + ....: [1, 0, 0, 1, 1]]); R10 [1 1 0 0 1] [1 1 1 0 0] [0 1 1 1 0] @@ -3524,11 +3526,11 @@ cdef class R10Node(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[1, 1, 1, 1, 1], - ....: [1, 1, 1, 0, 0], - ....: [1, 0, 1, 1, 0], - ....: [1, 0, 0, 1, 1], - ....: [1, 1, 0, 0, 1]]); R10 + ....: [[1, 1, 1, 1, 1], + ....: [1, 1, 1, 0, 0], + ....: [1, 0, 1, 1, 0], + ....: [1, 0, 0, 1, 1], + ....: [1, 1, 0, 0, 1]]); R10 [1 1 1 1 1] [1 1 1 0 0] [1 0 1 1 0] @@ -3541,36 +3543,36 @@ cdef class R10Node(DecompositionNode): R10: Regular matroid of rank 5 on 10 elements with 162 bases sage: certificate._isomorphism() {'a': 0, - 'b': 1, - 'c': 2, - 'd': 'a', - 'e': 'b', - 'f': 4, - 'g': 'c', - 'h': 'e', - 'i': 3, - 'j': 'd'} - sage: result, certificate = R10.is_totally_unimodular(certificate=True) + 'b': 1, + 'c': 2, + 'd': 'a', + 'e': 'b', + 'f': 4, + 'g': 'c', + 'h': 'e', + 'i': 3, + 'j': 'd'} + sage: result, certificate = R10.is_totally_unimodular(certificate=True) sage: certificate._matroid() R10: Regular matroid of rank 5 on 10 elements with 162 bases sage: certificate._isomorphism() {'a': 0, - 'b': 1, - 'c': 2, - 'd': 5, - 'e': 6, - 'f': 4, - 'g': 7, - 'h': 9, - 'i': 3, - 'j': 8} + 'b': 1, + 'c': 2, + 'd': 5, + 'e': 6, + 'f': 4, + 'g': 7, + 'h': 9, + 'i': 3, + 'j': 8} sage: R10 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 5, 5, sparse=True), - ....: [[ 1,-1, 0, 0,-1], - ....: [-1, 1,-1, 0, 0], - ....: [ 0,-1, 1,-1, 0], - ....: [ 0, 0,-1, 1,-1], - ....: [-1, 0, 0,-1, 1]]); R10 + ....: [[ 1,-1, 0, 0,-1], + ....: [-1, 1,-1, 0, 0], + ....: [ 0,-1, 1,-1, 0], + ....: [ 0, 0,-1, 1,-1], + ....: [-1, 0, 0,-1, 1]]); R10 [ 1 -1 0 0 -1] [-1 1 -1 0 0] [ 0 -1 1 -1 0] @@ -3622,15 +3624,15 @@ cdef class PivotsNode(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True) sage: certificate PivotsNode (9×12) @@ -3648,15 +3650,15 @@ cdef class PivotsNode(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True) sage: certificate PivotsNode (9×12) @@ -3681,15 +3683,15 @@ cdef class PivotsNode(DecompositionNode): sage: from sage.matrix.matrix_cmr_sparse import Matrix_cmr_chr_sparse sage: R12 = Matrix_cmr_chr_sparse(MatrixSpace(ZZ, 9, 12, sparse=True), - ....: [[1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - ....: [0, 0, 0, 1, -1, 0, 0, 0, 1 , 1, 1, 1], - ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], - ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], - ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], - ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], - ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], - ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) + ....: [[ 1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 1, -1, 0, 0, 0, 1, 1, 1, 1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + ....: [ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], + ....: [ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0], + ....: [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, -1], + ....: [ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ....: [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]]) sage: result, certificate = R12.is_totally_unimodular(certificate=True) sage: certificate PivotsNode (9×12)