├── .github
└── workflows
│ ├── ci-sage.yml
│ ├── ghpages.yml
│ └── unittests.yml
├── .gitignore
├── .gitmodules
├── .travis.yml
├── CMakeLists.txt
├── LICENSE
├── README
├── cmake
├── CMRConfig.cmake.in
├── FindGMP.cmake
├── FindGTestGit.cmake
├── FindGTestSources.cmake
└── FindGUROBI.cmake
├── doc
├── CMakeLists.txt
├── TEMPLATE.md
├── balanced.md
├── build.md
├── camion.md
├── changes.md
├── consecutive-ones.md
├── ctu.md
├── equimodular.md
├── file-formats.md
├── generators.md
├── graphic.md
├── header.html
├── index.md
├── k_ary.md
├── logo.png
├── matroids.md
├── max-flow-min-cut.md
├── named.md
├── network.md
├── perfect.md
├── regular.md
├── series-parallel.md
├── seymour.md
├── staircase-compatibility.md
├── totally-balanced.md
├── tu.md
└── utilities.md
├── experiments
├── config.py
├── config_modwheel.py
├── config_network.py
├── config_rndcamion.py
├── eval_modwheel.py
├── eval_parse.py
├── gen_modwheel.py
├── gen_modwheel.sbatch
├── gen_network.py
├── gen_network.sbatch
├── gen_rndcamion.py
├── gen_rndcamion.sbatch
├── graphic.py
├── run_modwheel.py
├── run_modwheel.sbatch
├── run_network.py
├── run_network.sbatch
├── run_rndcamion.py
├── run_rndcamion.sbatch
└── series_parallel.py
├── include
└── cmr
│ ├── balanced.h
│ ├── camion.h
│ ├── config.h.in
│ ├── ctu.h
│ ├── element.h
│ ├── env.h
│ ├── equimodular.h
│ ├── graph.h
│ ├── graphic.h
│ ├── linear_algebra.h
│ ├── matrix.h
│ ├── matroid.h
│ ├── named.h
│ ├── network.h
│ ├── regular.h
│ ├── separation.h
│ ├── series_parallel.h
│ ├── seymour.h
│ └── tu.h
├── src
├── cmr
│ ├── balanced.c
│ ├── bipartite_graph.c
│ ├── bipartite_graph.h
│ ├── block_decomposition.c
│ ├── block_decomposition.h
│ ├── camion.c
│ ├── camion_internal.h
│ ├── ctu.c
│ ├── densematrix.c
│ ├── densematrix.h
│ ├── element.c
│ ├── env.c
│ ├── env_internal.h
│ ├── equimodular.c
│ ├── graph.c
│ ├── graphic.c
│ ├── graphic_internal.h
│ ├── hashtable.c
│ ├── hashtable.h
│ ├── heap.c
│ ├── heap.h
│ ├── hereditary_property.c
│ ├── hereditary_property.h
│ ├── linear_algebra.c
│ ├── linear_algebra_internal.h
│ ├── listmatrix.c
│ ├── listmatrix.h
│ ├── matrix.c
│ ├── matrix_internal.h
│ ├── matroid.c
│ ├── named.c
│ ├── network.c
│ ├── regular.c
│ ├── regular_dec.c
│ ├── regularity_graphic.c
│ ├── regularity_nested_minor_sequence.c
│ ├── regularity_onesum.c
│ ├── regularity_partition.c
│ ├── regularity_r10.c
│ ├── regularity_series_parallel.c
│ ├── regularity_simple_three_separations.c
│ ├── regularity_threesum.c
│ ├── separation.c
│ ├── series_parallel.c
│ ├── seymour.c
│ ├── seymour_internal.h
│ ├── sign.c
│ ├── sort.c
│ ├── sort.h
│ └── tu.c
├── gen
│ ├── graphic_gen.c
│ ├── gurobi_extract.c
│ ├── network_gen.c
│ ├── random_gen.c
│ ├── random_perturb.c
│ ├── series_parallel_gen.c
│ └── wheel_gen.c
└── main
│ ├── balanced_main.c
│ ├── camion_main.c
│ ├── ctu_main.c
│ ├── equimodular_main.c
│ ├── graphic_main.c
│ ├── k_ary_main.c
│ ├── matrix_main.c
│ ├── named_main.c
│ ├── network_main.c
│ ├── regular_main.c
│ ├── series_parallel_main.c
│ └── tu_main.c
└── test
├── CMakeLists.txt
├── common.c
├── common.h
├── test_balanced.cpp
├── test_block_decomposition.cpp
├── test_camion.cpp
├── test_ctu.cpp
├── test_equimodular.cpp
├── test_graph.cpp
├── test_graphic.cpp
├── test_hashtable.cpp
├── test_main.cpp
├── test_matrix.cpp
├── test_matroid.cpp
├── test_network.cpp
├── test_regular.cpp
├── test_separation.cpp
├── test_series_parallel.cpp
└── test_tu.cpp
/.github/workflows/ci-sage.yml:
--------------------------------------------------------------------------------
1 | name: Run Sage CI
2 |
3 | ## This GitHub Actions workflow provides:
4 | ##
5 | ## - portability testing, by building and testing this project on many platforms
6 | ## (Linux variants)
7 | ##
8 | ## - continuous integration, by building and testing other software
9 | ## that depends on this project.
10 | ##
11 | ## It runs on every push to the GitHub repository.
12 | ##
13 | ## The testing can be monitored in the "Actions" tab of the GitHub repository.
14 | ##
15 | ## After all jobs have finished (or are canceled) and a short delay,
16 | ## tar files of all logs are made available as "build artifacts".
17 | ##
18 | ## This GitHub Actions workflow uses the portability testing framework
19 | ## of SageMath (https://www.sagemath.org/). For more information, see
20 | ## https://doc.sagemath.org/html/en/developer/portability_testing.html
21 |
22 | ## The workflow consists of two jobs:
23 | ##
24 | ## - First, it builds a source distribution of the project
25 | ## and generates a script "update-pkgs.sh". It uploads them
26 | ## as a build artifact named upstream.
27 | ##
28 | ## - Second, it checks out a copy of the SageMath source tree.
29 | ## It downloads the upstream artifact and replaces the project's
30 | ## package in the SageMath distribution by the newly packaged one
31 | ## from the upstream artifact, by running the script "update-pkgs.sh".
32 | ## Then it builds a small portion of the Sage distribution.
33 | ##
34 | ## Many copies of the second step are run in parallel for each of the tested
35 | ## systems/configurations.
36 |
37 | on:
38 | pull_request:
39 | branches:
40 | - main
41 | push:
42 | tags:
43 | branches:
44 | - main
45 | workflow_dispatch:
46 | # Allow to run manually
47 |
48 | concurrency:
49 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
50 | cancel-in-progress: true
51 |
52 | env:
53 | # Ubuntu packages to install so that the project can build an sdist
54 | DIST_PREREQ:
55 | # Name of this project in the Sage distribution
56 | SPKG: cmr
57 | REMOVE_PATCHES:
58 |
59 | jobs:
60 |
61 | dist:
62 | runs-on: ubuntu-latest
63 | steps:
64 | - name: Check out ${{ env.SPKG }}
65 | uses: actions/checkout@v4
66 | with:
67 | path: build/pkgs/${{ env.SPKG }}/src
68 | - name: Install prerequisites
69 | run: |
70 | sudo DEBIAN_FRONTEND=noninteractive apt-get update
71 | sudo DEBIAN_FRONTEND=noninteractive apt-get install $DIST_PREREQ
72 | - name: Run make dist, prepare upstream artifact
73 | run: |
74 | (cd build/pkgs/${{ env.SPKG }}/src && git archive --format=tar.gz --prefix=${{ env.SPKG }}-git/ HEAD > ${{ env.SPKG }}-git.tar.gz) \
75 | && mkdir -p upstream && cp build/pkgs/${{ env.SPKG }}/src/*.tar.gz upstream/${{ env.SPKG }}-git.tar.gz \
76 | && echo "sage-package create ${{ env.SPKG }} --version git --tarball ${{ env.SPKG }}-git.tar.gz --type=standard" > upstream/update-pkgs.sh \
77 | && if [ -n "${{ env.REMOVE_PATCHES }}" ]; then echo "(cd ../build/pkgs/${{ env.SPKG }}/patches && rm -f ${{ env.REMOVE_PATCHES }}; :)" >> upstream/update-pkgs.sh; fi \
78 | && ls -l upstream/
79 | - uses: actions/upload-artifact@v4
80 | with:
81 | path: upstream
82 | name: upstream
83 |
84 | linux:
85 | uses: passagemath/passagemath/.github/workflows/docker.yml@main
86 | with:
87 | # Extra system packages to install. See available packages at
88 | # https://github.com/passagemath/passagemath/tree/main/build/pkgs
89 | extra_sage_packages: "patch cmake gfortran openblas"
90 | # Sage distribution packages to build
91 | targets: SAGE_CHECK=no SAGE_CHECK_PACKAGES="cmr" cmr
92 | # Standard setting: Test the current HEAD of passagemath:
93 | sage_repo: passagemath/passagemath
94 | sage_ref: main
95 | upstream_artifact: upstream
96 | # Docker targets (stages) to tag
97 | docker_targets: "with-targets"
98 | # We prefix the image name with the SPKG name ("cmr_") to avoid the error
99 | # 'Package "sage-docker-..." is already associated with another repository.'
100 | docker_push_repository: ghcr.io/${{ github.repository }}/cmr_
101 | needs: [dist]
102 |
103 | macos:
104 | uses: passagemath/passagemath/.github/workflows/macos.yml@main
105 | with:
106 | # Extra system packages to install. See available packages at
107 | # https://github.com/passagemath/passagemath/tree/main/build/pkgs
108 | extra_sage_packages: "patch cmake gfortran openblas"
109 | # Sage distribution packages to build
110 | targets: SAGE_CHECK=no SAGE_CHECK_PACKAGES="cmr" cmr
111 | # Standard setting: Test the current beta release of Sage:
112 | sage_repo: passagemath/passagemath
113 | sage_ref: main
114 | upstream_artifact: upstream
115 | needs: [dist]
116 |
--------------------------------------------------------------------------------
/.github/workflows/ghpages.yml:
--------------------------------------------------------------------------------
1 | name: Doxygen CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | with:
13 | submodules: true
14 | - name: Install requirements
15 | run: |
16 | sudo apt-get update
17 | sudo apt-get install -y libboost-all-dev cmake doxygen
18 | - name: Create build directory
19 | run: mkdir build-debug-generators
20 | - name: Configure
21 | run: cd build-debug-generators && cmake .. -DCMAKE_BUILD_TYPE=Debug -DGENERATORS=on
22 | - name: Compile
23 | run: cd build-debug-generators && make
24 | - name: Test
25 | env:
26 | CTEST_OUTPUT_ON_FAILURE: 1
27 | run: cd build-debug-generators && make test
28 | - name: Create documentation
29 | run: cd build-debug-generators && make doc
30 | - name: Cleanup submodules
31 | run: git reset --hard HEAD && git submodule sync && git submodule deinit -f . || true
32 | - name: Checkout gh-pages
33 | uses: actions/checkout@v4
34 | with:
35 | ref: "gh-pages"
36 | clean: false
37 | - name: Move and commit files
38 | run: |
39 | git config --global user.name github-actions
40 | git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com'
41 | git remote set-url origin https://x-access-token:${{ secrets.DEPLOY_TOKEN }}@github.com/$GITHUB_REPOSITORY
42 | cp -rp ./build-debug-generators/doc/html/* .
43 | rm -rf ./build-debug-generators
44 | ls -lah
45 | git add .
46 | git commit -m "Documentation for $GITHUB_SHA" || true
47 | git push --force || true
48 |
--------------------------------------------------------------------------------
/.github/workflows/unittests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches: [ main, develop ]
6 | pull_request:
7 | branches: [ main, develop ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Install gtest manually
14 | run: sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake CMakeLists.txt && sudo make && sudo cp lib/*.a /usr/lib && sudo ln -s /usr/lib/libgtest.a /usr/local/lib/libgtest.a && sudo ln -s /usr/lib/libgtest_main.a /usr/local/lib/libgtest_main.a
15 | - uses: actions/checkout@v1
16 | - name: configure debug build
17 | run: mkdir build-debug && cd build-debug && cmake -DCMAKE_BUILD_TYPE=Debug ..
18 | - name: compile debug build
19 | run: cd build-debug && make
20 | - name: Run debug tests
21 | run: cd build-debug && ctest && ctest --rerun-failed --output-on-failure
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build*
2 | *.kdev4
3 | *.csv
4 | *.ods
5 | __pycache__
6 | experiments/network/
7 | experiments/modwheel/
8 | experiments/rndcamion/
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "doc/doxygen-awesome-css"]
2 | path = doc/doxygen-awesome-css
3 | url = https://github.com/jothepro/doxygen-awesome-css.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | branches:
4 | only:
5 | - master
6 |
7 | addons:
8 | apt:
9 | packages:
10 | - cmake
11 | - doxygen
12 | - libboost-all-dev
13 |
14 | script:
15 | - mkdir build-debug-generators
16 | - cd build-debug-generators
17 | - cmake .. -DCMAKE_BUILD_TYPE=Debug -DGENERATORS=on
18 | - make
19 | - make test
20 | - cd ..
21 | - mkdir build-release-generators
22 | - cd build-release-generators
23 | - cmake .. -DCMAKE_BUILD_TYPE=Release -DGENERATORS=on
24 | - make
25 | - make test
26 | - cd ..
27 | - mkdir build-release
28 | - cd build-release
29 | - cmake .. -DCMAKE_BUILD_TYPE=Release
30 | - make
31 | - make test
32 | - make doc
33 |
34 | deploy:
35 | provider: pages
36 | skip_cleanup: true
37 | local_dir: build-release/doc/html
38 | github_token: $GH_REPO_TOKEN
39 | on:
40 | branch: master
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 by CMR Authors: https://discopt.github.io/cmr/#authors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | 1. Create a build directory:
2 |
3 | mkdir build
4 |
5 | 2. Go to the build directory:
6 |
7 | cd build/
8 |
9 | 3. Configure the build:
10 |
11 | cmake ..
12 |
13 | 4. Compile:
14 |
15 | make
16 |
17 | 5. Use one of executables:
18 |
19 | ./cmr-camion # Camion's signing algorithm
20 | ./cmr-matrix # Basic matrix utililies (dense <-> sparse, transpose, submatrix, support)
21 | ./cmr-ctu # Recognition of complementary totally unimodular matrices
22 | ./cmr-graphic # Recognition and construction of graphic matrices
23 | ./cmr-network # Recognition and construction of network matrices
24 | ./cmr-tu # Recognition of totally unimodular matrices
25 | ./cmr-regular # Recognition of regular matrices / matroids
26 | ./cmr-k-ary # Extraction of large binary or ternary submatrices.
27 | ./cmr-equimodular # Recognition of (strongly) equimodular and unimodular matrices
28 | ./cmr-series-parallel # Recognition of series-parallel matrices
29 |
30 | 6. Optionally, you can also install the executables.
31 |
32 | make install
33 |
34 |
35 |
36 | If you configure cmake with -DGENERATORS=on then a couple of matrix generators are compiled.
37 | In particular, you can use
38 |
39 | ./cmr-extract-gurobi # Extract the coefficient matrix of a mixed-integer program.
40 |
41 |
--------------------------------------------------------------------------------
/cmake/CMRConfig.cmake.in:
--------------------------------------------------------------------------------
1 | get_filename_component(CMR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
2 | include(CMakeFindDependencyMacro)
3 |
4 | if(NOT TARGET CMR::CMR)
5 | include("${CMR_CMAKE_DIR}/CMRTargets.cmake")
6 | endif()
7 |
--------------------------------------------------------------------------------
/cmake/FindGMP.cmake:
--------------------------------------------------------------------------------
1 | # - Try to find the GMP libraries
2 | # This module defines:
3 | # GMP_FOUND - system has GMP lib
4 | # GMP_INCLUDE_DIR - the GMP include directory
5 | # GMP_LIBRARIES_DIR - directory where the GMP libraries are located
6 | # GMP_LIBRARIES - Link these to use GMP
7 |
8 | # TODO: support MacOSX
9 |
10 | include(FindPackageHandleStandardArgs)
11 |
12 | find_path(GMP_INCLUDE_DIR
13 | NAMES gmp.h
14 | HINTS ENV GMP_INC_DIR
15 | ENV GMP_DIR
16 | $ENV{GMP_DIR}/include
17 | PATH_SUFFIXES include
18 | DOC "The directory containing the GMP header files"
19 | )
20 |
21 | find_library(GMP_LIBRARY_RELEASE NAMES gmp libgmp-10 gmp-10 mpir
22 | HINTS ENV GMP_LIB_DIR
23 | ENV GMP_DIR
24 | $ENV{GMP_DIR}/lib
25 | PATH_SUFFIXES lib
26 | DOC "Path to the Release GMP library"
27 | )
28 |
29 | find_library(GMP_LIBRARY_DEBUG NAMES gmpd gmp libgmp-10 gmp-10 mpir
30 | HINTS ENV GMP_LIB_DIR
31 | ENV GMP_DIR
32 | $ENV{GMP_DIR}/include
33 | PATH_SUFFIXES lib
34 | DOC "Path to the Debug GMP library"
35 | )
36 |
37 | if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
38 | set(GMP_LIBRARIES ${GMP_LIBRARY_DEBUG})
39 | else()
40 | set(GMP_LIBRARIES ${GMP_LIBRARY_RELEASE})
41 | endif()
42 |
43 | # Attempt to load a user-defined configuration for GMP if couldn't be found
44 | if ( NOT GMP_INCLUDE_DIR OR NOT GMP_LIBRARIES)
45 | include( GMPConfig OPTIONAL )
46 | endif()
47 |
48 | find_package_handle_standard_args(GMP "DEFAULT_MSG" GMP_LIBRARIES GMP_INCLUDE_DIR)
49 |
--------------------------------------------------------------------------------
/cmake/FindGTestGit.cmake:
--------------------------------------------------------------------------------
1 | # FindGTestGit
2 | # ------------
3 | #
4 | # Download the sources of the Google C++ Testing Framework, build them and add them in a subdirectory.
5 | #
6 | # Sets variables from the subproject.
7 |
8 | message(STATUS "Using GTest sources from git repository.")
9 |
10 | # Create a cmake subproject for downloading in gtestgit-control/.
11 | file(WRITE ${CMAKE_BINARY_DIR}/gtestgit-control/CMakeLists.txt "\
12 | cmake_minimum_required(VERSION 3.5.0)
13 | project(gtestgit-control NONE)
14 | include(ExternalProject)
15 | ExternalProject_Add(googletest
16 | GIT_REPOSITORY https://github.com/google/googletest.git
17 | GIT_TAG main
18 | SOURCE_DIR \"${CMAKE_BINARY_DIR}/gtestgit-src\"
19 | BINARY_DIR \"${CMAKE_BINARY_DIR}/gtestgit-build\"
20 | CONFIGURE_COMMAND \"\"
21 | BUILD_COMMAND \"\"
22 | INSTALL_COMMAND \"\"
23 | TEST_COMMAND \"\"
24 | )")
25 |
26 | # Run cmake in gtestgit-control.
27 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
28 | RESULT_VARIABLE result
29 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/gtestgit-control )
30 | if(result)
31 | message(FATAL_ERROR "CMake step for FindGTestGit failed: ${result}")
32 | endif()
33 |
34 | # Build gtestgit-control.
35 | execute_process(COMMAND ${CMAKE_COMMAND} --build .
36 | RESULT_VARIABLE result
37 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/gtestgit-control )
38 | if(result)
39 | message(FATAL_ERROR "Build step for FindGTestGit failed: ${result}")
40 | endif()
41 |
42 | # Add subdirectory with sources in gtest-src and build in gtest-build.
43 | add_subdirectory(${CMAKE_BINARY_DIR}/gtestgit-src
44 | ${CMAKE_BINARY_DIR}/gtestgit-build
45 | EXCLUDE_FROM_ALL)
46 |
--------------------------------------------------------------------------------
/cmake/FindGTestSources.cmake:
--------------------------------------------------------------------------------
1 | # FindGTestSources
2 | # ----------------
3 | #
4 | # Locate the sources of the Google C++ Testing Framework, build them and add them in a subdirectory.
5 | #
6 | # Result variables
7 | # ^^^^^^^^^^^^^^^^
8 | #
9 | # This module will set the following variables in your project:
10 | #
11 | # ``GTESTSOURCES_FOUND``
12 | # Found the sources of the Google Testing framework
13 | # ``GTESTSOURCES_BASE``
14 | # the directory containing the sources of the Google Test headers
15 | #
16 | # In addition also sets variables from the subproject.
17 |
18 | find_path(GTESTSOURCES_BASE
19 | googletest/src/gtest-all.cc
20 | PATHS
21 | $ENV{GTESTSOURCES_ROOT}
22 | ${GTESTSOURCES_ROOT}
23 | HINTS
24 | /usr/src/googletest
25 | /usr/src/gtest
26 | )
27 | if(GTESTSOURCES_BASE)
28 | message(STATUS "Found GTest sources in ${GTESTSOURCES_BASE}.")
29 | set(GTESTSOURCES_FOUND TRUE)
30 | set(OLD_CMAKE_POLICY_DEFAULT_CMP0048 ${CMAKE_POLICY_DEFAULT_CMP0048})
31 | set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
32 |
33 | set(OLD_CMAKE_POLICY_DEFAULT_CMP0054 ${CMAKE_POLICY_DEFAULT_CMP0054})
34 | set(CMAKE_POLICY_DEFAULT_CMP0054 NEW)
35 |
36 | file(WRITE ${CMAKE_BINARY_DIR}/gtestsources-control/CMakeLists.txt "\
37 | cmake_minimum_required(VERSION 3.5.0)
38 | project(gtestsources-control NONE)
39 | include(ExternalProject)
40 | ExternalProject_Add(googletest
41 | SOURCE_DIR \"${GTESTSOURCES_BASE}\"
42 | BINARY_DIR \"${CMAKE_BINARY_DIR}/gtestsources-build\"
43 | CONFIGURE_COMMAND \"\"
44 | BUILD_COMMAND \"\"
45 | INSTALL_COMMAND \"\"
46 | TEST_COMMAND \"\"
47 | )")
48 | add_subdirectory(${GTESTSOURCES_BASE}
49 | ${CMAKE_BINARY_DIR}/gtestsources-build
50 | EXCLUDE_FROM_ALL)
51 | set(CMAKE_POLICY_DEFAULT_CMP0054 ${OLD_CMAKE_POLICY_DEFAULT_CMP0054})
52 | set(CMAKE_POLICY_DEFAULT_CMP0048 ${OLD_CMAKE_POLICY_DEFAULT_CMP0048})
53 | else()
54 | message(STATUS "Could not find GTestSources.")
55 | set(GTESTSOURCES_FOUND FALSE)
56 | endif()
57 |
--------------------------------------------------------------------------------
/cmake/FindGUROBI.cmake:
--------------------------------------------------------------------------------
1 | find_path(GUROBI_INCLUDE_DIRS
2 | NAMES gurobi_c.h
3 | HINTS ${GUROBI_DIR} $ENV{GUROBI_DIR}
4 | PATH_SUFFIXES linux64/include include)
5 |
6 | find_library( GUROBI_CXX_LIBRARY
7 | NAMES gurobi_c++ gurobi_stdc++
8 | HINTS ${GUROBI_DIR} $ENV{GUROBI_DIR}
9 | PATH_SUFFIXES linux64/lib lib)
10 |
11 | find_library(GUROBI_LIBRARY
12 | NAMES gurobi gurobi70 gurobi75 gurobi80 gurobi81 gurobi90 gurobi95 gurobi100
13 | HINTS ${GUROBI_DIR} $ENV{GUROBI_DIR}
14 | PATH_SUFFIXES linux64/lib lib)
15 |
16 | set(GUROBI_LIBRARIES ${GUROBI_LIBRARY} ${GUROBI_CXX_LIBRARY} )
17 |
18 | include(FindPackageHandleStandardArgs)
19 | find_package_handle_standard_args(GUROBI DEFAULT_MSG GUROBI_INCLUDE_DIRS GUROBI_LIBRARIES)
20 |
--------------------------------------------------------------------------------
/doc/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Find Doxygen package.
2 | find_package(Doxygen)
3 |
4 | if(DOXYGEN_FOUND)
5 | file(COPY
6 | ${CMAKE_SOURCE_DIR}/doc/doxygen-awesome-css
7 | ${CMAKE_SOURCE_DIR}/doc/header.html
8 | ${CMAKE_SOURCE_DIR}/doc/logo.png
9 | DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
10 | file(COPY
11 | ${CMAKE_SOURCE_DIR}/doc/header.html
12 | DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
13 | set(DOXYGEN_EXTRA_PACKAGES "amsmath" "amssymb" "mathtools" "amsfont")
14 | set(DOXYGEN_EXTRACT_ALL "yes")
15 | set(DOXYGEN_EXTRACT_STATIC "yes")
16 | set(DOXYGEN_USE_MATHJAX "yes")
17 | set(DOXYGEN_MATHJAX_RELPATH "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/")
18 | set(DOXYGEN_INCLUDE_GRAPH "no")
19 | set(DOXYGEN_INCLUDED_BY_GRAPH "no")
20 | set(DOXYGEN_HTML_HEADER "header.html")
21 | set(DOXYGEN_PROJECT_LOGO "logo.png")
22 | set(DOXYGEN_HTML_EXTRA_STYLESHEET "doxygen-awesome-css/doxygen-awesome.css")
23 | doxygen_add_docs(doc
24 | ${CMAKE_CURRENT_SOURCE_DIR}/index.md
25 | ${CMAKE_CURRENT_SOURCE_DIR}/balanced.md
26 | ${CMAKE_CURRENT_SOURCE_DIR}/build.md
27 | ${CMAKE_CURRENT_SOURCE_DIR}/camion.md
28 | ${CMAKE_CURRENT_SOURCE_DIR}/changes.md
29 | ${CMAKE_CURRENT_SOURCE_DIR}/consecutive-ones.md
30 | ${CMAKE_CURRENT_SOURCE_DIR}/ctu.md
31 | ${CMAKE_CURRENT_SOURCE_DIR}/k_ary.md
32 | ${CMAKE_CURRENT_SOURCE_DIR}/file-formats.md
33 | ${CMAKE_CURRENT_SOURCE_DIR}/graphic.md
34 | ${CMAKE_CURRENT_SOURCE_DIR}/generators.md
35 | ${CMAKE_CURRENT_SOURCE_DIR}/equimodular.md
36 | ${CMAKE_CURRENT_SOURCE_DIR}/matroids.md
37 | ${CMAKE_CURRENT_SOURCE_DIR}/max-flow-min-cut.md
38 | ${CMAKE_CURRENT_SOURCE_DIR}/named.md
39 | ${CMAKE_CURRENT_SOURCE_DIR}/network.md
40 | ${CMAKE_CURRENT_SOURCE_DIR}/perfect.md
41 | ${CMAKE_CURRENT_SOURCE_DIR}/regular.md
42 | ${CMAKE_CURRENT_SOURCE_DIR}/series-parallel.md
43 | ${CMAKE_CURRENT_SOURCE_DIR}/seymour.md
44 | ${CMAKE_CURRENT_SOURCE_DIR}/totally-balanced.md
45 | ${CMAKE_CURRENT_SOURCE_DIR}/tu.md
46 | ${CMAKE_CURRENT_SOURCE_DIR}/utilities.md
47 | ${CMAKE_SOURCE_DIR}/include/cmr
48 | ${CMAKE_SOURCE_DIR}/src/cmr
49 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
50 | COMMENT "Generating doxygen documentation in ${CMAKE_CURRENT_BINARY_DIR}.")
51 | else()
52 | message(WARNING "Could not find Doxygen. Generating a documentation is not supported.")
53 | endif()
54 |
--------------------------------------------------------------------------------
/doc/TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Description # {#shortcut}
2 |
3 | Definitions, basic tool description.
4 |
5 |
6 | ## Application ##
7 |
8 | The command
9 |
10 | cmr-NAME IN-MAT OUT-MAT [OPTION...]
11 |
12 | reads the input matrix and outputs a submatrix.
13 |
14 | **Options**:
15 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
16 | - `-o FORMAT` Format of file `OUT-MAT`; default: [dense](\ref dense-matrix).
17 | - `-t` Consider the transpose of the matrix.
18 | - `-O OUT-MAT` Write the ... matrix to file `OUT-MAT`; default: stdout.
19 | - `-N OUT-SUB` Write a minimal .. submatrix to file `OUT-SUB`; default: skip computation.
20 |
21 | **Advanced options**:
22 | - `--stats` Print statistics about the computation to stderr.
23 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
24 |
25 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
26 | If `IN-MAT` or `IN-FOO` is `-` then the matrix (resp. foo) is read from stdin.
27 | If `OUT-MAT` is `-` then the matrix is written to stdout.
28 |
29 | ### Algorithm ###
30 |
31 | The implemented algorithm...
32 | For a matrix \f$ M \in \{0,1\}^{m \times n}\f$ with \f$ k \f$ nonzeros it runs in \f$ \mathcal{O}( ? ) \f$ time.
33 |
34 | ### C Interface ###
35 |
36 | The corresponding function in the library is
37 |
38 | - CMRjobOnMatrix() does something.
39 |
40 | and is defined in \ref header.h.
41 |
42 | ...
43 |
--------------------------------------------------------------------------------
/doc/balanced.md:
--------------------------------------------------------------------------------
1 | # Balanced / Balanceable Matrices # {#balanced}
2 |
3 | A ternary matrix \f$ M \in \{-1,0,+1\}^{m \times n} \f$ is called **balanced** if it does not contain a square submatrix with two nonzero entries per row and per column in which the sum of all entries is 2 modulo 4.
4 | A binary matrix \f$ M \in \{0,1\}^{m \times n} \f$ is called **balanceable** if and its nonzero entries can be signed so that the resulting matrix is balanced.
5 |
6 | ## Recognizing Balanced Matrices ##
7 |
8 | The command
9 |
10 | cmr-balanced IN-MAT [OPTION...]
11 |
12 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is balanced.
13 |
14 | **Options:**
15 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
16 | - `-N NON-SUB` Write a minimal non-balanced submatrix to file `NON-SUB`; default: skip computation.
17 |
18 | **Advanced options:**
19 | - `--stats` Print statistics about the computation to stderr.
20 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
21 | - `--algorithm ALGO` Algorithm to use, among `enumerate` and `graph`; default: choose best.
22 | - `--no-series-parallel` Do not try series-parallel operations for preprocessing.
23 |
24 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
25 |
26 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
27 |
28 | If `NON-SUB` is `-` then the [submatrix](\ref file-formats-submatrix) is written to stdout.
29 |
30 | ## Algorithm ##
31 |
32 | Two types of algorithms exist for both, the binary and the ternary case.
33 | The first algorithm types enumerate subsets of rows and then finds subsets of columns such that the resulting submatrix defines an odd cycle.
34 | Its running time is exponential in the size of the matrix.
35 | The second algorithm types are the [polynomial-time algorithms](https://doi.org/10.1016/j.jctb.2005.02.006) by Giacomo Zambelli (Journal of Combinatorial Theory, Series B, 2005).
36 | They run in \f$ \mathcal{O}( (m+n)^9 ) \f$ time for binary matrices and in \f$ \mathcal{O}( (m+n)^{11} ) \f$ time for ternary matrices.
37 |
38 | \note Only the first algorithm is implemented so far.
39 |
40 | ## C Interface ##
41 |
42 | The corresponding function in the library is
43 |
44 | - CMRbalancedTest() tests a matrix for balancedness.
45 |
46 | and is defined in \ref balanced.h.
47 |
48 |
--------------------------------------------------------------------------------
/doc/build.md:
--------------------------------------------------------------------------------
1 | # Build instructions {#build}
2 |
3 | The library can be built using the [CMake build system](https://cmake.org/).
4 | A simple command sequence on Linux looks like this:
5 |
6 | mkdir build
7 | cd build
8 | cmake ..
9 | make
10 |
11 | Below you can find a list of all parameters for building CMR.
12 | As an optional step, one can execute unittests:
13 |
14 | make test
15 |
16 | The executables now reside in the current directory. One can also install them via
17 |
18 | make install
19 |
20 | **Build Parameters**
21 |
22 | - `-DCMAKE_BUILD_TYPE=Release` Compiles the code with optimization turned on. Make sue to use this if you need fast code for large matrices.
23 | - `-DGENERATORS=on` Builds [generator tools](\ref generators) for certain matrices.
24 | - `-DGMP=off` Disables large numbers; see \ref equimodular.
25 |
26 |
--------------------------------------------------------------------------------
/doc/camion.md:
--------------------------------------------------------------------------------
1 | # Camion's Signing Algorithm # {#camion}
2 |
3 | A key tool for the recognition of [network matrices](\ref network), [totally unimodular matrices](\ref tu) and [balanceable matrices](\ref balanced) is Camion's signing algorithm.
4 | Its input is a binary matrix \f$ M \in \{0,1\}^{m \times n} \f$ and it computes a ternary matrix \f$ M' \in \{-1,0,+1\}^{m \times n} \f$ with the same support, i.e., the same nonzero entries.
5 | The output matrix \f$ M' \f$ is guaranteed to be [balanced](\ref balanced) if (and only if) \f$ M \f$ was [balanceable](\ref balanced).
6 | This means that for every square submatrix of \f$ M' \f$ with two nonzero entries per row and per column the the sum of all entries is divisible by 4.
7 | The algorithm always outputs a **Camion-signed matrix**, regardless of whether the input matrix was balanceable.
8 | In particular, it does not recognize whether it deals with a balanceable matrix or not.
9 |
10 | If \f$ M \f$ is balanceable, then \f$ M' \f$ is unique up to scaling rows/columns with \f$ -1 \f$.
11 |
12 |
13 | ## Checking for being Camion-signed ##
14 |
15 | The command
16 |
17 | cmr-camion IN-MAT [OPTION]...
18 |
19 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is Camion-signed.
20 |
21 | **Options:**
22 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
23 | - `-N NON-SUB` Write a minimal non-Camion submatrix to file `NON-SUB`; default: skip computation.
24 |
25 | **Advanced options**:
26 | - `--stats` Print statistics about the computation to stderr.
27 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
28 |
29 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
30 |
31 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
32 |
33 | If `NON-SUB` is `-` then the [submatrix](\ref file-formats-submatrix) is written to stdout.
34 |
35 | ### Algorithm ###
36 |
37 | The implemented recognition algorithm is based on Section 18 of [A decomposition theory for matroids. V. Testing of matrix total unimodularity](https://doi.org/10.1016/0095-8956(90)90030-4) by Klaus Truemper (Journal of Combinatorial Theory, Series B, 1990).
38 | For a matrix \f$ M \in \{-1,0,1\}^{m \times n} \f$ it runs in \f$ \mathcal{O}( \min(m^2 \cdot n, m \cdot n^2) ) \f$ time.
39 |
40 | ### C Interface ###
41 |
42 | The corresponding function in the library is
43 |
44 | - CMRcamionTestSigns() tests a matrix for being Camion-signed.
45 |
46 | and is defined in \ref camion.h.
47 |
48 |
49 | ## Camion-signing a Matrix ##
50 |
51 | The command
52 |
53 | cmr-camion IN-MAT -S OUT-MAT [OPTION]...
54 |
55 | modifies the signs of the matrix given in file `IN-MAT` such that it is Camion-signed and writes the resulting new matrix to file `OUT-MAT`.
56 |
57 | **Options:**
58 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
59 | - `-o FORMAT` Format of file `OUT-MAT`; default: same as format of `IN-MAT`.
60 |
61 | **Advanced options**:
62 | - `--stats` Print statistics about the computation to stderr.
63 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
64 |
65 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
66 |
67 | If `IN-MAT` is `-` then the matrix is read from stdin.
68 |
69 | If `OUT-MAT` is `-` then the matrix is written to stdout.
70 |
71 | ### Algorithm ###
72 |
73 | The implemented algorithm is based on Section 18 of [A decomposition theory for matroids. V. Testing of matrix total unimodularity](https://doi.org/10.1016/0095-8956(90)90030-4) by Klaus Truemper (Journal of Combinatorial Theory, Series B, 1990).
74 | For a matrix \f$ M \in \{-1,0,1\}^{m \times n} \f$ it runs in \f$ \mathcal{O}( \min(m^2 \cdot n, m \cdot n^2) ) \f$ time.
75 |
76 | ### C Interface ###
77 |
78 | The corresponding function in the library is
79 |
80 | - CMRcamionComputeSigns() Computes a Camion-signed version of a given ternary matrix.
81 |
82 | and is defined in \ref camion.h.
83 |
--------------------------------------------------------------------------------
/doc/changes.md:
--------------------------------------------------------------------------------
1 | # Change Log # {#changes}
2 |
3 | - Revised the Seymour decomposition structure.
4 | - Fixed a bug in the code for printing dot-files for transposed graphic/network matrices; reported by Christopher Hojny.
5 | - Added a `timeLimit` parameter to all potentially time intensive functions.
6 | - Bugfix for the `timeLimit` parameter.
7 | - Added generator for wheel matrices.
8 | - Added first enumerative code for recognition of balanced matrices.
9 |
10 | ## Version 1.3 ##
11 |
12 | - Redesigned as [Combinatorial Matrix Recognition](\ref index) Library.
13 | - Added recognition of [(co)graphic](\ref graphic) and [(co)network](\ref network) matrices.
14 | - Added recognition of [series-parallel matrices](\ref series-parallel).
15 | - Moved all C++ code to internal implementation. The library interface is only in C.
16 | - Added generators for network, graphic and random matrices.
17 |
18 | ## Version 1.2 ##
19 |
20 | ### 1.2h (2019-09-27) ###
21 |
22 | - Bugfix in search for violating submatrix.
23 | - Added direct test for regularity of binary matroids.
24 |
25 | ### 1.2g (2019-08-15) ###
26 |
27 | - Added support for complement total unimodularity.
28 |
29 | ### 1.2f (2017-03-14) ###
30 |
31 | - Raise an error message if an integer overflow occurs during k-modularity check; reported by Filippo Quondam.
32 |
33 | ### 1.2e (2016-02-28) ###
34 |
35 | - Bugfix for violator search; reported by Bala Krishnamoorthy.
36 |
37 | ### 1.2d (2015-02-06) ###
38 |
39 | - Bugfix for memory bug; reported by Tobias Windisch.
40 |
41 | ### 1.2c (2014-05-08) ###
42 |
43 | - Compatibility fix for more recent boost library; fix by Volker Braun.
44 |
45 | ### 1.2b (2012-10-12) ###
46 |
47 | - Compatibility fix for Mac OS; reported by Yvon Sauvagneau.
48 |
49 | ### 1.2 (2012-04-13) ###
50 |
51 | - Official version for article [Implementation of a unimodularity test](https://doi.org/10.1007/s12532-012-0048-x) by Matthias Walter and Klaus Truemper (Mathematical Programming Computation, 2013).
52 | - Polymake users can now analyze the matroid decomposition.
53 |
54 | ## Version 1.1 (2012-02-09) ##
55 |
56 | - Bug in graphicness test. Older versions may produce wrong results; reported by Paulo Seijas.
57 | - Update for polymake version 2.11 by Marc Pfetsch.
58 |
59 | ## Version 1.0 (2011-06-13) ##
60 |
61 | - First release of the software.
62 |
63 | \anchor TUtest
64 | # TUtest Library #
65 |
66 | This library is the successor of the **TUtest** library, originally developed by Matthias Walter and Klaus Truemper for the recognition of [totally unimodular matrices](\ref tu).
67 | The new name and additional functionality are available since version 1.3.
68 |
--------------------------------------------------------------------------------
/doc/consecutive-ones.md:
--------------------------------------------------------------------------------
1 | # Consecutive Ones # {#consecutive-ones}
2 |
3 | A matrix \f$ M \in \{0,1\}^{m \times n} \f$ has the **consecutive ones property for columns** if there is a permutation of the columns such that the permuted matrix \f$ M' \in \{0,1\}^{m \times n} \f$ has the \f$ 1 \f$'s of each row consecutive.
4 | Similarly, \f$ M \in \{0,1\}^{m \times n} \f$ has the **consecutive ones property for rows** if \f$ M^{\mathsf{T}} \f$ has the consecutive ones property for columns.
5 |
6 |
--------------------------------------------------------------------------------
/doc/ctu.md:
--------------------------------------------------------------------------------
1 | # Complement Totally Unimodular Matrices # {#ctu}
2 |
3 | Consider a binary matrix \f$ M \in \{0,1\}^{m \times n} \f$.
4 | A **row complement** for row \f$ i \f$ is obtained by complementing all entries \f$ M_{r,c} \f$ with \f$ r \neq i \f$
5 | and \f$ M_{i,c} = 1 \f$.
6 | A **column complement** is defined as a row complement on the transpose matrix.
7 | A binary matrix \f$ M \f$ is **complement totally unimodular** if all matrices obtainable by successive row- and column complements are [totally unimodular](\ref tu).
8 | It turns out that all such matrices can be obtained already by at most one row complement and at most one column complement.
9 | Hence, complement total unimodularity can be checked by checking \f$ (m+1) \cdot (n+1) \f$ matrices for [total unimodularity](\ref tu).
10 |
11 | ## Recognizing Complement Totally Unimodular Matrices ##
12 |
13 | The command
14 |
15 | cmr-ctu IN-MAT [OPTION]...
16 |
17 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is complement totally unimodular.
18 |
19 | **Options**:
20 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
21 | - `-o FORMAT` Format of file `OUT-MAT`; default: same as for `IN-MAT`.
22 | - `-n OUT-OPS` Write complement operations that leads to a non-totally-unimodular matrix to file `OUT-OPS`; default: skip computation.
23 | - `-N OUT-MAT` Write a complemented matrix that is non-totally-unimodular to file `OUT-MAT`; default: skip computation.
24 |
25 | **Advanced options**:
26 | - `--stats` Print statistics about the computation to stderr.
27 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
28 |
29 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
30 |
31 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
32 |
33 | If `OUT-OPS` or `OUT-MAT` is `-` then the list of operations (resp. the [matrix](\ref file-formats-matrix)) is written to stdout.
34 |
35 | ### C Interface ###
36 |
37 | The corresponding function in the library is
38 |
39 | - CMRctuTest() tests a matrix for being complement totally unimodular.
40 |
41 | and is defined in \ref ctu.h.
42 |
43 |
44 | ## Applying Complement Operations ##
45 |
46 | The command
47 |
48 | cmr-ctu IN-MAT OUT-MAT [OPTION]...
49 |
50 | applies a sequence of row or column complement operations the matrix given in file `IN-MAT` and writes the result to `OUT-MAT`.
51 |
52 | **Options**:
53 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
54 | - `-o FORMAT` Format of file `OUT-MAT`; default: same as for `IN-MAT`.
55 | - `-r ROW` Apply row complement operation to row `ROW`.
56 | - `-c COLUMN` Apply column complement operation to column `COLUMN`.
57 |
58 | **Advanced options**:
59 | - `--stats` Print statistics about the computation to stderr.
60 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
61 |
62 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
63 | If `IN-MAT` is `-` then the matrix is read from stdin.
64 | If `OUT-MAT` is `-` then the matrix is written to stdout.
65 |
66 | ## C Interface ##
67 |
68 | The corresponding function in the library is
69 |
70 | - CMRctuComplementRowColumn() carries out a row- or column-complement operation for a matrix.
71 |
72 | and is defined in \ref ctu.h.
73 |
--------------------------------------------------------------------------------
/doc/equimodular.md:
--------------------------------------------------------------------------------
1 | # (Strongly) Equimodular and Unimodular Matrices # {#equimodular}
2 |
3 | Consider a matrix \f$ M \in \mathbb{Z}^{m \times n} \f$ of rank \f$ r \f$.
4 | The matrix \f$ M \f$ is called **equimodular** *with determinant gcd* \f$ k \in \{1,2,\dotsc \} \f$ if these two conditions are satisfied:
5 |
6 | - for some column basis \f$ B \subseteq \{1,2,\dotsc,n\} \f$ of \f$ M \f$, the greatest common divisor of the determinants of all \f$r \f$-by-\f$ r \f$ submatrices of \f$ M_{\star,B} \f$ is equal to \f$ k \f$.
7 | - The matrix \f$ X \f$ such that \f$ M = M_{\star,B} X \f$ is [totally unimodular](\ref tu).
8 |
9 | In case \f$ M \f$ has full row-rank, the first property requires that the determinant of any basis matrix shall be \f$ \pm k \f$, while the second property requires that \f$ M_{\star,B}^{-1} M \f$ is [totally unimodular](\ref tu).
10 | Otherwise, \f$ M_{\star,B} \f$ is not square, and hence the property is more technical.
11 |
12 | \note Equimodularity is independent of the choice of the column basis \f$ B \f$.
13 |
14 | Additionally, \f$ M \f$ is called **strongly equimodular** if \f$ M \f$ and \f$ M^{\textsf{T}} \f$ are both equimodular, which implies that they are equimodular for the same gcd determinants.
15 | The special cases with \f$ k = 1 \f$ are called **unimodular** and **strongly unimodular**, respectively.
16 |
17 | ## Usage ##
18 |
19 | The executable `cmr-equimodular` determines whether a given [matrix](\ref file-formats-matrix) \f$ M \f$ with determinant gcd \f$ k \f$.
20 |
21 | ./cmr-equimodular IN-MAT [OPTION]...
22 |
23 | **Options:**
24 | - `-i FORMAT` Format of of file `IN-MAT`; default: [dense](\ref dense-matrix).
25 | - `-t` Test \f$ M^{\textsf{T}} \f$ instead.
26 | - `-s` Test for strong equimodularity.
27 | - `-u` Test only for unimodularity, i.e., \f$ k = 1 \f$.
28 |
29 | **Advanced options**:
30 | - `--stats` Print statistics about the computation to stderr.
31 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
32 |
33 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
34 |
35 | If `IN-MAT` is `-`, then the input will be read from stdin.
36 |
37 | ## C Interface ##
38 |
39 | The functionality is defined in \ref equimodular.h.
40 | The main functions are:
41 |
42 | - CMRequimodularTest() tests a matrix for being equimodular.
43 | - CMRequimodularTestStrong() tests a matrix for being strongly equimodular.
44 | - CMRunimodularTest() tests a matrix for being unimodular.
45 | - CMRunimodularTestStrong() tests a matrix for being strongly unimodular.
46 |
--------------------------------------------------------------------------------
/doc/file-formats.md:
--------------------------------------------------------------------------------
1 | # File Formats # {#file-formats}
2 |
3 | ## Matrix File Formats ## {#file-formats-matrix}
4 |
5 | There are two accepted file formats for matrices.
6 |
7 | \anchor dense-matrix
8 | ### Dense Matrix ###
9 |
10 | The format **dense** is a text format in which a matrix \f$ A \in \mathbb{Z}^{m \times n} \f$ is represented as a whitespace-delimited list of \f$ m \f$, \f$ n \f$, and the \f$ m \cdot n \f$ entries \f$ A_{1,1} \f$, \f$ A_{1,2} \f$, etc..
11 | The matrix \f$ A = \begin{pmatrix} 1 & -1 & 0 \\ 0 & 1 & 1 \end{pmatrix} \f$ is represented as follows:
12 |
13 | 2 3
14 |
15 | 1 -1 0
16 | 0 1 1
17 |
18 | \anchor sparse-matrix
19 | ### Sparse Matrix ###
20 |
21 | The format **sparse** is a text format in which a matrix \f$ A \in \mathbb{Z}^{m \times n} \f$ with \f$ k \f$ non-zeros are represented as a whitespace-delimited list of \f$ m \f$, \f$ n \f$, \f$ k \f$ and \f$ k \f$ triples \f$ (r,c,v) \f$ for each nonzero value \f$ v \f$ in row \f$ r \f$ and column \f$ c \f$.
22 | Note that \f$ r \in \{1,2,\dotsc,m\} \f$ and \f$ c \in \{1,2,\dotsc,n\} \f$.
23 | The matrix \f$ A = \begin{pmatrix} 1 & -1 & 0 \\ 0 & 1 & 1 \end{pmatrix} \f$ is represented as follows:
24 |
25 | 2 3 4
26 |
27 | 1 1 1
28 | 1 2 -1
29 | 2 2 1
30 | 2 3 1
31 |
32 | ## Submatrices ## {#file-formats-submatrix}
33 |
34 | Several algorithms produce a submatrix of a matrix \f$ A \in \mathbb{Z}^{m \times n} \f$ as output.
35 | The corresponding format consists of three lines with whitespace-delimited integers.
36 | The first has the four entries \f$ m \f$, \f$ n \f$, \f$ r \f$, \f$ c \f$ for an \f$ r \f$-by-\f$ c \f$ submatrix of \f$ A \f$.
37 | The second line consists of \f$ r \f$ entries indicating the row subset (indexing starts at 1) and the third line consists of \f$ c \f$ entries indicating the column subset.
38 | The submatrix obtained from \f$ A = \begin{pmatrix} 1 & -1 & 0 \\ 0 & 1 & 1 \end{pmatrix} \f$ by removing the first column is represented as follows:
39 |
40 | 2 3 2 2
41 | 1 2
42 | 2 3
43 |
44 | In order to extract the actual submatrix, please use the [cmr-matrix](\ref utilities) command.
45 |
46 | ## Graph File Formats ##
47 |
48 | Currently, graphs can only be specified by means of edge lists.
49 |
50 | \anchor edge-list
51 | ### Edge List ###
52 |
53 | The format **edgelist** is a text format in which a graph \f$ G = (V,E) \f$ is represented as a line-separated list of edges.
54 | The line for each edge contains two or three tokens, separated by whitespace.
55 | The first two are names of nodes and the optional third specifies a row/column element.
56 | The graph \f$ G = (V,E) \f$ with nodes \f$ V = \{v,x,y,z\} \f$ and edges \f$ E = \{ \{v,x\}, \{v,y\}, \{v,z\}, \{x,y\}, \{y,z\}, \{z,x\} \} \f$, labeled as \f$ r_1, r_2, r_3, c_1, c_2, c_3 \f$, respectively, is represented as follows:
57 |
58 | v x r1
59 | v y r2
60 | v z r3
61 | x y c1
62 | y z c2
63 | z x c3
64 |
65 | Row/column element labels are useful for \ref graphic.
66 | In fact, the format represents a digraph, which is useful for \ref network.
67 |
68 | \anchor dot
69 | ### Dot ###
70 |
71 | The format **dot** is a text format for drawing graphs, e.g., via the [GraphViz](https://graphviz.org) toolbox.
72 | See [here](https://graphviz.org/doc/info/lang.html) for the language specification.
73 |
--------------------------------------------------------------------------------
/doc/graphic.md:
--------------------------------------------------------------------------------
1 | # Graphic / Cographic / Planar Matrices # {#graphic}
2 |
3 | Let \f$ G = (V,E) \f$ be a graph and let \f$ T \f$ be a spanning forest.
4 | The matrix \f$ M(G,T) \in \{0,1\}^{T \times (E \setminus T)} \f$ defined via
5 | \f[
6 | M(G,T)_{e,f} := \begin{cases}
7 | 1 & \text{if } e \text{ is contained in the unique cycle of } T \cup \{f\} \\
8 | 0 & \text{otherwise}
9 | \end{cases}
10 | \f]
11 | is called the **graphic matrix** of \f$ G \f$ with respect to \f$ T \f$.
12 | A binary matrix \f$ M \f$ is called **graphic** if there exists a graph \f$ G \f$ with a spanning forest \f$ T \f$ such that \f$ M = M(G,T) \f$.
13 | Moreover, \f$ M \f$ is called **cographic** if \f$ M^{\textsf{T}} \f$ is graphic, and
14 | it is called **planar** if it is graphic and cographic.
15 |
16 |
17 | ## Recognizing Graphic Matrices ##
18 |
19 | The command
20 |
21 | cmr-graphic IN-MAT [OPTION]...
22 |
23 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is (co)graphic.
24 |
25 | **Options**:
26 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
27 | - `-t` Test for being cographic; default: test for being graphic.
28 | - `-G OUT-GRAPH` Write a graph to file `OUT-GRAPH`; default: skip computation.
29 | - `-T OUT-TREE` Write a spanning tree to file `OUT-TREE`; default: skip computation.
30 | - `-D OUT-DOT` Write a dot file `OUT-DOT` with the graph and the spanning tree; default: skip computation.
31 |
32 | **Advanced options**:
33 | - `--stats` Print statistics about the computation to stderr.
34 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
35 |
36 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
37 |
38 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
39 |
40 | If `OUT-GRAPH`, `OUT-TREE`, `OUT-DOT` or `NON-SUB` is `-` then the graph (resp. the tree, dot file or non-(co)graphic [submatrix](\ref file-formats-submatrix)) is written to stdout.
41 |
42 | ### Algorithm ###
43 |
44 | The implemented recognition algorithm is based on [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).
45 | For a matrix \f$ M \in \{0,1\}^{m \times n}\f$ with \f$ k \f$ nonzeros it runs in \f$ \mathcal{O}( k \cdot \alpha(k, m) ) \f$ time, where \f$ \alpha(\cdot) \f$ denotes the inverse Ackerman function.
46 |
47 | ### C Interface ###
48 |
49 | The corresponding functions in the library are
50 |
51 | - CMRgraphicTestMatrix() tests a matrix for being graphic.
52 | - CMRgraphicTestTranspose() tests a matrix for being cographic.
53 |
54 | and are defined in \ref network.h.
55 |
56 |
57 | ## Computing graphic matrices ##
58 |
59 | The command
60 |
61 | cmr-graphic -c IN-GRAPH OUT-MAT [OPTION]...
62 |
63 | computes a (co)graphic [matrix](\ref file-formats-matrix) corresponding to the graph from file `IN-GRAPH` and writes it to `OUT-MAT`.
64 |
65 | **Options**:
66 | - `-o FORMAT` Format of file `OUT-MAT`; default: [dense](\ref dense-matrix).
67 | - `-t` Return the transpose of the graphic matrix.
68 | - `-T IN-TREE` Read a tree from file `IN-TREE`; default: use first specified arcs as tree edges.
69 |
70 | **Advanced options**:
71 | - `--stats` Print statistics about the computation to stderr.
72 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
73 |
74 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
75 |
76 | If `IN-GRAPH` or `IN-TREE` is `-` then the graph (resp. tree) is read from stdin.
77 |
78 | If `OUT-MAT` is `-` then the [matrix](\ref file-formats-matrix) is written to stdout.
79 |
80 | ### C Interface ###
81 |
82 | The corresponding function in the library is
83 |
84 | - CMRgraphicComputeMatrix() constructs a graphic matrix for a given graph.
85 |
86 | and is defined in \ref network.h.
87 |
--------------------------------------------------------------------------------
/doc/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | $projectname: $title
10 | $title
11 |
12 |
13 |
14 | $treeview
15 | $search
16 | $mathjax
17 |
18 | $extrastylesheet
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | $projectname
34 | $projectnumber
35 |
36 | $projectbrief
37 |
38 |
39 |
40 |
41 |
42 | $projectbrief
43 |
44 |
45 |
46 |
47 |
48 | $searchbox
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/doc/index.md:
--------------------------------------------------------------------------------
1 | # Combinatorial Matrix Recognition Library # {#index}
2 |
3 | This C/C++ library contains efficient implementations of various algorithms for recognizing combinatorial matrices.
4 | It is the successor of the [TUtest library](\ref TUtest).
5 | The following matrix classes can be recognized:
6 |
7 | - \ref tu
8 | - \ref network
9 | - \ref ctu
10 | - \ref equimodular
11 | - \ref balanced (currently only via enumerative methods)
12 |
13 | Moreover, [representation matrices](\ref matroids) for the following matroid classes can be recognized:
14 |
15 | - [Binary](\ref binary_regular) and [ternary](\ref tu) regular matroids
16 | - [Graphic, cographic and planar](\ref graphic) matroids
17 | - [Series-parallel](\ref series-parallel) matroids
18 |
19 | The following additional functionality is also part of the library:
20 |
21 | - \ref utilities
22 | - \ref k_ary
23 | - \ref camion
24 | - \ref named
25 |
26 | The library also contains various [instance generators](\ref generators).
27 |
28 | The following matrix/matroid classes are **planned**:
29 |
30 | - \ref totally-balanced
31 | - \ref perfect
32 | - \ref consecutive-ones
33 | - \ref max-flow-min-cut
34 |
35 | # Installation and Usage #
36 |
37 | The library can be found on [github](https://github.com/discopt/cmr/), or directly as a [ZIP Archive](https://github.com/discopt/cmr/archive/refs/heads/master.zip).
38 | The functionality can be used via command-line tools or via its C interface (see [build instructions](\ref build) for more information).
39 | There is one executable per matrix/matroid class.
40 | Its documentation and that of the interface can be found on the respective pages.
41 | The executables accept several \ref file-formats.
42 |
43 | Changes and bug fixes are listed [here](\ref changes).
44 |
45 | # License #
46 |
47 | The software is released under the [MIT License](https://en.wikipedia.org/wiki/MIT_License).
48 | Please cite the paper(s) corresponding to the respective tools.
49 |
50 | # Authors # {#authors}
51 |
52 | - [Rolf van der Hulst](https://people.utwente.nl/r.p.vanderhulst) (graphicness, network matrices)
53 | - Henk Kraaij (balancedness)
54 | - [Klaus Truemper](https://personal.utdallas.edu/~klaus/) (total unimodularity, regularity, complement total unimodularity)
55 | - [Matthias Walter](https://people.utwente.nl/m.walter) (maintainer)
56 |
57 | # Funding support
58 |
59 | - The software library acknowledges support from the Dutch Research Council (NWO) on grant number OCENW.M20.151 (11/2022-10/2026).
60 |
--------------------------------------------------------------------------------
/doc/k_ary.md:
--------------------------------------------------------------------------------
1 | # Matrix Entries Inspection # {#k_ary}
2 |
3 | This tool is useful for basic matrix inspection:
4 |
5 | - Test if the input matrix is integer.
6 | - Test if the input matrix is ternary, i.e, it has only entries in \f$ \{-1,0,+1\} \f$.
7 | - Test if the input matrix is binary, i.e, it has only entries in \f$ \{0,+1\} \f$.
8 |
9 |
10 | ## Recognizing Binary and Ternary Matrices ##
11 |
12 | The command
13 |
14 | cmr-k-ary IN-MAT [OPTION...]
15 |
16 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is integer (resp. binary or ternary).
17 |
18 | **Options**:
19 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
20 | - `-b` Test whether the matrix is binary, i.e., has entries in \f$ \{0,+1\} \f$.
21 | - `-t` Test whether the matrix is ternary, i.e., has entries in \f$ \{-1,0,+1\} \f$.
22 | - `-I` Test whether the matrix is integer.
23 | - `-e EPSILON` Allows rounding of numbers up to tolerance `EPSILON`; default: \f$ 10^{-9} \f$.
24 |
25 | **Advanced options**:
26 | - `--stats` Print statistics about the computation to stderr.
27 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
28 |
29 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
30 |
31 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
32 |
33 |
34 | ## Finding Large Binary or Ternary Submatrices ##
35 |
36 | The command
37 |
38 | cmr-k-ary IN-MAT -R OUT-SUB [OPTION...]
39 |
40 | finds a large binary (resp. ternary) [submatrix](\ref file-formats-matrix) of the [matrix](\ref file-formats-matrix) given in file `IN-MAT`.
41 |
42 | **Options:**
43 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
44 | - `-b` Find a large binary submatrix, i.e., one with only entries in \f$ \{0,+1\} \f$.
45 | - `-t` Find a large ternary submatrix, i.e., one with only entries in \f$ \{-1,0,+1\} \f$.
46 | - `-e EPSILON` Allows rounding of numbers up to tolerance `EPSILON`; default: \f$ 10^{-9} \f$.
47 |
48 | **Advanced options**:
49 | - `--stats` Print statistics about the computation to stderr.
50 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
51 |
52 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
53 |
54 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
55 |
56 | If `OUT-SUB` is `-` then the [submatrix](\ref file-formats-submatrix) is written to stdout.
57 |
58 | ## Algorithm ##
59 |
60 | The implemented algorithm successively removes a row or a column with the maximum number of forbidden entries.
61 |
--------------------------------------------------------------------------------
/doc/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discopt/cmr/acfda4fe72cb73eb68a7ed20ebfcf4fdb3027542/doc/logo.png
--------------------------------------------------------------------------------
/doc/matroids.md:
--------------------------------------------------------------------------------
1 | # Representation of Matroids # {#matroids}
2 |
3 | The matroid **represented** by a matrix \f$ M \in \mathbb{F}^{m \times n} \f$ has \f$ m + n \f$ elements that correspond to the columns of \f$ [ \mathbb{I} \mid M ] \f$.
4 | A subset of these columns is independent if and only if it is linearly independent over the field \f$ \mathbb{F} \f$.
5 | Applying a **pivot operation** (over \f$ \mathbb{F} \f$) and exchanging the corresponding row and column elements leaves
6 | the matroid unchanged.
7 | In CMR, pivots are carried out via \ref CMRchrmatBinaryPivot, \ref CMRchrmatBinaryPivots, \ref CMRchrmatTernaryPivot and \ref CMRchrmatTernaryPivots.
8 |
9 | ## Minors ##
10 |
11 | A **minor** of a represented matroid is another one obtained by **deleting** or **contracting** elements.
12 | An element associated with a row (resp. column) can be contracted (resp. deleted) by removing the corresponding matrix row (resp. column).
13 | 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.
14 |
15 | A minor of a matroid represented by matrix \f$ M \f$ is represented by means of a \ref CMR_MINOR object.
16 | It consists of a (potentially empty) array of pivots and a \ref CMR_SUBMAT object indicating a submatrix \f$ M' \f$ of the matrix obtained from \f$ M \f$ after applying the pivots.
17 | Moreover, the **type** field indicates a certain structure of \f$ M' \f$:
18 |
19 | - A [determinant](\ref CMR_MINOR_TYPE_DETERMINANT) type indicates that \f$ M' \f$ is a submatrix of \f$ M \f$ with \f$ |\det(M')| \geq 2 \f$.
20 | In particular, no pivots are applied.
21 | - A [Fano](\ref CMR_MINOR_TYPE_FANO) type indicates that \f$ M' \f$ represents the Fano matroid \f$ F_7 \f$.
22 | - A [Fano-dual](\ref CMR_MINOR_TYPE_FANO_DUAL) type indicates that \f$ M' \f$ represents the dual \f$ F_7^\star \f$ of the Fano matroid.
23 | - A [K5](\ref CMR_MINOR_TYPE_K5) type indicates that \f$ M' \f$ represents the graphic matroid \f$ M(K_5) \f$ of the complete graph \f$ K_5 \f$.
24 | - A [K5-dual](\ref CMR_MINOR_TYPE_K5_DUAL) type indicates that \f$ M' \f$ represents the dual matroid \f$ M(K_5)^\star \f$ of the complete graph \f$ K_5 \f$.
25 | - A [K33](\ref CMR_MINOR_TYPE_K33) type indicates that \f$ M' \f$ represents the graphic matroid \f$ M(K_{3,3}) \f$ of the complete bipartite graph \f$ K_{3,3} \f$.
26 | - A [K33-dual](\ref CMR_MINOR_TYPE_K33_DUAL) type indicates that \f$ M' \f$ represents the dual matroid \f$ M(K_{3,3})^\star \f$ of the complete bipartite graph \f$ K_{3,3} \f$.
27 |
--------------------------------------------------------------------------------
/doc/max-flow-min-cut.md:
--------------------------------------------------------------------------------
1 | # Max-Flow-Min-Cut Matroids # {#max-flow-min-cut}
2 |
3 | See [here](https://doi.org/10.1287/moor.12.1.72) for a definition.
4 |
--------------------------------------------------------------------------------
/doc/named.md:
--------------------------------------------------------------------------------
1 | # Named Matrices # {#named}
2 |
3 | There exist several matrices that play a special role in theory.
4 |
5 | The command
6 |
7 | cmr-named IN-MAT [OPTION]...
8 |
9 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is (up to row/column permutations) one of the named matrices below.
10 |
11 | **Representation matrices of:**
12 | - `R_10` regular matroid \f$ R_{10} \f$
13 |
14 | **Variants (can be combined):**
15 | - `
* ` refers to the dual matroid.
16 | - `.` refers to a specific representation matrix, \f$ k = 1,2, \dots \f$
17 |
18 | **Other matrices:**
19 | - `I_` Identity matrix of order SIZE.
20 |
21 | **Options:**
22 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
23 | - `-e EPSILON` Allows rounding of numbers up to tolerance EPSILON; default: \f$ 10^{-9} \f$.
24 |
25 |
26 |
27 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
28 |
29 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
30 |
31 | ### Algorithm ###
32 |
33 | The implemented algorithm is based on Section 18 of [A decomposition theory for matroids. V. Testing of matrix total unimodularity](https://doi.org/10.1016/0095-8956(90)90030-4) by Klaus Truemper (Journal of Combinatorial Theory, Series B, 1990).
34 | For a matrix \f$ M \in \{-1,0,1\}^{m \times n} \f$ it runs in \f$ \mathcal{O}( \min(m^2 \cdot n, m \cdot n^2) ) \f$ time.
35 |
36 | ### C Interface ###
37 |
38 | The corresponding function in the library is
39 |
40 | - CMRcamionComputeSigns() Computes a Camion-signed version of a given ternary matrix.
41 |
42 | and is defined in \ref camion.h.
43 |
--------------------------------------------------------------------------------
/doc/network.md:
--------------------------------------------------------------------------------
1 | # Network Matrices # {#network}
2 |
3 | Let \f$ D = (V,A) \f$ be a digraph and let \f$ T \f$ be an (arbitrarily) directed spanning forest of the underlying undirected graph.
4 | The matrix \f$ M(D,T) \in \{-1,0,1\}^{T \times (A \setminus T)} \f$ defined via
5 | \f[
6 | M(D,T)_{a,(v,w)} := \begin{cases}
7 | +1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ forwardly}, \\
8 | -1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ backwardly}, \\
9 | 0 & \text{otherwise}
10 | \end{cases}
11 | \f]
12 | is called the **network matrix** of \f$ D \f$ with respect to \f$ T \f$.
13 | A matrix \f$ M \f$ is called **network matrix** if there exists a digraph \f$ D \f$ with a directed spanning forest \f$ T \f$ such that \f$ M = M(D,T) \f$.
14 | Moreover, \f$ M \f$ is called **conetwork matrix** if \f$ M^{\textsf{T}} \f$ is a network matrix.
15 |
16 |
17 | ## Recognizing Network Matrices ##
18 |
19 | The command
20 |
21 | cmr-network IN-MAT [OPTION]...
22 |
23 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is (co)network.
24 |
25 | **Options**:
26 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
27 | - `-t` Test for being conetwork; default: test for being network.
28 | - `-G OUT-GRAPH` Write a digraph to file `OUT-GRAPH`; default: skip computation.
29 | - `-T OUT-TREE` Write a directed spanning tree to file `OUT-TREE`; default: skip computation.
30 | - `-D OUT-DOT` Write a dot file `OUT-DOT` with the digraph and the directed spanning tree; default: skip computation.
31 |
32 | **Advanced options**:
33 | - `--stats` Print statistics about the computation to stderr.
34 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
35 |
36 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
37 |
38 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
39 |
40 | If `OUT-GRAPH`, `OUT-TREE`, `OUT-DOT` or `NON-SUB` is `-` then the graph (resp. the tree, dot file or non-(co)network [submatrix](\ref file-formats-submatrix)) is written to stdout.
41 |
42 | ### Algorithm ###
43 |
44 | The implemented recognition algorithm first tests the support matrix of \f$ M \f$ for being [(co)graphic](\ref graphic) and uses \ref camion for testing whether \f$ M \f$ is signed correctly.
45 |
46 | ### C Interface ###
47 |
48 | The corresponding functions in the library are
49 |
50 | - CMRnetworkTestMatrix() tests a matrix for being network.
51 | - CMRnetworkTestTranspose() tests a matrix for being conetwork.
52 |
53 | and are defined in \ref network.h.
54 |
55 |
56 | ## Computing network matrices ##
57 |
58 | The command
59 |
60 | cmr-network -c IN-GRAPH OUT-MAT [OPTION]...
61 |
62 | computes a (co)network [matrix](\ref file-formats-matrix) corresponding to the digraph from file `IN-GRAPH` and writes it to `OUT-MAT`.
63 |
64 | **Options**:
65 | - `-o FORMAT` Format of file `OUT-MAT`; default: [dense](\ref dense-matrix).
66 | - `-t` Return the transpose of the network matrix.
67 | - `-T IN-TREE` Read a directed tree from file `IN-TREE`; default: use first specified arcs as tree edges.
68 |
69 | **Advanced options**:
70 | - `--stats` Print statistics about the computation to stderr.
71 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
72 |
73 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
74 |
75 | If `IN-GRAPH` or `IN-TREE` is `-` then the digraph (resp. directed tree) is read from stdin.
76 |
77 | If `OUT-MAT` is `-` then the [matrix](\ref file-formats-matrix) is written to stdout.
78 |
79 | ### C Interface ###
80 |
81 | The corresponding function in the library is
82 |
83 | - CMRnetworkComputeMatrix() constructs a network matrix for a given digraph.
84 |
85 | and is defined in \ref network.h.
86 |
--------------------------------------------------------------------------------
/doc/perfect.md:
--------------------------------------------------------------------------------
1 | # Perfect Matrices # {#perfect}
2 |
3 | A matrix \f$ M \in \{0,1\}^{m \times n} \f$ is called **perfect** if it is the clique-node incidence matrix of a [perfect graph](https://en.wikipedia.org/wiki/Perfect_graph).
4 | In [A Characterization of Perfect Matrices](https://doi.org/10.1016/S0304-0208(08)72932-3) by Manfred W. Padberg (North-Holland Mathematics Studies, 1984) a characterization in terms of forbidden submatrices is provided.
5 |
--------------------------------------------------------------------------------
/doc/regular.md:
--------------------------------------------------------------------------------
1 | # Binary Regular Matrices # {#binary_regular}
2 |
3 | A matrix \f$ M \in \{0,1\}^{m \times n} \f$ is **regular** if the binary matroid [represented](\ref matroids) by \f$ M \f$ is representable over *every* field.
4 | This is equivalent to requiring that the matroid is equal to the ternary matroid [represented](\ref matroids) by the [Camion-signed](\ref camion) version \f$ M' \f$ of \f$ M \f$, and thus equivalent to [total unimodularity](\ref tu) of \f$ M' \f$.
5 |
6 |
7 | ## Recognizing Binary Regular Matrices ##
8 |
9 | The command
10 |
11 | cmr-regular IN-MAT [OPTION...]
12 |
13 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is regular.
14 |
15 | **Options:**
16 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
17 | - `-D OUT-DEC` Write a decomposition tree of the regular matroid to file `OUT-DEC`; default: skip computation.
18 | - `-N NON-MINOR` Write a minimal non-regular submatrix to file `NON-SUB`; default: skip computation.
19 |
20 | **Advanced options:**
21 | - `--stats` Print statistics about the computation to stderr.
22 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
23 | - `--decompose STRATEGY` Strategy for decomposing among {`DP`, `YP`, `P3`, `D3`, `Y3`}; default: `D3`.
24 | - `--no-direct-graphic` Check only 3-connected matrices for regularity.
25 | - `--no-series-parallel` Do not allow series-parallel operations in decomposition tree.
26 | - `--no-simple-3-sepa` Do not allow testing for simple 3-separations.
27 |
28 |
29 | **Decomposition strategies:** 1st letter for distributed, 2nd for concentrated rank(s).
30 | - `D` Delta-sum (distributed ranks)
31 | - `Y` Y-sum (distributed ranks)
32 | - `3` 3-sum (concentrated rank)
33 | - `P` pivot (changes rank type)
34 | Note that D3 and Y3 do not produce pivots.
35 |
36 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
37 |
38 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
39 |
40 | If `OUT-DEC` or `NON-SUB` is `-` then the decomposition tree (resp. the [submatrix](\ref file-formats-submatrix)) is written to stdout.
41 |
42 | ## Algorithm ##
43 |
44 | The implemented recognition algorithm is based on [Implementation of a unimodularity test](https://doi.org/10.1007/s12532-012-0048-x) by Matthias Walter and Klaus Truemper (Mathematical Programming Computation, 2013).
45 | It is based on Seymour's [decomposition theorem for regular matroids](https://doi.org/10.1016/0095-8956(80)90075-1).
46 | The algorithm runs in \f$ \mathcal{O}( (m+n)^5 ) \f$ time and is a simplified version of [Truemper's cubic algorithm](https://doi.org/10.1016/0095-8956(90)90030-4).
47 | Please cite the following paper in case the implementation contributed to your research:
48 |
49 | @Article{WalterT13,
50 | author = {Walter, Matthias and Truemper, Klaus},
51 | title = {Implementation of a unimodularity test},
52 | journal = {Mathematical Programming Computation},
53 | year = {2013},
54 | volume = {5},
55 | number = {1},
56 | pages = {57--73},
57 | issn = {1867-2949},
58 | doi = {10.1007/s12532-012-0048-x},
59 | publisher = {Springer-Verlag},
60 | }
61 |
62 | ## C Interface ##
63 |
64 | The corresponding function in the library is
65 |
66 | - CMRregularTest() tests a binary matrix for regularity.
67 |
68 | and is defined in \ref regular.h.
69 |
--------------------------------------------------------------------------------
/doc/series-parallel.md:
--------------------------------------------------------------------------------
1 | # Series-Parallel Matrices # {#series-parallel}
2 |
3 | A matrix \f$ A \in \{-1,0,+1\}^{m \times n} \f$ is called **series-parallel** if it can be obtained from a \f$ 0 \f$-by-\f$ 0 \f$ matrix by successively adjoining
4 |
5 | - a zero row/column vector,
6 | - a (negated) standard unit row/column vector, or
7 | - a (negated) copy of an existing row/column.
8 |
9 | The removal of such a row/column is called an **SP-reduction**.
10 | A matroid is called **series-parallel** if it is [represented](\ref matroids) by a series-parallel matrix.
11 | This is equivalent to being the graphic matroid of a series-parallel graph.
12 |
13 | **Theorem.** A matrix \f$ A \in \{-1,0,1\}^{m \times n} \f$ is *either* series-parallel or it contains, up to scaling of rows/columns with \f$ -1 \f$,
14 |
15 | - a \f$ 2 \f$-by-\f$ 2 \f$ submatrix \f$ M_2 := \begin{pmatrix} -1 & 1 \\ 1 & 1 \end{pmatrix} \f$,
16 | - a \f$ 3 \f$-by-\f$ 3 \f$ submatrix \f$ M_3' := \begin{pmatrix} 1 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 1 & 1 \end{pmatrix} \f$, or
17 | - a \f$ k \f$-by-\f$ k \f$-submatrix \f$ M_k := \begin{pmatrix}
18 | 1 & 0 & 0 & 0 & \dotsb & 0 & 1 \\
19 | 1 & 1 & 0 & 0 & \dotsb & 0 & 0 \\
20 | 0 & 1 & 1 & 0 & \dotsb & 0 & 0 \\
21 | 0 & 0 & 1 & 1 & \ddots & 0 & 0 \\
22 | \vdots & \vdots & \vdots & \ddots & \ddots & \vdots & \vdots \\
23 | 0 & 0 & 0 & 0 & \dotsb & 1 & 0 \\
24 | 0 & 0 & 0 & 0 & \dotsb & 1 & 1
25 | \end{pmatrix} \f$ for \f$ k \geq 3 \f$.
26 |
27 | The latter two matrices are called **wheel matrices** since their represented matroids are the graphic matroids of wheel graphs.
28 |
29 |
30 | ## Recognizing Series-Parallel Matrices ##
31 |
32 | The command
33 |
34 | cmr-series-parallel IN-MAT [OPTION...]
35 |
36 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is series-parallel.
37 | If this is not the case, then a maximal number of SP-reductions is carried out, leading to the **reduced** matrix.
38 | Moreover, one can ask for one of the minimal non-series-parallel submatrices above.
39 |
40 | **Options:**
41 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
42 | - `-S OUT-SP` Write the list of series-parallel reductions to file `OUT-SP`; default: skip computation.
43 | - `-R OUT-REDUCED` Write the reduced submatrix to file `OUT-REDUCED`; default: skip computation.
44 | - `-N NON-SUB` Write a minimal non-series-parallel submatrix to file `NON-SUB`; default: skip computation.
45 | - `-b` Test for being binary series-parallel; default: ternary.
46 |
47 | **Advanced options**:
48 | - `--stats` Print statistics about the computation to stderr.
49 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
50 |
51 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
52 |
53 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
54 |
55 | If `OUT-SP`, `OUT-REDUCED` or `NON-SUB` is `-` then the list of reductions (resp. the [submatrix](\ref file-formats-submatrix)) is written to stdout.
56 |
57 | ## Algorithm ##
58 |
59 | The implemented algorithm is not yet published.
60 | For a matrix \f$ A \in \{0,1\}^{m \times n}\f$ with \f$ k \f$ (sorted) nonzeros it runs in \f$ \mathcal{O}( m + n + k ) \f$ time assuming no hashtable collisions.
61 |
62 | ## C Interface ##
63 |
64 | The corresponding functions in the library are
65 |
66 | - CMRspTestTernary() tests a binary matrix for being series-parallel.
67 | - CMRspTestBinary() tests a binary matrix for being series-parallel.
68 | - CMRspDecomposeBinary() tests a binary matrix for being series-parallel, but may also terminate early, returning a 2-separation of \f$ A \f$.
69 | - CMRspDecomposeTernary() tests a ternary matrix for being series-parallel, but may also terminate early, returning a 2-separation of \f$ A \f$.
70 |
71 | and are defined in \ref series_parallel.h.
72 |
--------------------------------------------------------------------------------
/doc/staircase-compatibility.md:
--------------------------------------------------------------------------------
1 | # Staircase Compatibility # {#staircase-compatibility}
2 |
3 | See [here](http://www.optimization-online.org/DB_HTML/2018/01/6435.html) for a definition.
4 |
--------------------------------------------------------------------------------
/doc/totally-balanced.md:
--------------------------------------------------------------------------------
1 | # Totally Balanced Matrices # {#totally-balanced}
2 |
3 | A binary matrix \f$M \in \{0,1\}^{m \times n} \f$ is called **totally balanced** if it does not contain a square matrix that is the incidence matrix of any cycle of length at least 3.
4 |
5 |
--------------------------------------------------------------------------------
/doc/tu.md:
--------------------------------------------------------------------------------
1 | # Totally Unimodular Matrices # {#tu}
2 |
3 | A matrix \f$ M \in \mathbb{Z}^{m \times n} \f$ is **totally unimodular** if all its square submatrices have a determinant in \f$ \{-1,0,+1\} \f$.
4 | Here, a submatrix does not need to be contiguous, i.e., the matrix \f$M = \begin{pmatrix} 1 & 0 & -1 \\ 1 & 0 & 1 \end{pmatrix} \f$ is not totally unimodular since the submatrix indexed by rows \f$ \{1, 2 \} \f$ and columns \f$ \{ 1,3 \} \f$ has determinant 2.
5 | In particular, every totally unimodular matrix has only entries in \f$ \{-1,0,+1\} \f$ as these are the 1-by-1 submatrices.
6 |
7 |
8 | ## Recognizing Totally Unimodular Matrices ##
9 |
10 | The command
11 |
12 | cmr-tu IN-MAT [OPTION...]
13 |
14 | determines whether the [matrix](\ref file-formats-matrix) given in file `IN-MAT` is totally unimodular.
15 |
16 | **Options:**
17 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
18 | - `-D OUT-DEC` Write a decomposition tree of the underlying regular matroid to file `OUT-DEC`; default: skip computation.
19 | - `-N NON-SUB` Write a minimal non-totally-unimodular submatrix to file `NON-SUB`; default: skip computation.
20 |
21 | **Advanced options:**
22 | - `--stats` Print statistics about the computation to stderr.
23 | - `--time-limit LIMIT` Allow at most `LIMIT` seconds for the computation.
24 | - `--decompose STRATEGY` Strategy for decomposing among {`DP`, `YP`, `P3`, `D3`, `Y3`}; default: `D3`.
25 | - `--no-direct-graphic` Check only 3-connected matrices for regularity.
26 | - `--no-series-parallel` Do not allow series-parallel operations in decomposition tree.
27 | - `--no-simple-3-sepa` Do not allow testing for simple 3-separations.
28 | - `--naive-submatrix` Use naive bad submatrix algorithm instead of greedy heuristic.
29 | - `--algo ALGO` Use algorithm from {`decomposition`, `submatrix`, `partition`}; default: `decomposition`.
30 |
31 | **Decomposition strategies:** 1st letter for distributed, 2nd for concentrated rank(s).
32 | - `D` Delta-sum (distributed ranks)
33 | - `Y` Y-sum (distributed ranks)
34 | - `3` 3-sum (concentrated rank)
35 | - `P` pivot (changes rank type)
36 | Note that D3 and Y3 do not produce pivots.
37 |
38 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
39 |
40 | If `IN-MAT` is `-` then the [matrix](\ref file-formats-matrix) is read from stdin.
41 |
42 | If `OUT-DEC` or `NON-SUB` is `-` then the decomposition tree (resp. the [submatrix](\ref file-formats-submatrix)) is written to stdout.
43 |
44 | ## Algorithms ##
45 |
46 | The implemented default recognition algorithm is based on [Implementation of a unimodularity test](https://doi.org/10.1007/s12532-012-0048-x) by Matthias Walter and Klaus Truemper (Mathematical Programming Computation, 2013).
47 | It either runs \ref camion to reduce the question to that of [recognizing binary regular matroids](\ref binary_regular) or decomposes a given ternary matrix directly by means of a [Seymour decomposition](\ref seymour_decomposition).
48 | Please cite the paper in case the implementation contributed to your research:
49 |
50 | @Article{WalterT13,
51 | author = {Walter, Matthias and Truemper, Klaus},
52 | title = {Implementation of a unimodularity test},
53 | journal = {Mathematical Programming Computation},
54 | year = {2013},
55 | volume = {5},
56 | number = {1},
57 | pages = {57--73},
58 | issn = {1867-2949},
59 | doi = {10.1007/s12532-012-0048-x},
60 | publisher = {Springer-Verlag},
61 | }
62 |
63 | In order to repeat experiments described in the paper above, the function can be parameterized as to use exponential-time algorithms.
64 |
65 | - The first is based on the criterion of Ghouila-Houri and runs in time \f$ \mathcal{O}( (m + n) \cdot 3^{\min(m, n)}) \f$.
66 | - The second enumerates square [Eulerian submatrices](https://www.ams.org/journals/proc/1965-016-05/S0002-9939-1965-0180568-2/) and runs in time \f$ \mathcal{O}( (m+n) \cdot 2^{ m + n } ) \f$.
67 |
68 | ## C Interface ##
69 |
70 | The corresponding function in the library is
71 |
72 | - CMRtuTest() tests a matrix for being totally unimodular.
73 |
74 | and is defined in \ref tu.h.
75 | Its parameters also allow to choose one of the enumeration algorithms with exponential running time instead of the decomposition algorithm.
76 |
77 |
--------------------------------------------------------------------------------
/doc/utilities.md:
--------------------------------------------------------------------------------
1 | # Basic Utilities # {#utilities}
2 |
3 | This tool is useful for basic matrix operations:
4 |
5 | - Transposing the input matrix.
6 | - Turning a submatrix of a matrix into an explicit matrix.
7 | - Computing the support matrix of the input matrix.
8 | - Computing the signed support matrix (negative entries are turned into \f$ -1 \f$'s, positive into \f$ +1 \f$'s) of the input matrix.
9 |
10 | ## Matrix Utilities ##
11 |
12 | The command
13 |
14 | cmr-matrix IN-MAT OUT-MAT [OPTION]...
15 |
16 | copies the [matrix](\ref file-formats-matrix) from file `IN-MAT` to file `OUT-MAT`, potentially applying certain operations.
17 |
18 | **Options:**
19 | - `-i FORMAT` Format of file `IN-MAT`; default: [dense](\ref dense-matrix).
20 | - `-o FORMAT` Format of file `OUT-MAT`; default: same as format of `IN-MAT`.
21 | - `-S IN-SUB` Consider the [submatrix](\ref file-formats-submatrix) of `IN-MAT` specified in file `IN-SUB` instead of `IN-MAT` itself; can be combined with other operations.
22 | - `-t` Transpose the matrix; can be combined with other operations.
23 | - `-c` Compute the support matrix instead of copying.
24 | - `-C` Compute the signed support matrix instead of copying.
25 | - `-r` Randomize the output matrix by randomly permuting rows/columns.
26 | - `-R2 NUM` Randomize the output matrix by performing `NUM` binary random pivots.
27 | - `-R3 NUM` Randomize the output matrix by performing `NUM` ternary random pivots.
28 | - `-d` Use double arithmetic instead of integers.
29 |
30 | Formats for matrices: [dense](\ref dense-matrix), [sparse](\ref sparse-matrix)
31 | If `IN-MAT` or `IN-SUB` is `-` then the input matrix (resp. submatrix) is read from stdin.
32 | If `OUT-MAT` is `-` then the output matrix is written to stdout.
33 |
--------------------------------------------------------------------------------
/experiments/config.py:
--------------------------------------------------------------------------------
1 | BUILD_DIRECTORY='/home/walterm/code/cmr-develop.git/build-release'
2 | UNIMOD_DIRECTORY='/home/walterm/code/unimodularity-library-1.2h/src'
3 | LOCAL_STORAGE='/local/walterm/cmr'
4 | ALGORITHMS = ['cmrdec', 'cmrpart', 'cmreuler', 'cmrcert', 'unimod', 'unimodcert']
5 |
--------------------------------------------------------------------------------
/experiments/config_modwheel.py:
--------------------------------------------------------------------------------
1 | from config import *
2 |
3 | INSTANCE_DIRECTORY = 'modwheel'
4 | INSTANCES = sorted(list(range(9, 99, 10)) + list(range(99, 900, 100)))
5 | SAMPLES = list(range(1, 10+1))
6 |
7 |
--------------------------------------------------------------------------------
/experiments/config_network.py:
--------------------------------------------------------------------------------
1 | from config import *
2 |
3 | INSTANCE_DIRECTORY = 'network'
4 | INSTANCES = sorted(set(range(1,41)) | set(100 * i for i in range(1,41) ) | set(1000 * i for i in range(1,41) ))
5 | SAMPLES = list(range(1, 10+1))
6 |
7 |
--------------------------------------------------------------------------------
/experiments/config_rndcamion.py:
--------------------------------------------------------------------------------
1 | from config import *
2 |
3 | INSTANCE_DIRECTORY = 'rndcamion'
4 | INSTANCES = [ (order,prob) for order in range(50,2001,50) for prob in [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1] ]
5 | SAMPLES = list(range(1, 10+1))
6 |
7 |
--------------------------------------------------------------------------------
/experiments/eval_modwheel.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 | import eval_parse
6 |
7 | from config_modwheel import *
8 |
9 | assert os.path.exists(INSTANCE_DIRECTORY)
10 |
11 | results = []
12 | for instance in INSTANCES:
13 | file_prefix = f'{INSTANCE_DIRECTORY}/modwheel-{instance:05d}x{instance:05d}'
14 | for algo in ALGORITHMS:
15 | for sample in SAMPLES:
16 | result = eval_parse.parse(file_prefix, instance, algo, sample)
17 |
18 | if algo.startswith('unimod') and result.time >= 3700.0:
19 | result.time = float('inf')
20 |
21 | results.append( result )
22 | print(f' {result}')
23 |
24 | times = eval_parse.averageTimes(results)
25 |
26 | for instance in INSTANCES:
27 | for algo in ALGORITHMS:
28 | print(instance, algo, times[ (instance, algo) ])
29 |
30 |
--------------------------------------------------------------------------------
/experiments/eval_parse.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import re
3 |
4 | class Result:
5 | def __init__(self, instance, algorithm, run=None):
6 | self._run = run
7 | self._instance = instance
8 | self._algorithm = algorithm
9 | self.time = float('inf')
10 | self.time_max = 0.0
11 | self.time_min = 0.0
12 |
13 | @property
14 | def instance(self):
15 | return self._instance
16 |
17 | @property
18 | def algorithm(self):
19 | return self._algorithm
20 |
21 | @property
22 | def run(self):
23 | return self._run
24 |
25 | def __repr__(self):
26 | run_str = '' if self._run is None else f' (run #{self._run})'
27 | return f'{self._instance} via {self._algorithm}{run_str}: {self.time} in [{self.time_min},{self.time_max}]'
28 |
29 | def averageTimes(result_list):
30 | result_map = { (result.instance, result.algorithm): [] for result in result_list }
31 | for result in result_list:
32 | result_map[result.instance,result.algorithm].append(result)
33 |
34 | def avg(instance, algorithm, L):
35 | times = [ result.time for result in L ]
36 | res = Result(instance, algorithm)
37 | res.time = sum(times) / len(L)
38 | res.time_min = min(times)
39 | res.time_max = max(times)
40 | return res
41 |
42 | return { key: avg(key[0], key[1], value) for key,value in result_map.items() }
43 |
44 | def parseCMR(file_base, instance, algorithm, run):
45 | result = Result(instance, algorithm, run)
46 |
47 | sys.stderr.write(f'Reading {file_base}.out|.err\n')
48 |
49 | re_part_time = re.compile(' partition time: ([0-9.]*)( seconds|)')
50 | re_euler_time = re.compile(' eulerian enumeration time: ([0-9.]*)( seconds|)')
51 | re_dec_time = re.compile(' seymour total: [0-9]* in ([0-9.]*)( seconds|)')
52 | re_time_limit = re.compile('Time limit exceeded!')
53 |
54 | try:
55 | time_limit = False
56 | with open(file_base + '.err', 'r') as err_file:
57 | for line in err_file:
58 | match = re_time_limit.match(line)
59 | if match:
60 | time_limit = True
61 | continue
62 | match = re_part_time.match(line)
63 | if algorithm == 'cmrpart' and match and not time_limit:
64 | result.time = float(match.group(1))
65 | continue
66 | match = re_euler_time.match(line)
67 | if algorithm == 'cmreuler' and match and not time_limit:
68 | result.time = float(match.group(1))
69 | continue
70 | match = re_dec_time.match(line)
71 | if algorithm in ['cmrdec', 'cmrcert'] and match and not time_limit:
72 | result.time = float(match.group(1))
73 | continue
74 | except:
75 | pass
76 |
77 | return result
78 |
79 | def parseUnimodularityTest(file_base, instance, algorithm, run):
80 | result = Result(instance, algorithm, run)
81 |
82 | sys.stderr.write(f'Reading {file_base}.out\n')
83 |
84 | re_total_time = re.compile('Total time: ([0-9.]*)')
85 |
86 | try:
87 | with open(file_base + '.out', 'r') as out_file:
88 | for line in out_file:
89 | match = re_total_time.match(line)
90 | if algorithm in ['unimod', 'unimodcert'] and match:
91 | result.time = float(match.group(1))
92 | continue
93 | except:
94 | pass
95 |
96 | return result
97 |
98 | def parse(file_prefix, instance, algorithm, run):
99 | if algorithm[:3] == 'cmr':
100 | return parseCMR(f'{file_prefix}#{run:03d}-{algorithm}', instance, algorithm, run)
101 | elif algorithm[:6] == 'unimod':
102 | return parseUnimodularityTest(f'{file_prefix}#{run:03d}-{algorithm}', instance, algorithm, run)
103 |
104 | if __name__ == '__main__':
105 | result = parse(sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4]))
106 | print(result)
107 |
108 |
--------------------------------------------------------------------------------
/experiments/gen_modwheel.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 | from config_modwheel import *
6 |
7 | assert os.path.exists(INSTANCE_DIRECTORY)
8 |
9 | for sample in SAMPLES:
10 | for instance in INSTANCES:
11 | file_base = f'{INSTANCE_DIRECTORY}/modwheel-{instance:05d}x{instance:05d}#{sample:03d}'
12 | os.system(f'{BUILD_DIRECTORY}/cmr-generate-wheel -01 {instance} -o sparse | {BUILD_DIRECTORY}/cmr-matrix -i sparse - -r -R2 {instance//2+1} -o sparse - | gzip > {file_base}.sparse.gz')
13 |
14 |
--------------------------------------------------------------------------------
/experiments/gen_modwheel.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 1 # Number of cores reserved for each task
3 | #SBATCH --mem=1G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J gen_modwheel
6 | #SBATCH --output=modwheel/gen-%A.log
7 | #SBATCH --time=0:05:00 # Time limit
8 |
9 |
10 | HOSTNAME=`hostname`
11 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
12 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
13 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
14 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
15 |
16 | python3 gen_modwheel.py
17 |
--------------------------------------------------------------------------------
/experiments/gen_network.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 |
6 | from config_network import *
7 |
8 | assert os.path.exists(INSTANCE_DIRECTORY)
9 |
10 | for sample in SAMPLES:
11 | for instance in INSTANCES:
12 | order = instance
13 | file_base = f'{INSTANCE_DIRECTORY}/network-{order:05d}x{order:05d}#{sample:03d}'
14 | os.system(f'{BUILD_DIRECTORY}/cmr-generate-network {order} {order} -o sparse | gzip > {file_base}.sparse.gz')
15 |
16 |
--------------------------------------------------------------------------------
/experiments/gen_network.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 1 # Number of cores reserved for each task
3 | #SBATCH --mem=1G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J gen_network
6 | #SBATCH --output=network/gen-%A.log
7 | #SBATCH --time=8:00:00 # Time limit
8 |
9 |
10 | HOSTNAME=`hostname`
11 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
12 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
13 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
14 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
15 |
16 | python3 gen_network.py
17 |
--------------------------------------------------------------------------------
/experiments/gen_rndcamion.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 |
6 | from config_rndcamion import *
7 |
8 | assert os.path.exists(INSTANCE_DIRECTORY)
9 |
10 | for sample in SAMPLES:
11 | for instance in INSTANCES:
12 | order,p = instance
13 | file_base = f'{INSTANCE_DIRECTORY}/rndcamion-{order:05d}x{order:05d}-p{p:0.2f}#{sample:03d}'
14 | os.system(f'{BUILD_DIRECTORY}/cmr-generate-random -o sparse {order} {order} {p} | {BUILD_DIRECTORY}/cmr-camion -i sparse - -S - | gzip > {file_base}.sparse.gz')
15 |
16 |
--------------------------------------------------------------------------------
/experiments/gen_rndcamion.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 1 # Number of cores reserved for each task
3 | #SBATCH --mem=1G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J gen_rndcamion
6 | #SBATCH --output=rndcamion/gen-%A.log
7 | #SBATCH --time=8:00:00 # Time limit
8 |
9 |
10 | HOSTNAME=`hostname`
11 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
12 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
13 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
14 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
15 |
16 | python3 gen_rndcamion.py
17 |
--------------------------------------------------------------------------------
/experiments/graphic.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 |
6 | GENERATOR = '../build-release/cmr-generate-graphic'
7 |
8 | # Parameter of script: #rows and number of repetitions
9 | try:
10 | numRows = int(sys.argv[1])
11 | numRepetitions = int(sys.argv[2])
12 | except:
13 | print(f'Usage: {sys.argv[0]} #ROWS NUM-REPETITIONS')
14 | sys.exit(1)
15 |
16 | sys.stdout.write('rows,cols,#nzs,tTrans,tCheck,tApply,tTotal\n')
17 | sys.stdout.flush()
18 |
19 | def run(numRows, numColumns, repetitions):
20 | command = [GENERATOR, str(int(numRows)), str(int(numColumns)), '-b', str(repetitions)]
21 | process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
22 | timeTranspose = 0.0
23 | timeCheck = 0.0
24 | timeApply = 0.0
25 | timeTotal = 0.0
26 | avgNonzeros = 0
27 | for line in process.stdout.decode('utf-8').split('\n'):
28 | if line.startswith('Generated a'):
29 | avgNonzeros += int(line.split(' ')[5].strip())
30 | if line.startswith('Transposition:'):
31 | timeTranspose += float(line.split('/')[1].strip())
32 | if line.startswith('Check:'):
33 | timeCheck += float(line.split('/')[1].strip())
34 | if line.startswith('Apply:'):
35 | timeApply += float(line.split('/')[1].strip())
36 | if line.startswith('Total:'):
37 | timeTotal += float(line.split('/')[1].strip())
38 | timeTranspose /= repetitions
39 | timeCheck /= repetitions
40 | timeApply /= repetitions
41 | timeTotal /= repetitions
42 | avgNonzeros /= repetitions
43 | sys.stdout.write(f'{numRows:.0f},{numColumns:.0f},{avgNonzeros:.1f},{timeTranspose},{timeCheck},{timeApply},{timeTotal}\n')
44 | sys.stdout.flush()
45 |
46 | run(numRows, int(4.0*numRows), numRepetitions)
47 | sys.exit(0)
48 |
49 | run(numRows, int(0.5*numRows), numRepetitions)
50 | run(numRows, int(1.0*numRows), numRepetitions)
51 | run(numRows, int(1.5*numRows), numRepetitions)
52 | run(numRows, int(2.0*numRows), numRepetitions)
53 | run(numRows, int(2.5*numRows), numRepetitions)
54 | run(numRows, int(3.0*numRows), numRepetitions)
55 | run(numRows, int(3.5*numRows), numRepetitions)
56 | run(numRows, int(4.0*numRows), numRepetitions)
57 | run(numRows, int(4.5*numRows), numRepetitions)
58 | run(numRows, int(5.0*numRows), numRepetitions)
59 | run(numRows, int(5.5*numRows), numRepetitions)
60 | run(numRows, int(6.0*numRows), numRepetitions)
61 | run(numRows, int(6.5*numRows), numRepetitions)
62 | run(numRows, int(7.0*numRows), numRepetitions)
63 | run(numRows, int(7.5*numRows), numRepetitions)
64 | run(numRows, int(8.0*numRows), numRepetitions)
65 |
66 |
--------------------------------------------------------------------------------
/experiments/run_modwheel.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 | from datetime import datetime
6 |
7 | from config_modwheel import *
8 |
9 | assert os.path.exists(INSTANCE_DIRECTORY)
10 |
11 | sample = int(sys.argv[1])
12 | sampleStorage = f'{LOCAL_STORAGE}/modwheel_{sample}/'
13 |
14 | os.system(f'mkdir -p {sampleStorage}')
15 |
16 | def call(command):
17 | # print('[' + command + ']')
18 | os.system(command)
19 |
20 | for instance in INSTANCES:
21 | file_base = f'{INSTANCE_DIRECTORY}/modwheel-{instance:05d}x{instance:05d}#{sample:03d}'
22 |
23 | print(f'Considering {file_base} at {datetime.now()}.', flush=True)
24 |
25 | # Run cmr-tu.
26 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo decomposition --time-limit 3600 1> {file_base}-cmrdec.out 2> {file_base}-cmrdec.err')
27 | if instance <= 50:
28 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo eulerian --time-limit 3600 1> {file_base}-cmreuler.out 2> {file_base}-cmreuler.err')
29 | if instance <= 50:
30 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo partition --time-limit 3600 1> {file_base}-cmrpart.out 2> {file_base}-cmrpart.err')
31 |
32 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo decomposition --time-limit 3600 -N {file_base}-cmrcert.sub 1> {file_base}-cmrcert.out 2> {file_base}-cmrcert.err')
33 |
34 | # Run unimodularity-test.
35 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-matrix - -i sparse -o dense {sampleStorage}/input.dense')
36 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/input.dense -s 2> /dev/null | egrep \'^[ 0-9-]*$\' 1> {sampleStorage}/signed.dense')
37 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/signed.dense -t -v 1> {file_base}-unimod.out 2> {file_base}-unimod.err')
38 | if instance <= 199:
39 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/signed.dense -t -v -c 1> {file_base}-unimodcert.out 2> {file_base}-unimodcert.err')
40 |
41 | os.system(f'rm -r {sampleStorage}')
42 |
43 |
--------------------------------------------------------------------------------
/experiments/run_modwheel.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 24 # Number of cores reserved for each task
3 | #SBATCH --mem=20G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J run_modwheel
6 | #SBATCH --output=modwheel/run-%A.log
7 | #SBATCH --constraint=titan-x
8 | #SBATCH --time=72:00:00 # Time limit
9 |
10 |
11 | HOSTNAME=`hostname`
12 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
13 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
14 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
15 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
16 |
17 | python3 run_modwheel.py 1 &
18 | pid1=$!
19 |
20 | python3 run_modwheel.py 2 &
21 | pid2=$!
22 |
23 | python3 run_modwheel.py 3 &
24 | pid3=$!
25 |
26 | python3 run_modwheel.py 4 &
27 | pid4=$!
28 |
29 | python3 run_modwheel.py 5 &
30 | pid5=$!
31 |
32 | python3 run_modwheel.py 6 &
33 | pid6=$!
34 |
35 | python3 run_modwheel.py 7 &
36 | pid7=$!
37 |
38 | python3 run_modwheel.py 8 &
39 | pid8=$!
40 |
41 | python3 run_modwheel.py 9 &
42 | pid9=$!
43 |
44 | python3 run_modwheel.py 10 &
45 | pid10=$!
46 |
47 | wait $pid1 $pid2 $pid3 $pid4 $pid5 $pid6 $pid7 $pid8 $pid9 $pid10
48 |
49 |
--------------------------------------------------------------------------------
/experiments/run_network.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 |
6 | from config_network import *
7 |
8 | assert os.path.exists(INSTANCE_DIRECTORY)
9 |
10 | sample = int(sys.argv[1])
11 | sampleStorage = f'{LOCAL_STORAGE}/network_{sample}/'
12 |
13 | def call(command):
14 | # print('[' + command + ']')
15 | os.system(command)
16 |
17 | for instance in INSTANCES:
18 | file_base = f'{INSTANCE_DIRECTORY}/network-{order:05d}x{order:05d}#{sample:03d}'
19 |
20 | print(f'Considering {file_base}.')
21 |
22 | # Run cmr-tu.
23 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo decomposition --time-limit 3600 1> {file_base}-cmrdec.out 2> {file_base}-cmrdec.err')
24 | if order <= 20:
25 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo eulerian --time-limit 3600 1> {file_base}-cmreuler.out 2> {file_base}-cmreuler.err')
26 | if order <= 30:
27 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo partition --time-limit 3600 1> {file_base}-cmrpart.out 2> {file_base}-cmrpart.err')
28 |
29 | # Run unimodularity-test.
30 | if order <= 4000:
31 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-matrix - -i sparse -o dense {sampleStorage}/input.dense')
32 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/input.dense -t -v 1> {file_base}-unimod.out 2> {file_base}-unimod.err')
33 |
34 | os.system(f'rm -r {sampleStorage}')
35 |
36 |
--------------------------------------------------------------------------------
/experiments/run_network.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 1 # Number of cores reserved for each task
3 | #SBATCH --mem=40G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J run_network
6 | #SBATCH --output=network/run-%A.log
7 | #SBATCH --constraint=titan-x
8 | #SBATCH --time=168:00:00 # Time limit
9 |
10 |
11 | HOSTNAME=`hostname`
12 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
13 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
14 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
15 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
16 |
17 | for SAMPLE in `seq 1 10`; do
18 | python3 run_network.py ${SAMPLE}
19 | done
20 |
--------------------------------------------------------------------------------
/experiments/run_rndcamion.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 | from datetime import datetime
6 |
7 | from config_rndcamion import *
8 |
9 | assert os.path.exists(INSTANCE_DIRECTORY)
10 |
11 | sample = int(sys.argv[1])
12 | sampleStorage = f'{LOCAL_STORAGE}/rndcamion_{sample}/'
13 |
14 | os.system(f'mkdir -p {sampleStorage}')
15 |
16 |
17 |
18 | def call(command):
19 | # print('[' + command + ']')
20 | os.system(command)
21 |
22 | for instance in INSTANCES:
23 | order,p = instance
24 | file_base = f'{INSTANCE_DIRECTORY}/rndcamion-{order:05d}x{order:05d}-p{p:0.2f}#{sample:03d}'
25 |
26 | print(f'Considering {file_base} at {datetime.now()}.', flush=True)
27 |
28 | # Run cmr-tu.
29 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo decomposition --time-limit 3600 1> {file_base}-cmrdec.out 2> {file_base}-cmrdec.err')
30 | if order <= 600:
31 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo eulerian --time-limit 3600 1> {file_base}-cmreuler.out 2> {file_base}-cmreuler.err')
32 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo partition --time-limit 3600 1> {file_base}-cmrpart.out 2> {file_base}-cmrpart.err')
33 |
34 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-tu - -i sparse --stats --algo decomposition --time-limit 3600 -N {file_base}-cmrcert.sub 1> {file_base}-cmrcert.out 2> {file_base}-cmrcert.err')
35 |
36 | # Run unimodularity-test.
37 | call(f'gunzip -cd {file_base}.sparse.gz | {BUILD_DIRECTORY}/cmr-matrix - -i sparse -o dense {sampleStorage}/input.dense')
38 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/input.dense -s 2> /dev/null | egrep \'^[ 0-9-]*$\' 1> {sampleStorage}/signed.dense')
39 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/signed.dense -t -v 1> {file_base}-unimod.out 2> {file_base}-unimod.err')
40 | if order <= 1000:
41 | call(f'{UNIMOD_DIRECTORY}/unimodularity-test {sampleStorage}/signed.dense -t -v -c 1> {file_base}-unimodcert.out 2> {file_base}-unimodcert.err')
42 |
43 | os.system(f'rm -r {sampleStorage}')
44 |
45 |
--------------------------------------------------------------------------------
/experiments/run_rndcamion.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH -c 24 # Number of cores reserved for each task
3 | #SBATCH --mem=200G # Memory reserved for each task
4 | #SBATCH --mail-type=END,FAIL # When to send an email
5 | #SBATCH -J run_rndcamion
6 | #SBATCH --output=rndcamion/run-%A.log
7 | #SBATCH --constraint=titan-x
8 | #SBATCH --time=48:00:00 # Time limit
9 |
10 |
11 | HOSTNAME=`hostname`
12 | NUM_CPUS=`lscpu | egrep '^CPU\(s\):' | cut -d ':' -f2- | sed -e 's/^[[:space:]]*//'`
13 | NUM_CORES=`egrep '^cpu cores' /proc/cpuinfo | uniq | cut -d ':' -f2 | cut -d ' ' -f2-`
14 | MEM=`lsmem | egrep 'Total online memory:' | cut -d: -f2- | sed -e 's/^[[:space:]]*//'`
15 | echo "Run on ${HOSTNAME} which has ${NUM_CPUS} CPUs (${NUM_CORES} cores) and ${MEM} memory."
16 |
17 | python3 run_rndcamion.py 1 &
18 | pid1=$!
19 |
20 | python3 run_rndcamion.py 2 &
21 | pid2=$!
22 |
23 | python3 run_rndcamion.py 3 &
24 | pid3=$!
25 |
26 | python3 run_rndcamion.py 4 &
27 | pid4=$!
28 |
29 | python3 run_rndcamion.py 5 &
30 | pid5=$!
31 |
32 | python3 run_rndcamion.py 6 &
33 | pid6=$!
34 |
35 | python3 run_rndcamion.py 7 &
36 | pid7=$!
37 |
38 | python3 run_rndcamion.py 8 &
39 | pid8=$!
40 |
41 | python3 run_rndcamion.py 9 &
42 | pid9=$!
43 |
44 | python3 run_rndcamion.py 10 &
45 | pid10=$!
46 |
47 | wait $pid1 $pid2 $pid3 $pid4 $pid5 $pid6 $pid7 $pid8 $pid9 $pid10
48 |
49 |
--------------------------------------------------------------------------------
/experiments/series_parallel.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import math
4 | import subprocess
5 |
6 | GENERATOR = '../build-release/cmr-generate-series-parallel'
7 |
8 | # Parameter of script: max amount of GB to be used.
9 | try:
10 | maxMemory = float(sys.argv[1]) * 1024 * 1024 * 1024
11 | numRepetitions = int(sys.argv[2])
12 | except:
13 | print(f'Usage: {sys.argv[0]} MAX-MEMORY-IN-GIGABYTES NUM-REPETITIONS')
14 | sys.exit(1)
15 | maxNumNonzeros = maxMemory / 45 # This is the approximate number of bytes required per nonzero.
16 |
17 | bitsNonzeros = int(round(math.log(maxNumNonzeros) / math.log(2), 0))
18 |
19 | sys.stdout.write('rTot,cTot,rBase,cBase,rZero,cZero,rUnit,cUnit,rCopy,cCopy,sp,tRed,tWheel,tTern,tTotal,#nzs\n')
20 | sys.stdout.flush()
21 |
22 | def run(sparsity, numBaseRows, numBaseColumns, numZeroRows, numZeroColumns, numUnitRows, numUnitColumns, numCopiedRows, numCopiedColumns, ternary, repetitions):
23 | command = [GENERATOR, str(int(numBaseRows)), str(int(numBaseColumns)), '-z', str(int(numZeroRows)), str(int(numZeroColumns)), '-u', str(int(numUnitRows)), str(int(numUnitColumns)), '-c', str(int(numCopiedRows)), str(int(numCopiedColumns)), '-s', str(sparsity), '-b', str(repetitions)]
24 | if ternary:
25 | command.append('-t')
26 | process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
27 | timeReductions = 0.0
28 | timeWheel = 0.0
29 | timeTernary = 0.0
30 | timeTotal = 0.0
31 | avgNonzeros = None
32 | for line in process.stdout.decode('utf-8').split('\n'):
33 | if line.startswith('Search for reductions:'):
34 | timeReductions = float(line.split('/')[1].strip())
35 | if line.startswith('Search for wheel matrices:'):
36 | timeWheel = float(line.split('/')[1].strip())
37 | if line.startswith('Search for ternary certificate:'):
38 | timeTernary = float(line.split('/')[1].strip())
39 | if line.startswith('Total:'):
40 | timeTotal = float(line.split('/')[1].strip())
41 | if line.startswith('Average number of nonzeros:'):
42 | avgNonzeros = float(line.split(':')[1].strip())
43 | timeReductions /= repetitions
44 | timeWheel /= repetitions
45 | timeTernary /= repetitions
46 | timeTotal /= repetitions
47 | sys.stdout.write(f'{numBaseRows+numZeroRows+numUnitRows+numCopiedRows:.0f},{numBaseColumns+numZeroColumns+numUnitColumns+numCopiedColumns:.0f},{numBaseRows},{numBaseColumns},{numZeroRows},{numZeroColumns},{numUnitRows},{numUnitColumns},{numCopiedRows},{numCopiedColumns},{sparsity},{timeReductions},{timeWheel},{timeTernary},{timeTotal},{avgNonzeros}\n')
48 | sys.stdout.flush()
49 |
50 | for ternary in [False, True]:
51 |
52 | # Different portions of unit/copied.
53 | if True:
54 | size = 2**(bitsNonzeros-16)
55 | run(1, 1, 1, 0, 0, 1.0*size-1, 1.0*size-1, 0, 0, ternary, numRepetitions)
56 | run(1, 1, 1, 0, 0, 0.9*size-1, 0.9*size-1, 0.1*size, 0.1*size, ternary, numRepetitions)
57 | run(1, 1, 1, 0, 0, 0.8*size-1, 0.8*size-1, 0.2*size, 0.2*size, ternary, numRepetitions)
58 | run(1, 1, 1, 0, 0, 0.7*size-1, 0.7*size-1, 0.3*size, 0.3*size, ternary, numRepetitions)
59 | run(1, 1, 1, 0, 0, 0.6*size-1, 0.6*size-1, 0.4*size, 0.4*size, ternary, numRepetitions)
60 | run(1, 1, 1, 0, 0, 0.5*size-1, 0.5*size-1, 0.5*size, 0.5*size, ternary, numRepetitions)
61 | run(1, 1, 1, 0, 0, 0.4*size-1, 0.4*size-1, 0.6*size, 0.6*size, ternary, numRepetitions)
62 | run(1, 1, 1, 0, 0, 0.3*size-1, 0.3*size-1, 0.7*size, 0.7*size, ternary, numRepetitions)
63 | run(1, 1, 1, 0, 0, 0.2*size-1, 0.2*size-1, 0.8*size, 0.8*size, ternary, numRepetitions)
64 | run(1, 1, 1, 0, 0, 0.1*size-1, 0.1*size-1, 0.9*size, 0.9*size, ternary, numRepetitions)
65 | run(1, 1, 1, 0, 0, 0, 0, 1.0*size-1, 1.0*size-1, ternary, numRepetitions)
66 | sys.stdout.write('\n')
67 |
68 | if True:
69 | # Different portion of base.
70 | size = 2**(bitsNonzeros-16)
71 | run(1, 1, 1, 0, 0, 0.5*size-1, 0.5*size-1, 0.5*size, 0.5*size, ternary, numRepetitions)
72 | run(0.05*size, 0.1*size, 0.1*size, 0, 0, 0.45*size, 0.45*size, 0.45*size, 0.45*size, ternary, numRepetitions)
73 | run(0.10*size, 0.2*size, 0.2*size, 0, 0, 0.40*size, 0.40*size, 0.40*size, 0.40*size, ternary, numRepetitions)
74 | run(0.15*size, 0.3*size, 0.3*size, 0, 0, 0.35*size, 0.35*size, 0.35*size, 0.35*size, ternary, numRepetitions)
75 | run(0.20*size, 0.4*size, 0.4*size, 0, 0, 0.30*size, 0.30*size, 0.30*size, 0.30*size, ternary, numRepetitions)
76 | run(0.25*size, 0.5*size, 0.5*size, 0, 0, 0.25*size, 0.25*size, 0.25*size, 0.25*size, ternary, numRepetitions)
77 | run(0.30*size, 0.6*size, 0.6*size, 0, 0, 0.20*size, 0.20*size, 0.20*size, 0.20*size, ternary, numRepetitions)
78 | run(0.35*size, 0.7*size, 0.7*size, 0, 0, 0.15*size, 0.15*size, 0.15*size, 0.15*size, ternary, numRepetitions)
79 | run(0.40*size, 0.8*size, 0.8*size, 0, 0, 0.10*size, 0.10*size, 0.10*size, 0.10*size, ternary, numRepetitions)
80 | run(0.45*size, 0.9*size, 0.9*size, 0, 0, 0.05*size, 0.05*size, 0.05*size, 0.05*size, ternary, numRepetitions)
81 | run(0.50*size, 1.0*size, 1.0*size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
82 | sys.stdout.write('\n')
83 |
84 | if True:
85 | # Different densities of full base.
86 | size = 2**(bitsNonzeros-16)
87 | run(0.0*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
88 | run(0.1*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
89 | run(0.2*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
90 | run(0.3*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
91 | run(0.4*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
92 | run(0.5*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
93 | run(0.6*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
94 | run(0.7*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
95 | run(0.8*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
96 | run(0.9*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
97 | run(1.0*size, size, size, 0, 0, 0, 0, 0, 0, ternary, numRepetitions)
98 | sys.stdout.write('\n')
99 |
100 |
--------------------------------------------------------------------------------
/include/cmr/balanced.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_BALANCED_H
2 | #define CMR_BALANCED_H
3 |
4 | /**
5 | * \file balanced.h
6 | *
7 | * \author Henk Kraaij and Matthias Walter
8 | *
9 | * \brief Recognition of [balanced matrices](\ref balanced).
10 | */
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | typedef enum
23 | {
24 | CMR_BALANCED_ALGORITHM_AUTO = 0, /**< \brief Automatically select a fast algorithm. */
25 | CMR_BALANCED_ALGORITHM_SUBMATRIX = 1, /**< \brief Exponential-time enumeration algorithm based on submatrices. */
26 | CMR_BALANCED_ALGORITHM_GRAPH = 2 /**< \brief Polynomial-time algorithm based on graphs. */
27 | } CMR_BALANCED_ALGORITHM;
28 |
29 | typedef struct
30 | {
31 | CMR_BALANCED_ALGORITHM algorithm; /**< \brief Algorithm to use. */
32 | bool seriesParallel; /**< \brief Whether to carry out series-parallel operations as preprocessing. */
33 | } CMR_BALANCED_PARAMS;
34 |
35 | /**
36 | * \brief Initializes the default parameters for recognition of [balanced](\ref balanced) matrices.
37 | */
38 |
39 | CMR_EXPORT
40 | CMR_ERROR CMRbalancedParamsInit(
41 | CMR_BALANCED_PARAMS* params /**< Pointer to parameters. */
42 | );
43 |
44 | /**
45 | * \brief Statistics for recognition algorithm for [balanced](\ref balanced) matrices.
46 | */
47 |
48 | typedef struct
49 | {
50 | uint32_t totalCount; /**< Total number of invocations. */
51 | double totalTime; /**< Total time of all invocations. */
52 | CMR_SP_STATISTICS seriesParallel; /**< Statistics for series-parallel algorithm. */
53 | size_t enumeratedRowSubsets; /**< Number of enumerated row subsets. */
54 | size_t enumeratedColumnSubsets; /**< Number of enumerated column subsets. */
55 | } CMR_BALANCED_STATS;
56 |
57 | /**
58 | * \brief Initializes all statistics for recognition algorithm for [balanced](\ref balanced) matrices.
59 | */
60 |
61 | CMR_EXPORT
62 | CMR_ERROR CMRbalancedStatsInit(
63 | CMR_BALANCED_STATS* stats /**< Pointer to statistics. */
64 | );
65 |
66 | /**
67 | * \brief Prints statistics for recognition algorithm for [balanced](\ref balanced) matrices.
68 | */
69 |
70 | CMR_EXPORT
71 | CMR_ERROR CMRbalancedStatsPrint(
72 | FILE* stream, /**< File stream to print to. */
73 | CMR_BALANCED_STATS* stats, /**< Pointer to statistics. */
74 | const char* prefix /**< Prefix string to prepend to each printed line (may be \c NULL). */
75 | );
76 |
77 | /**
78 | * \brief Tests a matrix \f$ M \f$ for being [balanced](\ref balanced).
79 | *
80 | * Tests if matrix \f$ M \f$ is balanced and sets \p *pisBalanced accordingly.
81 | * Automatically decides which algorithm to use.
82 | *
83 | * If \f$ M \f$ is not balanced and \p psubmatrix != \c NULL, then \p *psubmatrix will indicate a submatrix
84 | * of \f$ M \f$ with exactly two nonzeros in each row and in each column and with determinant \f$ -2 \f$ or \f$ 2 \f$.
85 | */
86 |
87 | CMR_EXPORT
88 | CMR_ERROR CMRbalancedTest(
89 | CMR* cmr, /**< \ref CMR environment */
90 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
91 | bool* pisBalanced, /**< Pointer for storing whether \f$ M \f$ is balanced. */
92 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a minimal nonbalanced submatrix (may be \c NULL). */
93 | CMR_BALANCED_PARAMS* params, /**< Parameters for the computation (may be \c NULL for defaults). */
94 | CMR_BALANCED_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
95 | double timeLimit /**< Time limit to impose. */
96 | );
97 |
98 | #ifdef __cplusplus
99 | }
100 | #endif
101 |
102 | #endif /* CMR_BALANCED_H */
103 |
--------------------------------------------------------------------------------
/include/cmr/camion.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_CAMION_H
2 | #define CMR_CAMION_H
3 |
4 | /**
5 | * \file camion.h
6 | *
7 | * \author Matthias Walter
8 | *
9 | * \brief Testing whether a matrix is [Camion-signed](\ref camion).
10 | */
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #include
17 | #include
18 |
19 | #include
20 |
21 | /**
22 | * \brief Statistics for [Camion-signing](\ref camion) algorithm.
23 | */
24 |
25 | typedef struct
26 | {
27 | uint32_t generalCount; /**< Number of invocations for general matrices. */
28 | double generalTime; /**< Total time for all invocations for general matrices. */
29 | uint32_t graphCount; /**< Number of invocations for graphic matrices. */
30 | double graphTime; /**< Total time for all invocations for graphic matrices. */
31 | uint32_t totalCount; /**< Total number of invocations. */
32 | double totalTime; /**< Total time for all invocations. */
33 | } CMR_CAMION_STATISTICS;
34 |
35 | /**
36 | * \brief Initializes all statistics for [Camion-signing](\ref camion) algorithm.
37 | */
38 |
39 | CMR_EXPORT
40 | CMR_ERROR CMRcamionStatsInit(
41 | CMR_CAMION_STATISTICS* stats /**< Pointer to statistics. */
42 | );
43 |
44 | /**
45 | * \brief Prints statistics for [Camion-signing](\ref camion) algorithm.
46 | */
47 |
48 | CMR_EXPORT
49 | CMR_ERROR CMRcamionStatsPrint(
50 | FILE* stream, /**< File stream to print to. */
51 | CMR_CAMION_STATISTICS* stats, /**< Pointer to statistics. */
52 | const char* prefix /**< Prefix string to prepend to each printed line (may be \c NULL). */
53 | );
54 |
55 |
56 | /**
57 | * \brief Tests a matrix \f$ M \f$ for being a [Camion-signed](\ref camion).
58 | */
59 |
60 | CMR_EXPORT
61 | CMR_ERROR CMRcamionTestSigns(
62 | CMR* cmr, /**< \ref CMR environment. */
63 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
64 | bool* pisCamionSigned, /**< Pointer for storing whether \f$ M \f$ is [Camion-signed](\ref camion). */
65 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a non-Camion submatrix (may be \c NULL). */
66 | CMR_CAMION_STATISTICS* stats, /**< Statistics for the computation (may be \c NULL). */
67 | double timeLimit /**< Time limit to impose. */
68 | );
69 |
70 | /**
71 | * \brief Computes a [Camion-signed](\ref camion) version of a given ternary matrix \f$ M \f$.
72 | */
73 |
74 | CMR_EXPORT
75 | CMR_ERROR CMRcamionComputeSigns(
76 | CMR* cmr, /**< \ref CMR environment. */
77 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$ to be modified. */
78 | bool* pwasCamionSigned, /**< Pointer for storing whether \f$ M \f$ was already [Camion-signed](\ref camion). */
79 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a non-Camion submatrix (may be \c NULL). */
80 | CMR_CAMION_STATISTICS* stats, /**< Statistics for the computation (may be \c NULL). */
81 | double timeLimit /**< Time limit to impose. */
82 | );
83 |
84 |
85 | /**
86 | * \brief Orients the edges of the graph \p cograph such that the matrix \p matrix \f$ M \f$ is the corresponding
87 | * network matrix, which implicitly tests if \p matrix is [Camion-signed](\ref camion).
88 | *
89 | * The cograph \f$ G = (V,E) \f$ has a spanning tree \f$ T \subseteq E \f$ indexed by the columns of \f$ M \f$.
90 | * Its complement \f$ E \setminus T \f$ is indexed by the rows of \f$ M \f$. The function assumes that
91 | * \f$ supp(M) = M(G,T)^\textsf{T} \f$ holds and attempts to compute an orientation \f$ A \f$ of the edges \f$ E \f$
92 | * (which is stored in \p arcsReversed) that corresponds to the signs of \f$ M \f$. \p *pisCamionSigned indicates
93 | * success. If successful, \f$ M \f$ is the network matrix of the digraph \f$ D = (V,A) \f$. Otherwise,
94 | * \p *psubmatrix will indicate a violating submatrix (if not \c NULL).
95 | */
96 |
97 | CMR_EXPORT
98 | CMR_ERROR CMRcamionCographicOrient(
99 | CMR* cmr, /**< \ref CMR environment. */
100 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
101 | CMR_GRAPH* cograph, /**< Cograph \f$ G = (V,E) \f$ claimed to correspond to \f$ M \f$. */
102 | CMR_GRAPH_EDGE* forestEdges, /**< \f$ T \f$, ordered by the columns of \f$ M \f$. */
103 | CMR_GRAPH_EDGE* coforestEdges, /**< \f$ E \setminus T \f$, ordered by the rows of \f$ M \f$. */
104 | bool* arcsReversed, /**< Indicates, for each edge \f$ \{u, v\} \in E\f$, whether \f$ (u,v) \in A \f$
105 | ** (if \c false) or \f$ (v,u) \in A \f$ (if \c true). */
106 | bool* pisCamionSigned, /**< Pointer for storing whether \f$ M \f$ is [Camion-signed](\ref camion). */
107 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a non-Camion submatrix (may be \c NULL). */
108 | CMR_CAMION_STATISTICS* stats /**< Statistics for the computation (may be \c NULL). */
109 | );
110 |
111 |
112 | #ifdef __cplusplus
113 | }
114 | #endif
115 |
116 | #endif /* CMR_CAMION_H */
117 |
--------------------------------------------------------------------------------
/include/cmr/config.h.in:
--------------------------------------------------------------------------------
1 | #define CMR_CMAKE_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
2 | #define CMR_VERSION_MAJOR @CMR_VERSION_MAJOR@
3 | #define CMR_VERSION_MINOR @CMR_VERSION_MINOR@
4 | #define CMR_VERSION_PATCH @CMR_VERSION_PATCH@
5 |
6 | #cmakedefine CMR_WITH_GMP
7 |
--------------------------------------------------------------------------------
/include/cmr/ctu.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_CTU_H
2 | #define CMR_CTU_H
3 |
4 | /**
5 | * \file ctu.h
6 | *
7 | * \author Matthias Walter and Klaus Truemper
8 | *
9 | * \brief Recognition of [complement totally unimodular matrices](\ref ctu).
10 | */
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | typedef struct
21 | {
22 | CMR_TU_PARAMS tu; /**< \brief Parameters for TU test. */
23 | } CMR_CTU_PARAMS;
24 |
25 | /**
26 | * \brief Initializes the default parameters for recognition of [complement totally unimodular](\ref ctu) matrices.
27 | *
28 | * These are selected for minimum running time.
29 | */
30 |
31 | CMR_EXPORT
32 | CMR_ERROR CMRctuParamsInit(
33 | CMR_CTU_PARAMS* params /**< Pointer to parameters. */
34 | );
35 |
36 | /**
37 | * \brief Statistics for recognition algorithm for [totally unimodular](\ref tu) matrices.
38 | */
39 |
40 | typedef struct
41 | {
42 | uint32_t totalCount; /**< Total number of invocations. */
43 | double totalTime; /**< Total time of all invocations. */
44 | CMR_TU_STATS tu; /**< Total unimodularity test. */
45 | } CMR_CTU_STATISTICS;
46 |
47 | /**
48 | * \brief Initializes all statistics for recognition algorithm for [complement totally unimodular](\ref ctu) matrices.
49 | */
50 |
51 | CMR_EXPORT
52 | CMR_ERROR CMRstatsComplementTotalUnimodularityInit(
53 | CMR_CTU_STATISTICS* stats /**< Pointer to statistics. */
54 | );
55 |
56 | /**
57 | * \brief Prints statistics for recognition algorithm for [complement totally unimodular](\ref ctu) matrices.
58 | */
59 |
60 | CMR_EXPORT
61 | CMR_ERROR CMRstatsComplementTotalUnimodularityPrint(
62 | FILE* stream, /**< File stream to print to. */
63 | CMR_CTU_STATISTICS* stats, /**< Pointer to statistics. */
64 | const char* prefix /**< Prefix string to prepend to each printed line (may be \c NULL). */
65 | );
66 |
67 | /**
68 | * \brief Carries out a row- and column-complement operations on the binary matrix.
69 | */
70 |
71 | CMR_EXPORT
72 | CMR_ERROR CMRctuComplementRowColumn(
73 | CMR* cmr, /**< \ref CMR environment */
74 | CMR_CHRMAT* matrix, /**< Input matrix. */
75 | size_t complementRow, /**< Row to be complemented (\c SIZE_MAX for no row complement). */
76 | size_t complementColumn, /**< Column to be complemented (\c SIZE_MAX for no column complement). */
77 | CMR_CHRMAT** presult /**< Resulting matrix. */
78 | );
79 |
80 | /**
81 | * \brief Tests a matrix \f$ M \f$ for being [complement totally unimodular](\ref ctu).
82 | *
83 | * Tests if matrix \f$ M \f$ is complement totally unimodular and sets \p *pisComplementTotallyUnimodular accordingly.
84 | *
85 | * If \f$ M \f$ is not complement totally unimodular and \p pcomplementRow != \c NULL and
86 | * \p pcomplementColumn != \c NULL, then \p *pcomplementRow and \p *pcomplementColumn will indicate the row and column
87 | * that need to be complemented for obtaining a matrix that is not [totally unimodular](\ref tu).
88 | * If no row/column needs to be complemented, then the respective variables are set to \c SIZE_MAX.
89 | */
90 |
91 | CMR_EXPORT
92 | CMR_ERROR CMRctuTest(
93 | CMR* cmr, /**< \ref CMR environment */
94 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
95 | bool* pisComplementTotallyUnimodular, /**< Pointer for storing whether \f$ M \f$ is complement totally unimodular. */
96 | size_t* pcomplementRow, /**< Pointer for storing the row to be complemented (may be \c NULL). */
97 | size_t* pcomplementColumn, /**< Pointer for storing the column to be complemented (may be \c NULL). */
98 | CMR_CTU_PARAMS* params, /**< Parameters for the computation (may be \c NULL for defaults). */
99 | CMR_CTU_STATISTICS* stats, /**< Statistics for the computation (may be \c NULL). */
100 | double timeLimit /**< Time limit to impose. */
101 | );
102 |
103 | #ifdef __cplusplus
104 | }
105 | #endif
106 |
107 | #endif /* CMR_CTU_H */
108 |
--------------------------------------------------------------------------------
/include/cmr/element.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_ELEMENT_H
2 | #define CMR_ELEMENT_H
3 |
4 | /**
5 | * \file element.h
6 | *
7 | * \author Matthias Walter
8 | *
9 | * \brief Functionality for the row and column **elements** of a matrix.
10 | */
11 |
12 | #include
13 |
14 | #include
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | typedef int CMR_ELEMENT;
21 |
22 | CMR_EXPORT
23 | const char* CMRelementString(
24 | CMR_ELEMENT element, /**< Element to print. */
25 | char* buffer /**< Buffer of size at least 32. May be \c NULL, in which case a static buffer is used. */
26 | );
27 |
28 | /**
29 | * \brief Returns \c true if \p element is a row or a column element.
30 | */
31 |
32 | static inline
33 | bool CMRelementIsValid(
34 | CMR_ELEMENT element /**< Element to check for validity. */
35 | )
36 | {
37 | return element != 0;
38 | }
39 |
40 | static inline
41 | CMR_ELEMENT CMRrowToElement(
42 | size_t row /**< Row index. */
43 | )
44 | {
45 | return -1 - (int)row;
46 | }
47 |
48 | static inline
49 | CMR_ELEMENT CMRcolumnToElement(
50 | size_t column /**< Column index. */
51 | )
52 | {
53 | return 1 + (int)column;
54 | }
55 |
56 | static inline
57 | bool CMRelementIsRow(
58 | CMR_ELEMENT element /**< Element to check. */
59 | )
60 | {
61 | return element < 0;
62 | }
63 |
64 | static inline
65 | size_t CMRelementToRowIndex(
66 | CMR_ELEMENT element /**< Element to convert. */
67 | )
68 | {
69 | assert(element < 0);
70 | return -1 - element;
71 | }
72 |
73 | static inline
74 | bool CMRelementIsColumn(
75 | CMR_ELEMENT element /**< Element to check. */
76 | )
77 | {
78 | return element > 0;
79 | }
80 |
81 | static inline
82 | size_t CMRelementToColumnIndex(
83 | CMR_ELEMENT element /**< Element to convert. */
84 | )
85 | {
86 | assert(element > 0);
87 | return -1 + element;
88 | }
89 |
90 | /**
91 | * \brief Transposes \p element, i.e., turns rows into columns and vice versa.
92 | */
93 |
94 | static inline
95 | CMR_ELEMENT CMRelementTranspose(
96 | CMR_ELEMENT element /**< Element to transpose. */
97 | )
98 | {
99 | return -element;
100 | }
101 |
102 | #ifdef __cplusplus
103 | }
104 | #endif
105 |
106 | #endif /* CMR_ELEMENT_H */
107 |
--------------------------------------------------------------------------------
/include/cmr/linear_algebra.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_LINEAR_ALGEBRA_H
2 | #define CMR_LINEAR_ALGEBRA_H
3 |
4 | /**
5 | * \file linear_algebra.h
6 | *
7 | * \author Matthias Walter
8 | */
9 |
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | /**
21 | * \brief Computes the determinant of an 8-bit integer matrix.
22 | */
23 |
24 | CMR_EXPORT
25 | CMR_ERROR CMRchrmatDeterminant(
26 | CMR* cmr, /**< \ref CMR environment. */
27 | CMR_CHRMAT* matrix, /**< Matrix. */
28 | int64_t* pdeterminant /**< Pointer for storing the determinant. */
29 | );
30 |
31 | /**
32 | * \brief Computes the determinant of an int matrix.
33 | */
34 |
35 | CMR_EXPORT
36 | CMR_ERROR CMRintmatDeterminant(
37 | CMR* cmr, /**< \ref CMR environment. */
38 | CMR_INTMAT* matrix, /**< Matrix. */
39 | int64_t* pdeterminant /**< Pointer for storing the determinant. */
40 | );
41 |
42 | #ifdef __cplusplus
43 | }
44 | #endif
45 |
46 | #endif /* CMR_LINEAR_ALGEBRA_H */
47 |
--------------------------------------------------------------------------------
/include/cmr/named.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_NAMED_H
2 | #define CMR_NAMED_H
3 |
4 | /**
5 | * \file special.h
6 | *
7 | * \author Matthias Walter
8 | *
9 | * \brief Functionality for special matrix.
10 | */
11 |
12 | #include
13 | #include
14 |
15 | #ifdef __cplusplus
16 | extern "C" {
17 | #endif
18 |
19 | /**
20 | * \brief Checks if the given \p matrix is an identity matrix.
21 | *
22 | * If \p matrix is not identity matrix then \p *porder indicates the order; Otherwise, it is set to \c SIZE_MAX.
23 | */
24 |
25 | CMR_EXPORT
26 | CMR_ERROR CMRisIdentityMatrix(
27 | CMR* cmr, /**< \ref CMR environment. */
28 | CMR_CHRMAT* matrix, /**< Matrix. */
29 | size_t* porder /**< Pointer for storing the order of the matrix. */
30 | );
31 |
32 | /**
33 | * \brief Constructs an identity matrix of given \p order.
34 | */
35 |
36 | CMR_EXPORT
37 | CMR_ERROR CMRcreateIdentityMatrix(
38 | CMR* cmr, /**< \ref CMR environment. */
39 | size_t order, /**< Order of the matrix. */
40 | CMR_CHRMAT** presult /**< Pointer for storing the matrix. */
41 | );
42 |
43 | /**
44 | * \brief Checks if the given \p matrix represents the matroid \f$ R_{10} \f$.
45 | */
46 |
47 | CMR_EXPORT
48 | CMR_ERROR CMRisR10Matrix(
49 | CMR* cmr, /**< \ref CMR environment. */
50 | CMR_CHRMAT* matrix, /**< Matrix. */
51 | size_t* pisR10 /**< Pointer for storing the representation matrix index. */
52 | );
53 |
54 | /**
55 | * \brief Constructs a representation matrix for \f$ R_{10} \f$.
56 | */
57 |
58 | CMR_EXPORT
59 | CMR_ERROR CMRcreateR10Matrix(
60 | CMR* cmr, /**< \ref CMR environment. */
61 | size_t index, /**< Which of the two matrices to return; among {1,2}. */
62 | CMR_CHRMAT** presult /**< Pointer for storing the matrix. */
63 | );
64 |
65 | /**
66 | * \brief Checks if the given \p matrix represents the matroid \f$ R_{12} \f$.
67 | */
68 |
69 | CMR_EXPORT
70 | CMR_ERROR CMRisR12Matrix(
71 | CMR* cmr, /**< \ref CMR environment. */
72 | CMR_CHRMAT* matrix, /**< Matrix. */
73 | size_t* pisR12 /**< Pointer for storing the representation matrix index. */
74 | );
75 |
76 | /**
77 | * \brief Constructs a representation matrix for \f$ R_{12} \f$.
78 | */
79 |
80 | CMR_EXPORT
81 | CMR_ERROR CMRcreateR12Matrix(
82 | CMR* cmr, /**< \ref CMR environment. */
83 | size_t index, /**< Which of the matrices to return; must be 1. */
84 | CMR_CHRMAT** presult /**< Pointer for storing the matrix. */
85 | );
86 |
87 | /**
88 | * \brief Constructs a representation matrix for \f$ M(K_5) \f$.
89 | */
90 |
91 | CMR_EXPORT
92 | CMR_ERROR CMRcreateK5Matrix(
93 | CMR* cmr, /**< \ref CMR environment. */
94 | size_t index, /**< Which of the matrices to return; must be 1. */
95 | CMR_CHRMAT** presult /**< Pointer for storing the matrix. */
96 | );
97 |
98 | /**
99 | * \brief Constructs a representation matrix for \f$ M(K_{3,3}) \f$.
100 | */
101 |
102 | CMR_EXPORT
103 | CMR_ERROR CMRcreateK33Matrix(
104 | CMR* cmr, /**< \ref CMR environment. */
105 | size_t index, /**< Which of the matrices to return; must be 1. */
106 | CMR_CHRMAT** presult /**< Pointer for storing the matrix. */
107 | );
108 |
109 | #ifdef __cplusplus
110 | }
111 | #endif
112 |
113 | #endif /* CMR_NAMED_H */
114 |
115 |
--------------------------------------------------------------------------------
/include/cmr/regular.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_REGULAR_H
2 | #define CMR_REGULAR_H
3 |
4 | /**
5 | * \file regular.h
6 | *
7 | * \author Matthias Walter and Klaus Truemper
8 | *
9 | * \brief Recognition of [binary regular matrices](\ref binary_regular).
10 | */
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | typedef struct
26 | {
27 | CMR_SEYMOUR_PARAMS seymour;
28 | } CMR_REGULAR_PARAMS;
29 |
30 | /**
31 | * \brief Initializes the default parameters for regularity testing.
32 | *
33 | * These are selected for minimum running time.
34 | */
35 |
36 | CMR_EXPORT
37 | CMR_ERROR CMRregularParamsInit(
38 | CMR_REGULAR_PARAMS* params /**< Pointer to parameters. */
39 | );
40 |
41 | /**
42 | * \brief Statistics for regular matroid recognition algorithm.
43 | */
44 |
45 | typedef struct
46 | {
47 | CMR_SEYMOUR_STATS seymour; /**< Statistics for Seymour decomposition computations. */
48 | } CMR_REGULAR_STATS;
49 |
50 |
51 | /**
52 | * \brief Initializes all statistics for regularity test computations.
53 | */
54 |
55 | CMR_EXPORT
56 | CMR_ERROR CMRregularStatsInit(
57 | CMR_REGULAR_STATS* stats /**< Pointer to statistics. */
58 | );
59 |
60 | /**
61 | * \brief Prints statistics for regularity test computations.
62 | */
63 |
64 | CMR_EXPORT
65 | CMR_ERROR CMRregularStatsPrint(
66 | FILE* stream, /**< File stream to print to. */
67 | CMR_REGULAR_STATS* stats, /**< Pointer to statistics. */
68 | const char* prefix /**< Prefix string to prepend to each printed line (may be \c NULL). */
69 | );
70 |
71 | /**
72 | * \brief Tests binary linear matroid for regularity.
73 | *
74 | * If \p pdec is not \c NULL, \c *pdec will be a (partial) decomposition tree.
75 | * If \p completeTree is \c true, then the decomposition tree is complete. Otherwise, it must only contain sufficient
76 | * information in order to determine regularity.
77 | *
78 | * If \p pminor is not \c NULL and \p matrix is not regular, then an \f$ F_7 \f$ or \f$ F_7^\star \f$ minor is searched.
79 | * This causes additional computational effort!
80 | */
81 |
82 | CMR_EXPORT
83 | CMR_ERROR CMRregularTest(
84 | CMR* cmr, /**< \ref CMR environment. */
85 | CMR_CHRMAT* matrix, /**< Input matrix. */
86 | bool *pisRegular, /**< Pointer for storing whether \p matrix is regular. */
87 | CMR_SEYMOUR_NODE** proot, /**< Pointer for storing the Seymour decomposition tree (may be \c NULL). */
88 | CMR_MINOR** pminor, /**< Pointer for storing an \f$ F_7 \f$ or \f$ F_7^\star \f$ minor. */
89 | CMR_REGULAR_PARAMS* params, /**< Parameters for the computation (may be \c NULL for defaults). */
90 | CMR_REGULAR_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
91 | double timeLimit /**< Time limit to impose. */
92 | );
93 |
94 | /**
95 | * \brief Completes a subtree of an existing decomposition tree.
96 | *
97 | * Replace the node's subtree by a new one even if it exists. Note that different parameters may yield a different
98 | * subtree.
99 | */
100 |
101 | CMR_EXPORT
102 | CMR_ERROR CMRregularCompleteDecomposition(
103 | CMR* cmr, /**< \ref CMR environment. */
104 | CMR_SEYMOUR_NODE* dec, /**< Pointer to the decomposition node that is the root of the new subtree. */
105 | CMR_REGULAR_PARAMS* params, /**< Parameters for the computation (may be \c NULL). */
106 | CMR_REGULAR_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
107 | double timeLimit /**< Time limit to impose. */
108 | );
109 |
110 | /**
111 | * \brief Refines a list of decomposition nodes.
112 | *
113 | * Replace the nodes' subtrees by new ones even if they exist.
114 | */
115 |
116 | CMR_EXPORT
117 | CMR_ERROR CMRregularRefineDecomposition(
118 | CMR* cmr, /**< \ref CMR environment. */
119 | size_t numNodes, /**< Number of nodes to refine. */
120 | CMR_SEYMOUR_NODE** nodes, /**< Array of decomposition nodes to refine. */
121 | CMR_REGULAR_PARAMS* params, /**< Parameters for the computation (may be \c NULL). */
122 | CMR_REGULAR_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
123 | double timeLimit /**< Time limit to impose. */
124 | );
125 |
126 | #ifdef __cplusplus
127 | }
128 | #endif
129 |
130 | #endif /* CMR_REGULAR_H */
131 |
132 |
--------------------------------------------------------------------------------
/include/cmr/tu.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_TU_H
2 | #define CMR_TU_H
3 |
4 | /**
5 | * \file tu.h
6 | *
7 | * \author Matthias Walter and Klaus Truemper
8 | *
9 | * \brief Recognition of [totally unimodular matrices](\ref tu).
10 | */
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | typedef enum
22 | {
23 | CMR_TU_ALGORITHM_DECOMPOSITION = 0, /**< \brief Algorithm based on Seymour's decomposition of regular matroids. */
24 | CMR_TU_ALGORITHM_EULERIAN = 1, /**< \brief Enumeration algorithm based on Eulerian submatrices. */
25 | CMR_TU_ALGORITHM_PARTITION = 2 /**< \brief Enumeration algorithm based on criterion of Ghouila-Houri. */
26 | } CMR_TU_ALGORITHM;
27 |
28 | typedef struct
29 | {
30 | CMR_TU_ALGORITHM algorithm; /**< \brief Algorithm to use. */
31 | CMR_SEYMOUR_PARAMS seymour; /**< \brief Parameters for testing via Seymour decomposition. */
32 | bool ternary; /**< \brief Whether to create a ternary Seymour decomposition tree (default: \c true). */
33 | bool camionFirst; /**< \brief If \c ternary is \c false, then whether to run the Camion test first. */
34 | bool naiveSubmatrix; /**< \brief Whether to use the naive submatrix search instead of a greedy algorithm
35 | ** (default: \c false). */
36 | } CMR_TU_PARAMS;
37 |
38 | /**
39 | * \brief Initializes the default parameters for recognition of [totally unimodular](\ref tu) matrices.
40 | *
41 | * These are selected for minimum running time.
42 | */
43 |
44 | CMR_EXPORT
45 | CMR_ERROR CMRtuParamsInit(
46 | CMR_TU_PARAMS* params /**< Pointer to parameters. */
47 | );
48 |
49 | /**
50 | * \brief Statistics for recognition algorithm for [totally unimodular](\ref tu) matrices.
51 | */
52 |
53 | typedef struct
54 | {
55 | CMR_SEYMOUR_STATS seymour; /**< Statistics for Seymour decomposition computation. */
56 | CMR_CAMION_STATISTICS camion; /**< Statistics for Camion signing. */
57 |
58 | uint32_t enumerationTotalCount; /**< Total number of invocations. */
59 | uint32_t enumerationRowSubsets; /**< Number of considered row subsets in enumeration algorithm. */
60 | uint32_t enumerationColumnSubsets; /**< Number of considered column subsets in enumeration algorithm. */
61 | double enumerationTime; /**< Total time of enumeration algorithm. */
62 |
63 | uint32_t partitionTotalCount; /**< Total number of invocations. */
64 | uint32_t partitionRowSubsets; /**< Number of considered row subsets in partition algorithm. */
65 | uint32_t partitionColumnSubsets; /**< Number of considered column subsets in partition algorithm. */
66 | double partitionTime; /**< Total time of partition algorithm. */
67 | } CMR_TU_STATS;
68 |
69 | /**
70 | * \brief Initializes all statistics for recognition algorithm for [totally unimodular](\ref tu) matrices.
71 | */
72 |
73 | CMR_EXPORT
74 | CMR_ERROR CMRtuStatsInit(
75 | CMR_TU_STATS* stats /**< Pointer to statistics. */
76 | );
77 |
78 | /**
79 | * \brief Prints statistics for recognition algorithm for [totally unimodular](\ref tu) matrices.
80 | */
81 |
82 | CMR_EXPORT
83 | CMR_ERROR CMRtuStatsPrint(
84 | FILE* stream, /**< File stream to print to. */
85 | CMR_TU_STATS* stats, /**< Pointer to statistics. */
86 | const char* prefix /**< Prefix string to prepend to each printed line (may be \c NULL). */
87 | );
88 |
89 | /**
90 | * \brief Tests a matrix \f$ M \f$ for being [totally unimodular](\ref tu).
91 | *
92 | * Tests if matrix \f$ M \f$ is totally unimodular and sets \p *pisTotallyUnimodular accordingly.
93 | *
94 | * If \f$ M \f$ is totally unimodular and \p pdec != \c NULL, then \p *pdec will contain a decomposition tree of the
95 | * regular matroid. The caller must release it via \ref CMRdecFree().
96 | *
97 | * If \f$ M \f$ is not totally unimodular and \p psubmatrix != \c NULL, then \p *psubmatrix will indicate a submatrix
98 | * of \f$ M \f$ with determinant \f$ -2 \f$ or \f$ 2 \f$.
99 | */
100 |
101 | CMR_EXPORT
102 | CMR_ERROR CMRtuTest(
103 | CMR* cmr, /**< \ref CMR environment */
104 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
105 | bool* pisTotallyUnimodular, /**< Pointer for storing whether \f$ M \f$ is totally unimodular. */
106 | CMR_SEYMOUR_NODE** proot, /**< Pointer for storing the decomposition tree (may be \c NULL). */
107 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a submatrix with non-ternary determinant (may be \c NULL). */
108 | CMR_TU_PARAMS* params, /**< Parameters for the computation (may be \c NULL for defaults). */
109 | CMR_TU_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
110 | double timeLimit /**< Time limit to impose. */
111 | );
112 |
113 | /**
114 | * \brief Completes a subtree of an existing decomposition tree.
115 | *
116 | * Replace the node's subtree by a new one even if it exists. Note that different parameters may yield a different
117 | * subtree.
118 | *
119 | * \note Requires \p params.algorithm to be \ref CMR_TU_ALGORITHM_DECOMPOSITION.
120 | */
121 |
122 | CMR_EXPORT
123 | CMR_ERROR CMRtuCompleteDecomposition(
124 | CMR* cmr, /**< \ref CMR environment. */
125 | CMR_SEYMOUR_NODE* dec, /**< Pointer to the decomposition node that is the root of the new subtree. */
126 | CMR_TU_PARAMS* params, /**< Parameters for the computation. */
127 | CMR_TU_STATS* stats, /**< Statistics for the computation (may be \c NULL). */
128 | double timeLimit /**< Time limit to impose. */
129 | );
130 |
131 | #ifdef __cplusplus
132 | }
133 | #endif
134 |
135 | #endif /* CMR_TU_H */
136 |
--------------------------------------------------------------------------------
/src/cmr/bipartite_graph.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_BIPARTITE_GRAPH_INTERNAL_H
2 | #define CMR_BIPARTITE_GRAPH_INTERNAL_H
3 |
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | /**
12 | * \brief Finds a shortest path between different vertex groups in the bipartite graph of a submatrix of the given
13 | * \p matrix.
14 | *
15 | * The bipartite graph of a matrix \f$ M \f$ has the rows and columns of as vertices and edges for all nonzeros of
16 | * \f$ M \f$. The rows and columns are assigned to groups, and some shortest path from any nonzero group to any larger
17 | * nonzero group will be returned. Vertices whose group is negative are ignored.
18 | *
19 | * A negative row/column group value means to disable the node. Positive values indicate different groups.
20 | */
21 |
22 | CMR_ERROR CMRchrmatSubmatrixBipartitePath(
23 | CMR* cmr, /**< \ref CMR environment. */
24 | CMR_CHRMAT* matrix, /**< Matrix. */
25 | CMR_CHRMAT* transpose, /**< Transpose of \p matrix. */
26 | int* rowsGroup, /**< Array that specifies each row's group. */
27 | int* columnsGroup, /**< Array that specifies each column's group. */
28 | bool* pconnected, /**< Pointer for storing whether such a path exists; may be \c NULL. */
29 | CMR_ELEMENT* ppathSource, /**< Pointer for storing the source row/column; set to invalid if no path exists;
30 | ** may be \c NULL. */
31 | CMR_ELEMENT* ppathTarget, /**< Pointer for storing the target row/column; set to invalid if no path exists;
32 | ** may be \c NULL. */
33 | CMR_ELEMENT* rowsPredecessor, /**< Array for storing the predecessor of each row vertex; may be \c NULL. */
34 | CMR_ELEMENT* columnsPredecessor, /**< Array for storing the predecessor of each column vertex; may be \c NULL. */
35 | int* psum /**< Pointer for storing the sum of the edge entries on the path; may be \c NULL. */
36 | );
37 |
38 | #ifdef __cplusplus
39 | }
40 | #endif
41 |
42 | #endif /* CMR_BIPARTITE_GRAPH_INTERNAL_H */
43 |
--------------------------------------------------------------------------------
/src/cmr/block_decomposition.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_BLOCK_DECOMPOSITION_H
2 | #define CMR_BLOCK_DECOMPOSITION_H
3 |
4 | #include
5 | #include "matrix_internal.h"
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | /**
12 | * \brief Information on one block of a block decomposition of a matrix.
13 | */
14 |
15 | typedef struct
16 | {
17 | CMR_MATRIX* matrix; /**< \brief Sparse matrix. */
18 | CMR_MATRIX* transpose; /**< \brief Sparse transposed matrix. */
19 | size_t* rowsToOriginal; /**< \brief Maps component rows to original matrix rows. */
20 | size_t* columnsToOriginal; /**< \brief Maps component columns to original matrix columns. */
21 | } CMR_BLOCK;
22 |
23 | /**
24 | * \brief Decomposes int matrix into 1-connected submatrices.
25 | *
26 | * Allocates an array \p components with an entry per 1-connected submatrix. The caller has to free this array and
27 | * its members.
28 | */
29 |
30 | CMR_ERROR CMRdecomposeBlocks(
31 | CMR* cmr, /**< \ref CMR environment */
32 | CMR_MATRIX* matrix, /**< Matrix */
33 | size_t matrixType, /**< Size of base type of matrix. */
34 | size_t targetType, /**< Size of base type of component matrices. */
35 | size_t* pnumBlocks, /**< Pointer for storing the number of components. */
36 | CMR_BLOCK** pblocks, /**< Pointer for storing the array with component information. */
37 | size_t* rowsToBlock, /**< Mapping of rows of \p matrix to components (may be \c NULL). */
38 | size_t* columnsToBlock, /**< Mapping of columns of \p matrix to components (may be \c NULL). */
39 | size_t* rowsToBlockRows, /**< Mapping of rows to rows of the component (may be \c NULL). */
40 | size_t* columnsToBlockColumns /**< Mapping of columns to columns of the component (may be \c NULL). */
41 | );
42 |
43 | #ifdef __cplusplus
44 | }
45 | #endif
46 |
47 | #endif /* CMR_BLOCK_DECOMPOSITION_H */
48 |
--------------------------------------------------------------------------------
/src/cmr/camion_internal.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_CAMION_INTERNAL_H
2 | #define CMR_CAMION_INTERNAL_H
3 |
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | /**
12 | * \brief Ensures that sequentially connected matrix \f$ M \f$ is [Camion-signed](\ref camion).
13 | *
14 | * The matrix \f$ M \f$ is assumed to be ternary. If sign changes are necessary, only \p matrix is modified.
15 | * In particular, \p transpose remains unchanged.
16 | *
17 | * If \p submatrix is not \c NULL and sign changes are necessary, then a submatrix with determinant
18 | * -2 or +2 is stored in \p *psubmatrix and the caller must use \ref CMRsubmatFree() to free its
19 | * memory. It is set to \c NULL if no sign changes are needed.
20 | */
21 |
22 | CMR_ERROR CMRcamionComputeSignSequentiallyConnected(
23 | CMR* cmr, /**< \ref CMR environment. */
24 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$. */
25 | CMR_CHRMAT* transpose, /**< Transpose \f$ M^{\mathsf{T}} \f$. */
26 | bool change, /**< Whether signs of \p matrix should be changed if necessary. */
27 | char* pmodification, /**< Pointer for storing which matrix was modified. */
28 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a submatrix with a bad determinant (may be \c NULL). */
29 | double timeLimit /**< Time limit to impose. */
30 | );
31 |
32 | #ifdef __cplusplus
33 | }
34 | #endif
35 |
36 | #endif /* CMR_CAMION_INTERNAL_H */
37 |
--------------------------------------------------------------------------------
/src/cmr/densematrix.c:
--------------------------------------------------------------------------------
1 | // #define CMR_DEBUG /* Uncomment to debug this file. */
2 |
3 | #include "env_internal.h"
4 | #include "densematrix.h"
5 |
6 | #include
7 | #include
8 |
9 |
10 | CMR_ERROR CMRdensebinmatrixCreate(CMR* cmr, size_t numRows, size_t numColumns, DenseBinaryMatrix** presult)
11 | {
12 | assert(cmr);
13 |
14 | CMR_CALL( CMRallocBlock(cmr, presult) );
15 | DenseBinaryMatrix* matrix = *presult;
16 |
17 | size_t size = (numRows * numColumns + (8 * sizeof(size_t)) - 1) / (8 * sizeof(size_t));
18 | CMRdbgMsg(10, "Creating %zux%zu DenseBinaryMatrix using %zu blocks each of which having %zu bytes.\n", numRows,
19 | numColumns, size, sizeof(size_t));
20 | matrix->numRows = numRows;
21 | matrix->numColumns = numColumns;
22 | matrix->data = NULL;
23 | CMR_CALL( CMRallocBlockArray(cmr, &matrix->data, size) );
24 | for (size_t i = 0; i < size; ++i)
25 | matrix->data[i] = 0UL;
26 |
27 | return CMR_OKAY;
28 | }
29 |
30 | CMR_ERROR CMRdensebinmatrixFree(CMR* cmr, DenseBinaryMatrix** pmatrix)
31 | {
32 | assert(cmr);
33 | assert(pmatrix);
34 |
35 | if (!*pmatrix)
36 | return CMR_OKAY;
37 |
38 | CMR_CALL( CMRfreeBlockArray(cmr, &(*pmatrix)->data) );
39 | CMR_CALL( CMRfreeBlockArray(cmr, pmatrix) );
40 |
41 | return CMR_OKAY;
42 | }
43 |
--------------------------------------------------------------------------------
/src/cmr/densematrix.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_DENSEMATRIX_INTERNAL_H
2 | #define CMR_DENSEMATRIX_INTERNAL_H
3 |
4 | #include "env_internal.h"
5 |
6 | #include
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | /**
13 | * \brief Dense matrix.
14 | */
15 |
16 | typedef struct
17 | {
18 | size_t* data;
19 | size_t numRows;
20 | size_t numColumns;
21 | } DenseBinaryMatrix;
22 |
23 | CMR_ERROR CMRdensebinmatrixCreate(
24 | CMR* cmr, /**< \ref CMR environment. */
25 | size_t numRows, /**< Number of rows. */
26 | size_t numColumns, /**< Number of columns. */
27 | DenseBinaryMatrix** presult /**< Pointer for storing the result. */
28 | );
29 |
30 | CMR_ERROR CMRdensebinmatrixFree(
31 | CMR* cmr, /**< \ref CMR environment. */
32 | DenseBinaryMatrix** pmatrix /**< Pointer for storing the result. */
33 | );
34 |
35 | static inline
36 | bool CMRdensebinmatrixGet(
37 | DenseBinaryMatrix* matrix, /**< Matrix. */
38 | size_t row, /**< Row index. */
39 | size_t column /**< Column index. */
40 | )
41 | {
42 | size_t index = row * matrix->numColumns + column;
43 | size_t block = matrix->data[index / (8 * sizeof(size_t))];
44 | // CMRdbgMsg(8, "CMRdensebinmatrixGet(%zu,%zu) uses index %zu in block %zu at %zu -> %d\n", row, column, index,
45 | // index / (8 * sizeof(size_t)), (index % (8 * sizeof(size_t))),
46 | // (block & (1UL << (index % (8 * sizeof(size_t))))) ? 1 : 0);
47 | return block & (1UL << (index % (8 * sizeof(size_t))));
48 | }
49 |
50 | static inline
51 | void CMRdensebinmatrixSet0(
52 | DenseBinaryMatrix* matrix, /**< Matrix. */
53 | size_t row, /**< Row index. */
54 | size_t column /**< Column index. */
55 | )
56 | {
57 | size_t index = row * matrix->numColumns + column;
58 | // CMRdbgMsg(8, "CMRdensebinmatrixSet0(%zu,%zu) uses index %zu in block %zu at %zu.\n", row, column, index,
59 | // index / (8 * sizeof(size_t)), (index % (8 * sizeof(size_t))));
60 | size_t* pblock = &matrix->data[index / (8 * sizeof(size_t))];
61 | *pblock &= ~(1UL << (index % (8 * sizeof(size_t))));
62 | }
63 |
64 | static inline
65 | void CMRdensebinmatrixSet1(
66 | DenseBinaryMatrix* matrix, /**< Matrix. */
67 | size_t row, /**< Row index. */
68 | size_t column /**< Column index. */
69 | )
70 | {
71 | size_t index = row * matrix->numColumns + column;
72 | // CMRdbgMsg(8, "CMRdensebinmatrixSet1(%zu,%zu) uses index %zu in block %zu at %zu.\n", row, column, index,
73 | // index / (8 * sizeof(size_t)), (index % (8 * sizeof(size_t))));
74 | size_t* pblock = &matrix->data[index / (8 * sizeof(size_t))];
75 | *pblock |= (1UL << (index % (8 * sizeof(size_t))));
76 | }
77 |
78 | static inline
79 | void CMRdensebinmatrixSet(
80 | DenseBinaryMatrix* matrix, /**< Matrix. */
81 | size_t row, /**< Row index. */
82 | size_t column, /**< Column index. */
83 | bool value /**< Value. */
84 | )
85 | {
86 | size_t index = row * matrix->numColumns + column;
87 | CMRdbgMsg(8, "CMRdensebinmatrixSet(%zu,%zu,%d) uses index %zu in block %zu at %zu.\n", row, column, value ? 1 : 0, index,
88 | index / (8 * sizeof(size_t)), (index % (8 * sizeof(size_t))));
89 | size_t* pblock = &matrix->data[index / (8 * sizeof(size_t))];
90 | size_t mask = (1UL << (index % (8 * sizeof(size_t))));
91 | if (value)
92 | *pblock |= mask;
93 | else
94 | *pblock &= ~mask;
95 | }
96 |
97 |
98 | static inline
99 | void CMRdensebinmatrixFlip(
100 | DenseBinaryMatrix* matrix, /**< Matrix. */
101 | size_t row, /**< Row index. */
102 | size_t column /**< Column index. */
103 | )
104 | {
105 | size_t index = row * matrix->numColumns + column;
106 | // CMRdbgMsg(8, "CMRdensebinmatrixFlip(%zu,%zu) uses index %zu in block %zu at %zu.\n", row, column, index,
107 | // index / (8 * sizeof(size_t)), (index % (8 * sizeof(size_t))));
108 | size_t* pblock = &matrix->data[index / (8 * sizeof(size_t))];
109 | size_t mask = (1UL << (index % (8 * sizeof(size_t))));
110 | if (*pblock & mask)
111 | *pblock &= ~mask;
112 | else
113 | *pblock |= mask;
114 | }
115 |
116 | #ifdef __cplusplus
117 | }
118 | #endif
119 |
120 | #endif /* CMR_LISTMATRIX_INTERNAL_H */
121 |
--------------------------------------------------------------------------------
/src/cmr/element.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | static char elementStringBuffer[32];
7 |
8 | CMR_EXPORT
9 | const char* CMRelementString(CMR_ELEMENT element, char* buffer)
10 | {
11 | if (!buffer)
12 | buffer = elementStringBuffer;
13 |
14 | if (element < 0)
15 | sprintf(buffer, "r%d", -element);
16 | else if (element > 0)
17 | sprintf(buffer, "c%d", element);
18 | else
19 | strcpy(buffer, "");
20 | return buffer;
21 | }
22 |
--------------------------------------------------------------------------------
/src/cmr/env_internal.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_ENV_INTERNAL_H
2 | #define CMR_ENV_INTERNAL_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | #if defined(CMR_DEBUG)
11 |
12 | static inline
13 | void CMRdbgMsg(int indent, const char* format, ...)
14 | {
15 | va_list args;
16 |
17 | for (int i = 0; i < indent; ++i)
18 | putchar(' ');
19 | va_start(args, format);
20 | vprintf(format, args);
21 | va_end(args);
22 | fflush(stdout);
23 | }
24 |
25 | #else /* !CMR_DEBUG */
26 |
27 | static inline
28 | void CMRdbgMsg(int indent, const char* format, ...)
29 | {
30 | CMR_UNUSED(indent);
31 | CMR_UNUSED(format);
32 | }
33 | /*#define CMRdbgMsg(...) */
34 |
35 | #endif /* CMR_DEBUG */
36 |
37 |
38 | typedef struct
39 | {
40 | char* memory; /**< \brief Raw memory. */
41 | size_t top; /**< \brief First used byte. */
42 | } CMR_STACK;
43 |
44 | struct CMR_ENVIRONMENT
45 | {
46 | char* errorMessage; /**< \brief Error message. */
47 |
48 | FILE* output; /**< \brief Output stream or \c NULL if silent. */
49 | bool closeOutput; /**< \brief Whether to close the output stream at the end. */
50 | int verbosity; /**< \brief Verbosity level. */
51 | int numThreads; /**< \brief Number of threads to use. */
52 |
53 | size_t numStacks; /**< \brief Number of allocated stacks in stack array. */
54 | size_t memStacks; /**< \brief Memory for stack array. */
55 | size_t currentStack; /**< \brief Index of last used stack. */
56 | CMR_STACK* stacks; /**< \brief Array of stacks. */
57 | };
58 |
59 | #include
60 |
61 | /**
62 | * \brief Allocates statck memory for *\p ptr.
63 | *
64 | * Stack memory shall be freed with \ref CMRfreeStack in the reverse order of allocation.
65 | * The size is determined automatically.
66 | */
67 |
68 | #define CMRallocStack(cmr, ptr) \
69 | _CMRallocStack(cmr, (void**) ptr, sizeof(**ptr))
70 |
71 | /**
72 | * \brief Carries out the allocation for \ref CMRallocStack.
73 | *
74 | * \note Use \ref CMRallocStack to allocate stack memory.
75 | */
76 |
77 | CMR_EXPORT
78 | CMR_ERROR _CMRallocStack(
79 | CMR* cmr, /**< \ref CMR environment. */
80 | void** ptr, /**< Pointer where the space shall be allocated. */
81 | size_t size /**< Space to allocate. */
82 | );
83 |
84 | /**
85 | * \brief Frees a stack memory chunk allocated with \ref CMRallocStack.
86 | */
87 |
88 | #define CMRfreeStack(cmr, ptr) \
89 | _CMRfreeStack(cmr, (void**) ptr, sizeof(**ptr))
90 |
91 | /**
92 | * \brief Carries out the deallocation for \ref CMRfreeStack.
93 | *
94 | * \note Use \ref CMRfreeStack to free stack memory.
95 | */
96 |
97 | CMR_EXPORT
98 | CMR_ERROR _CMRfreeStack(
99 | CMR* cmr, /**< \ref CMR environment. */
100 | void** ptr /**< Pointer of space to be freed. */
101 | );
102 |
103 | /**
104 | * \brief Allocates memory for an array of blocks on the stack.
105 | */
106 |
107 | #define CMRallocStackArray(cmr, ptr, length) \
108 | _CMRallocStack(cmr, (void**) ptr, sizeof(**ptr) * (length))
109 |
110 | /**
111 | * \brief Frees memory of an array of blocks on the stack.
112 | */
113 |
114 | #define CMRfreeStackArray(cmr, ptr) \
115 | _CMRfreeStack(cmr, (void**) ptr)
116 |
117 | #if !defined(NDEBUG)
118 |
119 | /**
120 | * \brief Checks stack protection fields for corruption.
121 | *
122 | * Useful for debugging memory errors.
123 | */
124 |
125 | void CMRassertStackConsistency(
126 | CMR* cmr /**< \ref CMR environment. */
127 | );
128 |
129 | #else
130 |
131 | static inline
132 | void CMRassertStackConsistency(
133 | CMR* cmr /**< \ref CMR environment. */
134 | )
135 | {
136 | CMR_UNUSED(cmr);
137 | assert(cmr);
138 | }
139 |
140 | #endif /* !NDEBUG */
141 |
142 | void CMRraiseErrorMessage(
143 | CMR* cmr, /**< \ref CMR environment. */
144 | const char* format, /**< Format string in printf-style. */
145 | ... /**< Variadic arguments. */
146 | );
147 |
148 | size_t CMRgetStackUsage(
149 | CMR* cmr /**< \ref CMR environment. */
150 | );
151 |
152 | char* CMRconsistencyMessage(const char* format, ...);
153 |
154 | #if defined(CMR_DEBUG)
155 |
156 | /**
157 | * \brief Asserts that \p call reports consistency. Otherwise, the inconsistency explanation is printed and the program
158 | * terminates.
159 | *
160 | * The following example code checks \c matrix (of type \ref CMR_CHRMAT*) for consistency using
161 | * \ref CMRchrmatConsistency.
162 | *
163 | * CMRconsistencyAssert( CMRchrmatConsistency(matrix) );
164 | */
165 |
166 | #define CMRdbgConsistencyAssert( call ) \
167 | do \
168 | { \
169 | char* __message = call; \
170 | if (__message) \
171 | { \
172 | fflush(stdout); \
173 | fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, __message); \
174 | fflush(stderr); \
175 | free(__message); \
176 | assert(!"Consistency assertion raised!"); \
177 | } \
178 | } \
179 | while (false);
180 |
181 | #else
182 |
183 | #define CMRdbgConsistencyAssert( call )
184 |
185 | #endif
186 |
187 | #endif /* CMR_ENV_INTERNAL_H */
188 |
--------------------------------------------------------------------------------
/src/cmr/graphic_internal.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_GRAPHIC_INTERNAL_H
2 | #define CMR_GRAPHIC_INTERNAL_H
3 |
4 | #include
5 |
6 | /**
7 | * \brief Computes the network or graphic matrix of a given (di)graph \f$ D = (V,A) \f$.
8 | *
9 | * Computes the [network matrix](\ref network) \f$ M := M(D,T) \f$ for given \f$ D \f$ and optionally given (directed)
10 | * spanning forest \f$ T \subseteq A \f$ or the support matrix of \f$ M(D,T) \f$.
11 | * If \f$ T \f$ is not given, an arbitrary (directed) spanning forest of \f$ D \f$ is used.
12 | * The direction of the edges is that of \p digraph, but may be flipped by specifying \p arcsReversed.
13 | * If \p forestArcs is \c NULL, an arbitrary (directed) spanning forest \f$ T \f$ of \f$ D \f$ is computed.
14 | * The ordering of the columns can be specified via \p coforestArcs.
15 | *
16 | * \note The function computes a network matrix of \f$ D \f$ (and \f$ T \f$) regardless of whether \p forestArcs is
17 | * a correct (directed) spanning forest. Whether this was the case is indicated via \p *pisCorrectForest.
18 | */
19 |
20 | CMR_ERROR CMRcomputeRepresentationMatrix(
21 | CMR* cmr, /**< \ref CMR environment. */
22 | CMR_GRAPH* digraph, /**< Digraph \f$ D = (V,A) \f$. */
23 | bool ternary, /**< Whether we need to compute correct signs. */
24 | CMR_CHRMAT** ptranspose, /**< Pointer for storing \f$ M^{\mathsf{T}} \f$ (may be \c NULL). */
25 | bool* arcsReversed, /**< Indicates, for each edge \f$ \{u, v\}\f$, whether we consider \f$ (u, v)\f$
26 | ** (if \c false) or \f$ (v,u)\f$ (if \c true). */
27 | int numForestArcs, /**< \f$ |T| \f$ (0 if \c forestArcs is \c NULL). */
28 | CMR_GRAPH_EDGE* forestArcs, /**< \f$ T \f$, ordered by the rows of \f$ M \f$ (may be \c NULL). */
29 | int numCoforestArcs, /**< \f$ |A \setminus T| \f$ (0 if \c coforestArcs is \c NULL). */
30 | CMR_GRAPH_EDGE* coforestArcs, /**< \f$ A \setminus T \f$, ordered by the columns of \f$ M \f$ (may be
31 | ** \c NULL). */
32 | bool* pisCorrectForest /**< Pointer for storing whether \c forestArcs is a (directed) spanning forest of
33 | ** \f$ D \f$'s underlying undirected graph (may be \c NULL). */
34 | );
35 |
36 | /**
37 | * \brief Tests the support matrix \f$ M \f$ of the input matrix for being a [cographic matrix](\ref graphic).
38 | *
39 | * Tests if \f$ M = M(G,T)^{\mathsf{T}} \f$ for some graph \f$ G = (V,E) \f$ and some spanning forest
40 | * \f$ T \subseteq E \f$ of \f$ G \f$ and sets \p *pisCographic accordingly.
41 | *
42 | * If \f$ M \f$ is a cographic matrix and \p pgraph != \c NULL, then one possible graph \f$ G \f$ is computed and
43 | * stored in \p *pgraph. The caller must release its memory via \ref CMRgraphFree.
44 | * If in addition to \p pgraph also \p pforestEdges != \c NULL (resp. \p pcoforestEdges != \c NULL), then a
45 | * corresponding spanning forest \f$ T \f$ (resp.\ its complement \f$ E \setminus T \f$) is stored in
46 | * \p *pforestEdges (resp. \p *pcoforestEdges). The caller must release this memory via \ref CMRfreeBlockArray.
47 | *
48 | * \note Retrieval of minimal non-cographic submatrices via \p *psubmatrix is not implemented, yet.
49 | */
50 |
51 | CMR_ERROR CMRcographicTestSupport(
52 | CMR* cmr, /**< \ref CMR environment. */
53 | CMR_CHRMAT* matrix, /**< Matrix \f$ M \f$ */
54 | bool* pisCographic, /**< Returns true if and only if \f$ M \f$ is a cographic matrix. */
55 | CMR_GRAPH** pgraph, /**< Pointer for storing the graph \f$ G \f$ (if \f$ M \f$ is graphic). */
56 | CMR_GRAPH_EDGE** pforestEdges, /**< Pointer for storing \f$ T \f$, indexed by the rows of \f$ M \f$ (if \f$ M \f$
57 | ** is graphic). */
58 | CMR_GRAPH_EDGE** pcoforestEdges, /**< Pointer for storing \f$ E \setminus T \f$, indexed by the columns of \f$ M \f$
59 | ** (if \f$ M \f$ is graphic). */
60 | CMR_GRAPHIC_STATISTICS* stats, /**< Pointer to statistics (may be \c NULL). */
61 | double timeLimit /**< Time limit to impose. */
62 | );
63 |
64 | #endif /* CMR_GRAPHIC_INTERNAL_H */
65 |
--------------------------------------------------------------------------------
/src/cmr/heap.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_HEAP_INTERNAL_H
2 | #define CMR_HEAP_INTERNAL_H
3 |
4 | #include
5 | #include "env_internal.h"
6 | #include
7 |
8 | #ifdef __cplus
9 | extern "C" {
10 | #endif
11 |
12 | /**
13 | * \brief Structure for min-heap with unsigned int values.
14 | */
15 |
16 | typedef struct
17 | {
18 | int size; /**< \brief Current size of the heap. */
19 | int memKeys; /**< \brief Memory for keys. */
20 | int* values; /**< \brief Array that maps keys to values. */
21 | int* positions; /**< \brief Array that maps keys to heap positions. */
22 | int* data; /**< \brief Array that maps heap positions to keys. */
23 | } CMR_INTHEAP;
24 |
25 | /**
26 | * \brief Initializes an empty heap using stack memory.
27 | */
28 |
29 | CMR_ERROR CMRintheapInitStack(
30 | CMR* cmr, /**< \ref CMR environment. */
31 | CMR_INTHEAP* heap, /**< Heap pointer. */
32 | int memKeys /**< Maximum number of elements and bound on key entries. */
33 | );
34 |
35 | /**
36 | * \brief Clears the given \p heap.
37 | */
38 |
39 | CMR_ERROR CMRintheapClearStack(
40 | CMR* cmr, /**< \ref CMR environment. */
41 | CMR_INTHEAP* heap /**< Heap pointer. */
42 | );
43 |
44 | /**
45 | * \brief Inserts a \p key \p value pair into the heap.
46 | */
47 |
48 | CMR_ERROR CMRintheapInsert(
49 | CMR_INTHEAP* heap, /**< Heap pointer. */
50 | int key, /**< Key of new element. */
51 | int value /**< Value of new element. */
52 | );
53 |
54 | /**
55 | * \brief Decreases the value of \p key to \p newValue.
56 | */
57 |
58 | CMR_ERROR CMRintheapDecrease(
59 | CMR_INTHEAP* heap, /**< Heap pointer. */
60 | int key, /**< Key of element. */
61 | int newValue /**< New value of element. */
62 | );
63 |
64 | /**
65 | * \brief Decreases the value of \p key to \p newValue or inserts it.
66 | */
67 |
68 | CMR_ERROR CMRintheapDecreaseInsert(
69 | CMR_INTHEAP* heap, /**< Heap pointer. */
70 | int key, /**< Key of element. */
71 | int newValue /**< New value of element. */
72 | );
73 |
74 | /**
75 | * \brief Returns \c true if the heap is empty.
76 | */
77 |
78 | static inline
79 | bool CMRintheapEmpty(
80 | CMR_INTHEAP* heap /**< Heap pointer. */
81 | )
82 | {
83 | return heap->size == 0;
84 | }
85 |
86 | /**
87 | * \brief Returns the key of the minimum element.
88 | */
89 |
90 | static inline
91 | int CMRintheapMinimumKey(
92 | CMR_INTHEAP* heap /**< Heap pointer. */
93 | )
94 | {
95 | return heap->data[0];
96 | }
97 |
98 | /**
99 | * \brief Returns the value of the minimum element.
100 | */
101 |
102 | static inline
103 | int CMRintheapMinimumValue(
104 | CMR_INTHEAP* heap /**< Heap. */
105 | )
106 | {
107 | return heap->values[heap->data[0]];
108 | }
109 |
110 | /**
111 | * \brief Returns \c true if an element with \p key is present in the heap.
112 | */
113 |
114 | static inline
115 | bool CMRintheapContains(
116 | CMR_INTHEAP* heap, /**< Heap pointer. */
117 | int key /**< Key whose existence shall be checked. */
118 | )
119 | {
120 | return heap->positions[key] >= 0;
121 | }
122 |
123 | static inline
124 | int CMRintheapGetValue(
125 | CMR_INTHEAP* heap, /*< Heap. */
126 | int key /*< Key whose value shall be returned. */
127 | )
128 | {
129 | return heap->values[key];
130 | }
131 |
132 | /**
133 | * \brief Reutrns the value of \p key or \c INT_MAX if there is no such element.
134 | */
135 |
136 | static inline
137 | int CMRintheapGetValueInfinity(
138 | CMR_INTHEAP* heap, /**< Heap pointer. */
139 | int key /**< Key to be searched. */
140 | )
141 | {
142 | if (heap->positions[key] >= 0)
143 | return heap->values[key];
144 | else
145 | return INT_MAX;
146 | }
147 |
148 | /**
149 | * \brief Extracts the minimum element and returns its key.
150 | */
151 |
152 | int CMRintheapExtractMinimum(
153 | CMR_INTHEAP* heap /**< Heap pointer. */
154 | );
155 |
156 | #ifdef __cplusplus
157 | }
158 | #endif
159 |
160 | #endif /* CMR_HEAP_INTERNAL_H */
161 |
--------------------------------------------------------------------------------
/src/cmr/hereditary_property.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_HEREDITARY_PROPERTY_H
2 | #define CMR_HEREDITARY_PROPERTY_H
3 |
4 | #include
5 | #include "env_internal.h"
6 | #include
7 | #include
8 |
9 | #ifdef __cplus
10 | extern "C" {
11 | #endif
12 |
13 | typedef CMR_ERROR (*HereditaryPropertyTest)(
14 | CMR* cmr, /**< \ref CMR environment. */
15 | CMR_CHRMAT* matrix, /**< Some matrix to be tested for the property. */
16 | void* data, /**< Potential additional data for the test function. */
17 | bool* phasProperty, /**< Pointer for storing whether \p matrix has the property. */
18 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a proper submatrix of \p matrix without the property. */
19 | double timeLimit /**< Time limit to impose. */
20 | ); /**< Function pointer for functions that test a hereditary matrix property. */
21 |
22 | /**
23 | * \brief Tests a given \p matrix for the hereditary property defined by a given \p testFunction.
24 | *
25 | * The algorithm finds the submatrix by successively single zeroing out rows or columns.
26 | */
27 |
28 | CMR_ERROR CMRtestHereditaryPropertyNaive(
29 | CMR* cmr, /**< \ref CMR environment. */
30 | CMR_CHRMAT* matrix, /**< Some matrix not having the hereditary property. */
31 | HereditaryPropertyTest testFunction, /**< Test function. */
32 | void* testData, /**< Data to be forwarded to the test function. */
33 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a minimal submatrix not having the property. */
34 | double timeLimit /**< Time limit to impose. */
35 | );
36 |
37 | /**
38 | * \brief Greedily tests a given \p matrix for the hereditary property defined by a given \p testFunction.
39 | *
40 | * The algorithm finds the submatrix by successively zeroing out sets of rows or columns.
41 | */
42 |
43 | CMR_ERROR CMRtestHereditaryPropertyGreedy(
44 | CMR* cmr, /**< \ref CMR environment. */
45 | CMR_CHRMAT* matrix, /**< Some matrix not having the hereditary property. */
46 | HereditaryPropertyTest testFunction, /**< Test function. */
47 | void* testData, /**< Data to be forwarded to the test function. */
48 | CMR_SUBMAT** psubmatrix, /**< Pointer for storing a minimal submatrix not having the property. */
49 | double timeLimit /**< Time limit to impose. */
50 | );
51 |
52 | #ifdef __cplusplus
53 | }
54 | #endif
55 |
56 | #endif /* CMR_HEREDITARY_PROPERTY_H */
57 |
--------------------------------------------------------------------------------
/src/cmr/linear_algebra_internal.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_LINALG_INTERNAL_H
2 | #define CMR_LINALG_INTERNAL_H
3 |
4 | #include
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | static inline
11 | int moduloNonnegative(int p, int q)
12 | {
13 | if (q == 0)
14 | return p;
15 | if (q < 0)
16 | q = -q;
17 | int r = p % q;
18 | if (r < 0)
19 | r += q;
20 | return r;
21 | }
22 |
23 | static inline
24 | int moduloTernary(int p, int q)
25 | {
26 | if (q == 0)
27 | return p;
28 | if (q < 0)
29 | q = -q;
30 | int r = p % q;
31 | if (r < 0)
32 | r += q;
33 | return (r == 2 && q == 3) ? -1 : r;
34 | }
35 |
36 | /**
37 | * \brief Transforms \p matrix into a new matrix by applying integer row operations and row- and column swaps to find
38 | * an upper-diagonal basis matrix.
39 | *
40 | * The rank \f$ r \f$ is stored in \p *prank and the row- and column permutations are stored in \p *ppermutations,
41 | * such that the first \f$ r \f$ rows and columns of the resulting matrix form an invertible upper-diagonal matrix.
42 | * If \p invert is \c true then in this \f$ r \f$-by-\f$ r \f$ submatrix, the largest (in terms of absolute value)
43 | * entry in each column is on the diagonal.
44 | */
45 |
46 | CMR_ERROR CMRintmatComputeUpperDiagonal(
47 | CMR* cmr, /**< \ref CMR environment. */
48 | CMR_INTMAT* matrix, /**< A matrix */
49 | bool invert, /**< Whether the transformed basis columns shall be strictly diagonally dominant. */
50 | size_t* prank, /**< Pointer for storing the rank of the basis matrix. */
51 | CMR_SUBMAT** ppermutations, /**< Pointer for storing the row- and column permutations applied to \p matrix
52 | ** (may be \c NULL). */
53 | CMR_INTMAT** presult, /**< Pointer for storing the resulting int matrix (may be \c NULL). */
54 | CMR_INTMAT** ptranspose /**< Pointer for storing the transpose of the result int matrix (may be \c NULL). */
55 | );
56 |
57 | #ifdef __cplusplus
58 | }
59 | #endif
60 |
61 | #endif /* CMR_LINALG_INTERNAL_H */
62 |
--------------------------------------------------------------------------------
/src/cmr/matrix_internal.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_MATRIX_INTERNAL_H
2 | #define CMR_MATRIX_INTERNAL_H
3 |
4 | #include
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | /**
11 | * \brief Abstract struct for row-wise representations of sparse matrices.
12 | */
13 |
14 | typedef struct
15 | {
16 | size_t numRows; /**< \brief Number of rows. */
17 | size_t numColumns; /**< \brief Number of columns. */
18 | size_t numNonzeros; /**< \brief Number of and memory allocated for nonzeros. */
19 | size_t * rowSlice; /**< \brief Array mapping each row to the index of its first entry. */
20 | size_t* entryColumns; /**< \brief Array mapping each entry to its column.*/
21 | void* entryValues; /**< \brief Array mapping each entry to its value. */
22 | } CMR_MATRIX;
23 |
24 | /**
25 | * \brief Sorts the row and column indices of \p submatrix.
26 | */
27 |
28 | CMR_ERROR CMRsortSubmatrix(
29 | CMR* cmr, /**< \ref CMR environment. */
30 | CMR_SUBMAT* submatrix /**< The submatrix. */
31 | );
32 |
33 | /**
34 | * \brief Creates a \p numRows \f$ \times \f$ \p numColumns submatrix of the char \p matrix indexed by \p rows and
35 | * \p columns.
36 | */
37 |
38 | CMR_ERROR CMRchrmatFilter(
39 | CMR* cmr, /**< \ref CMR environment. */
40 | CMR_CHRMAT* matrix, /**< Matrix. */
41 | size_t numRows, /**< Number of rows of submatrix. */
42 | size_t* rows, /**< Rows of \p matrix to be copied into the submatrix. */
43 | size_t numColumns, /**< Number of columns of submatrix. */
44 | size_t* columns, /**< Columns of \p matrix to be copied into the submatrix. */
45 | CMR_CHRMAT** presult /**< Pointer for storing the created submatrix. */
46 | );
47 |
48 | #ifdef __cplusplus
49 | }
50 | #endif
51 |
52 | #endif /* CMR_MATRIX_INTERNAL_H */
53 |
--------------------------------------------------------------------------------
/src/cmr/regular.c:
--------------------------------------------------------------------------------
1 | // #define CMR_DEBUG /** Uncomment to debug this file. */
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "env_internal.h"
10 | #include "seymour_internal.h"
11 |
12 | CMR_ERROR CMRregularParamsInit(CMR_REGULAR_PARAMS* params)
13 | {
14 | assert(params);
15 |
16 | CMR_CALL( CMRseymourParamsInit(&(params->seymour)) );
17 |
18 | return CMR_OKAY;
19 | }
20 |
21 | CMR_ERROR CMRregularStatsInit(CMR_REGULAR_STATS* stats)
22 | {
23 | assert(stats);
24 |
25 | CMR_CALL( CMRseymourStatsInit(&(stats->seymour)) );
26 |
27 | return CMR_OKAY;
28 | }
29 |
30 | CMR_ERROR CMRregularStatsPrint(FILE* stream, CMR_REGULAR_STATS* stats, const char* prefix)
31 | {
32 | assert(stream);
33 | assert(stats);
34 |
35 | CMR_CALL( CMRseymourStatsPrint(stream, &(stats->seymour), prefix) );
36 |
37 | return CMR_OKAY;
38 | }
39 |
40 |
41 | CMR_ERROR CMRregularTest(CMR* cmr, CMR_CHRMAT* matrix, bool *pisRegular, CMR_SEYMOUR_NODE** proot,
42 | CMR_MINOR** pminor, CMR_REGULAR_PARAMS* params, CMR_REGULAR_STATS* stats, double timeLimit)
43 | {
44 | assert(cmr);
45 | assert(matrix);
46 |
47 | CMR_REGULAR_PARAMS defaultParams;
48 | if (!params)
49 | {
50 | CMR_CALL( CMRregularParamsInit(&defaultParams) );
51 | params = &defaultParams;
52 | }
53 |
54 | CMR_SUBMAT* submatrix = NULL;
55 | if (!CMRchrmatIsBinary(cmr, matrix, pminor ? &submatrix : NULL))
56 | {
57 | if (pisRegular)
58 | *pisRegular = false;
59 | if (pminor)
60 | CMR_CALL( CMRminorCreate(cmr, pminor, 0, submatrix, CMR_MINOR_TYPE_ENTRY) );
61 | return CMR_OKAY;
62 | }
63 |
64 | CMR_SEYMOUR_NODE* root = NULL;
65 | CMR_CALL( CMRseymourDecompose(cmr, matrix, false, &root, &(params->seymour), stats ? &(stats->seymour) : NULL,
66 | timeLimit) );
67 | int8_t regularity = CMRseymourRegularity(root);
68 | if (regularity)
69 | *pisRegular = regularity > 0;
70 | if (proot)
71 | *proot = root;
72 | else
73 | CMR_CALL( CMRseymourRelease(cmr, &root) );
74 |
75 | return CMR_OKAY;
76 | }
77 |
78 | CMR_ERROR CMRregularCompleteDecomposition(CMR* cmr, CMR_SEYMOUR_NODE* dec, CMR_REGULAR_PARAMS* params,
79 | CMR_REGULAR_STATS* stats, double timeLimit)
80 | {
81 | assert(cmr);
82 | assert(dec);
83 | assert(timeLimit > 0);
84 |
85 | CMR_REGULAR_PARAMS defaultParams;
86 | if (!params)
87 | {
88 | CMR_CALL( CMRregularParamsInit(&defaultParams) );
89 | params = &defaultParams;
90 | }
91 |
92 | CMR_CALL( CMRregularityCompleteDecomposition(cmr, dec, &(params->seymour), stats ? &(stats->seymour) : NULL,
93 | timeLimit) );
94 |
95 | return CMR_OKAY;
96 | }
97 |
98 | CMR_ERROR CMRregularRefineDecomposition(CMR* cmr, size_t numNodes, CMR_SEYMOUR_NODE** nodes, CMR_REGULAR_PARAMS* params,
99 | CMR_REGULAR_STATS* stats, double timeLimit)
100 | {
101 | assert(cmr);
102 | assert(timeLimit > 0);
103 |
104 | if (numNodes == 0)
105 | return CMR_OKAY;
106 | assert(nodes);
107 |
108 | CMR_REGULAR_PARAMS defaultParams;
109 | if (!params)
110 | {
111 | CMR_CALL( CMRregularParamsInit(&defaultParams) );
112 | params = &defaultParams;
113 | }
114 |
115 | CMR_CALL( CMRregularityRefineDecomposition(cmr, numNodes, nodes, &(params->seymour), stats ? &(stats->seymour) : NULL,
116 | timeLimit) );
117 |
118 | return CMR_OKAY;
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/src/cmr/regularity_onesum.c:
--------------------------------------------------------------------------------
1 | // #define CMR_DEBUG /** Uncomment to debug this file. */
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "env_internal.h"
9 | #include "seymour_internal.h"
10 | #include "sort.h"
11 | #include "block_decomposition.h"
12 |
13 | int compareOneSumComponents(const void* a, const void* b)
14 | {
15 | return ((CMR_BLOCK*)b)->matrix->numNonzeros -
16 | ((CMR_BLOCK*)a)->matrix->numNonzeros;
17 | }
18 |
19 |
20 | CMR_ERROR CMRregularitySearchOnesum(CMR* cmr, DecompositionTask* task, DecompositionQueue* queue)
21 | {
22 | assert(cmr);
23 | assert(task);
24 | assert(task->node);
25 | assert(task->node->matrix);
26 |
27 | #if defined(CMR_DEBUG)
28 | CMRdbgMsg(6, "Searching for 1-separations for the following matrix:\n");
29 | CMR_CALL( CMRchrmatPrintDense(cmr, task->dec->matrix, stdout, '0', true) );
30 | #endif /* CMR_DEBUG */
31 |
32 | /* Perform 1-sum decomposition. */
33 |
34 | size_t numComponents;
35 | CMR_BLOCK* components = NULL;
36 | CMR_CALL( CMRdecomposeBlocks(cmr, (CMR_MATRIX*) task->node->matrix, sizeof(char), sizeof(char), &numComponents, &components,
37 | NULL, NULL, NULL, NULL) );
38 |
39 | if (numComponents == 1)
40 | {
41 | CMRdbgMsg(6, "Matrix is 2-connected.\n", numComponents);
42 |
43 | CMR_CALL( CMRchrmatFree(cmr, (CMR_CHRMAT**) &components[0].matrix) );
44 | CMR_CALL( CMRchrmatFree(cmr, (CMR_CHRMAT**) &components[0].transpose) );
45 | CMR_CALL( CMRfreeBlockArray(cmr, &components[0].rowsToOriginal) );
46 | CMR_CALL( CMRfreeBlockArray(cmr, &components[0].columnsToOriginal) );
47 |
48 | /* Just mark it as 2-connected and add it back to the list of unprocessed tasks. */
49 | task->node->testedTwoConnected = true;
50 | CMRregularityQueueAdd(queue, task);
51 | }
52 | else if (numComponents >= 2)
53 | {
54 | CMRdbgMsg(6, "The 1-sum consists of %zu components.\n", numComponents);
55 |
56 | /* Space for mapping of rows/columns to rows. */
57 | CMR_ELEMENT* rowsToParent = NULL;
58 | CMR_CALL( CMRallocStackArray(cmr, &rowsToParent, task->node->numRows) );
59 | CMR_ELEMENT* columnsToParent = NULL;
60 | CMR_CALL( CMRallocStackArray(cmr, &columnsToParent, task->node->numColumns) );
61 |
62 | /* We now create the children. */
63 | CMR_CALL( CMRseymourUpdateOnesum(cmr, task->node, numComponents) );
64 | for (size_t comp = 0; comp < numComponents; ++comp)
65 | {
66 | CMR_BLOCK* component = &components[comp];
67 | for (size_t row = 0; row < component->matrix->numRows; ++row)
68 | rowsToParent[row] = CMRrowToElement(component->rowsToOriginal[row]);
69 | for (size_t column = 0; column < component->matrix->numColumns; ++column)
70 | columnsToParent[column] = CMRcolumnToElement(component->columnsToOriginal[column]);
71 | CMR_CALL( CMRseymourCreateChildFromMatrices(cmr, task->node, comp, (CMR_CHRMAT*) component->matrix,
72 | (CMR_CHRMAT*) component->transpose, rowsToParent, columnsToParent) );
73 |
74 | CMR_CALL( CMRfreeBlockArray(cmr, &component->rowsToOriginal) );
75 | CMR_CALL( CMRfreeBlockArray(cmr, &component->columnsToOriginal) );
76 | }
77 | task->node->type = CMR_SEYMOUR_NODE_TYPE_ONESUM;
78 |
79 | CMR_CALL( CMRfreeStackArray(cmr, &columnsToParent) );
80 | CMR_CALL( CMRfreeStackArray(cmr, &rowsToParent) );
81 |
82 | for (size_t c = numComponents; c > 0; --c)
83 | {
84 | size_t child = c - 1;
85 | task->node->children[child]->testedTwoConnected = true;
86 | DecompositionTask* childTask = NULL;
87 | CMR_CALL( CMRregularityTaskCreateRoot(cmr, task->node->children[child], &childTask, task->params, task->stats,
88 | task->startClock, task->timeLimit) );
89 | CMRregularityQueueAdd(queue, childTask);
90 | }
91 |
92 | CMR_CALL( CMRregularityTaskFree(cmr, &task) );
93 | }
94 |
95 | CMR_CALL( CMRfreeBlockArray(cmr, &components) );
96 |
97 | return CMR_OKAY;
98 | }
99 |
--------------------------------------------------------------------------------
/src/cmr/regularity_r10.c:
--------------------------------------------------------------------------------
1 | // #define CMR_DEBUG /* Uncomment to debug this file. */
2 |
3 | #include "env_internal.h"
4 | #include "seymour_internal.h"
5 |
6 | #include
7 |
8 | CMR_ERROR CMRregularityTestR10(CMR* cmr, DecompositionTask* task, DecompositionQueue* queue)
9 | {
10 | assert(task);
11 | assert(queue);
12 |
13 | CMR_SEYMOUR_NODE* dec = task->node;
14 | assert(dec);
15 |
16 | #if defined(CMR_DEBUG)
17 | CMRdbgMsg(2, "Testing for representation of R10.\n");
18 | CMR_CALL( CMRchrmatPrintDense(cmr, dec->matrix, stdout, '0', true) );
19 | #endif /* CMR_DEBUG */
20 |
21 |
22 | dec->testedR10 = true;
23 | if (dec->numRows != 5 || dec->numColumns != 5)
24 | goto cleanup;
25 |
26 | size_t count3 = 0;
27 | size_t count5 = 0;
28 | for (size_t row = 0; row < 5; ++row)
29 | {
30 | size_t numNonzeros = dec->matrix->rowSlice[row + 1] - dec->matrix->rowSlice[row];
31 | if (numNonzeros == 3)
32 | ++count3;
33 | else if (numNonzeros == 5)
34 | ++count5;
35 | else
36 | goto cleanup;
37 | }
38 | if ((count3 != 4 || count5 != 1) && count3 != 5)
39 | goto cleanup;
40 |
41 | count3 = 0;
42 | count5 = 0;
43 | size_t columnCount[5] = {0, 0, 0, 0, 0};
44 | for (size_t e = 0; e < dec->matrix->numNonzeros; ++e)
45 | columnCount[dec->matrix->entryColumns[e]]++;
46 | for (size_t column = 0; column < 5; ++column)
47 | {
48 | if (columnCount[column] == 3)
49 | ++count3;
50 | else if (columnCount[column] == 5)
51 | ++count5;
52 | else
53 | goto cleanup;
54 | }
55 | if ((count3 != 4 || count5 != 1) && count3 != 5)
56 | goto cleanup;
57 |
58 | /* The number of nonzeros in the rows/columns are 2, 2, 2, 2 and 5. Every 3-connected 5-by-5 matrix with this property
59 | * represents R10.
60 | */
61 |
62 | if (dec->isTernary)
63 | {
64 | bool isCamion;
65 | CMR_SUBMAT* violatorSubmatrix = NULL;
66 | CMR_CALL( CMRcamionTestSigns(cmr, dec->matrix, &isCamion, &violatorSubmatrix,
67 | task->stats ? &task->stats->network.camion : NULL, DBL_MAX) );
68 |
69 | if (violatorSubmatrix)
70 | {
71 | assert(!isCamion);
72 |
73 | /* TODO: Do we actually need the child node or just the irregularity information? */
74 | CMR_CALL( CMRseymourUpdateViolator(cmr, dec, violatorSubmatrix) );
75 |
76 | /* Task is done. */
77 | CMR_CALL( CMRregularityTaskFree(cmr, &task) );
78 | queue->foundIrregularity = true;
79 |
80 | return CMR_OKAY;
81 | }
82 | else
83 | {
84 | assert(isCamion);
85 | }
86 | }
87 |
88 | dec->type = CMR_SEYMOUR_NODE_TYPE_R10;
89 | queue->foundNongraphicness = true;
90 | queue->foundNoncographicness = true;
91 |
92 | cleanup:
93 |
94 | if (dec->type == CMR_SEYMOUR_NODE_TYPE_R10)
95 | {
96 | CMR_CALL( CMRregularityTaskFree(cmr, &task) );
97 | }
98 | else
99 | {
100 | CMRregularityQueueAdd(queue, task);
101 | }
102 |
103 | return CMR_OKAY;
104 | }
105 |
--------------------------------------------------------------------------------
/src/cmr/sign.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discopt/cmr/acfda4fe72cb73eb68a7ed20ebfcf4fdb3027542/src/cmr/sign.c
--------------------------------------------------------------------------------
/src/cmr/sort.c:
--------------------------------------------------------------------------------
1 | // #define CMR_DEBUG /* Uncomment to debug the sorting. */
2 |
3 | #include "sort.h"
4 |
5 | #include
6 | #include
7 |
8 | #define MOVE_ELEMENT(source, target, size) \
9 | do \
10 | { \
11 | size_t __size = (size); \
12 | char* __s = (source); \
13 | char* __t = (target); \
14 | do \
15 | { \
16 | *__t++ = *__s++; \
17 | } \
18 | while (--__size > 0); \
19 | } \
20 | while (false)
21 |
22 | CMR_ERROR CMRsort(CMR* cmr, size_t length, void* array, size_t elementSize, int (*compare)(const void*, const void*))
23 | {
24 | CMR_UNUSED(cmr);
25 |
26 | assert(cmr);
27 |
28 | qsort(array, length, elementSize, compare);
29 |
30 | return CMR_OKAY;
31 | }
32 |
33 | CMR_ERROR CMRsort2(CMR* cmr, size_t length, void* array1, size_t elementSize1, void* array2, size_t elementSize2,
34 | int (*compare)(const void**, const void**))
35 | {
36 | assert(cmr);
37 |
38 | char* data1 = array1;
39 | char* data2 = array2;
40 |
41 | CMRassertStackConsistency(cmr);
42 |
43 | /* Allocate space for temporary elements of both arrays. */
44 | char* temp1 = NULL;
45 | CMR_CALL( CMRallocStackArray(cmr, &temp1, elementSize1) );
46 | char* temp2 = NULL;
47 | CMR_CALL( CMRallocStackArray(cmr, &temp2, elementSize2) );
48 |
49 | /* Create an array with pointers into array1. */
50 | char** pointerArray = NULL;
51 | CMR_CALL( CMRallocStackArray(cmr, &pointerArray, length) );
52 | char* pointer = data1;
53 | for (size_t i = 0; i < length; ++i)
54 | {
55 | pointerArray[i] = pointer;
56 | pointer += elementSize1;
57 | }
58 |
59 | qsort(pointerArray, length, sizeof(size_t*), (int (*)(const void*, const void*)) compare);
60 |
61 | /* Reorder data1 and data2 according to the array of pointers. */
62 | for (size_t i = 0; i < length; ++i)
63 | {
64 | CMRdbgMsg(0, "i = %d, pointerArray[i] = %p array1 = %p, difference = %ld, scaled = %d\n", i, pointerArray[i], data1,
65 | pointerArray[i] - data1, (pointerArray[i] - data1) / elementSize1);
66 | if (i != (pointerArray[i] - data1) / elementSize1)
67 | {
68 | MOVE_ELEMENT(data1 + elementSize1 * i, temp1, elementSize1); /* temp1 = array1[i] */
69 | MOVE_ELEMENT(data2 + elementSize2 * i, temp2, elementSize2); /* temp2 = array2[i] */
70 | size_t j;
71 | size_t k = i;
72 | while (i != (j = (pointerArray[k] - data1) / elementSize1))
73 | {
74 | MOVE_ELEMENT(data1 + elementSize1 * j, data1 + elementSize1 * k, elementSize1); /* data1[k] = data1[j] */
75 | MOVE_ELEMENT(data2 + elementSize2 * j, data2 + elementSize2 * k, elementSize2); /* data2[k] = data2[j] */
76 | pointerArray[k] = data1 + elementSize1 * k;
77 | k = j;
78 | }
79 | MOVE_ELEMENT(temp1, data1 + elementSize1 * k, elementSize1); /* data1[k] = temp1 */
80 | MOVE_ELEMENT(temp2, data2 + elementSize2 * k, elementSize2); /* data2[k] = temp2 */
81 | pointerArray[k] = data1 + elementSize1 * k;
82 | }
83 | }
84 |
85 | /* Free the temporary space. */
86 | CMR_CALL( CMRfreeStackArray(cmr, &pointerArray) );
87 | CMR_CALL( CMRfreeStackArray(cmr, &temp2) );
88 | CMR_CALL( CMRfreeStackArray(cmr, &temp1) );
89 | CMRassertStackConsistency(cmr);
90 |
91 | return CMR_OKAY;
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/src/cmr/sort.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_SORT_INTERNAL_H
2 | #define CMR_SORT_INTERNAL_H
3 |
4 | #include "env_internal.h"
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | /**
11 | * \brief Sorts an array.
12 | *
13 | * The user must provide a \p compare function that is called several times with pointers into the first array.
14 | * The arguments must be dereferenced once in order to access the actual element.
15 | */
16 |
17 | CMR_ERROR CMRsort(
18 | CMR* cmr, /**< \ref CMR environment. */
19 | size_t length, /**< Number of elements in both arrays. */
20 | void *array, /**< Pointer to the first element of the array. */
21 | size_t elementSize, /**< Size (in bytes) of each element of the array. */
22 | int (*compare)(const void*, const void*) /**< Comparison function for comparing two elements. */
23 | );
24 |
25 | /**
26 | * \brief Sorts two arrays simultaneously.
27 | *
28 | * Sorts two arrays using the qsort function from the C library. The user must provide a \p compare function that is
29 | * called several times with pointers to pointers into the first array. Hence, the arguments must be dereferenced twice
30 | * in order to access the actual element.
31 | */
32 |
33 | CMR_ERROR CMRsort2(
34 | CMR* cmr, /**< \ref CMR environment. */
35 | size_t length, /**< Number of elements in both arrays. */
36 | void *array1, /**< Pointer to the first element of the first array. */
37 | size_t elementSize1, /**< Size (in bytes) of each element of the first array. */
38 | void* array2, /**< Pointer to the first element of the second array. */
39 | size_t elementSize2, /**< Size (in bytes) of each element of the second array. */
40 | int (*compare)(const void**, const void**) /**< Comparison function for comparing two elements. */
41 | );
42 |
43 | #ifdef __cplusplus
44 | }
45 | #endif
46 |
47 | #endif /* CMR_SORT_INTERNAL_H */
48 |
--------------------------------------------------------------------------------
/src/gen/gurobi_extract.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 |
13 | typedef enum
14 | {
15 | FILEFORMAT_UNDEFINED = 0, /**< Whether the file format of output was defined by the user. */
16 | FILEFORMAT_MATRIX_DENSE = 1, /**< Dense matrix format. */
17 | FILEFORMAT_MATRIX_SPARSE = 2, /**< Sparse matrix format. */
18 | } FileFormat;
19 |
20 | #define GRB_CALL(x) \
21 | do \
22 | { \
23 | int _grb_error = x; \
24 | if (_grb_error) \
25 | { \
26 | fprintf(stderr, "[Gurobi error <%d>: %s]", _grb_error, GRBgeterrormsg(env)); \
27 | } \
28 | } while(0)
29 |
30 | static
31 | CMR_ERROR extractMatrixGurobi(
32 | char* mipFileName, /**< File name of MIP. */
33 | FileFormat outputFormat /**< Output file format. */
34 | )
35 | {
36 | GRBenv* env = NULL;
37 | GRBemptyenv(&env);
38 | GRB_CALL( GRBsetintparam(env, "outputflag", 0) );
39 | GRBstartenv(env);
40 |
41 | GRBmodel* model = NULL;
42 | GRB_CALL( GRBreadmodel(env, mipFileName, &model) );
43 |
44 | int numRows, numColumns, numNonzeros;
45 | GRB_CALL( GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &numRows) );
46 | GRB_CALL( GRBgetintattr(model, GRB_INT_ATTR_NUMVARS, &numColumns) );
47 | GRB_CALL( GRBgetintattr(model, GRB_INT_ATTR_NUMNZS, &numNonzeros) );
48 |
49 | CMR* cmr = NULL;
50 | CMR_CALL( CMRcreateEnvironment(&cmr) );
51 |
52 | CMR_DBLMAT* matrix = NULL;
53 | CMR_CALL( CMRdblmatCreate(cmr, &matrix, numRows, numColumns, numNonzeros) );
54 | size_t entry = 0;
55 |
56 | int* begin = NULL;
57 | int* indices = NULL;
58 | double* values = NULL;
59 | CMR_CALL( CMRallocBlockArray(cmr, &begin, numRows+1) );
60 | CMR_CALL( CMRallocBlockArray(cmr, &indices, numNonzeros) );
61 | CMR_CALL( CMRallocBlockArray(cmr, &values, numNonzeros) );
62 |
63 | GRB_CALL( GRBgetconstrs(model, &numNonzeros, begin, indices, values, 0, numRows) );
64 | for (size_t row = 0; row < numRows; ++row)
65 | {
66 | matrix->rowSlice[row] = entry;
67 | size_t beyond = (row+1 < numRows) ? begin[row+1] : numNonzeros;
68 | for (size_t i = begin[row]; i < beyond; ++i)
69 | {
70 | matrix->entryColumns[entry] = indices[i];
71 | matrix->entryValues[entry] = values[i];
72 | ++entry;
73 | }
74 | }
75 | matrix->rowSlice[numRows] = entry;
76 | assert(entry == numNonzeros);
77 |
78 | if (outputFormat == FILEFORMAT_MATRIX_SPARSE)
79 | CMR_CALL( CMRdblmatPrintSparse(cmr, matrix, stdout) );
80 | else if (outputFormat == FILEFORMAT_MATRIX_DENSE)
81 | CMR_CALL( CMRdblmatPrintDense(cmr, matrix, stdout, '0', false) );
82 |
83 | CMR_CALL( CMRfreeBlockArray(cmr, &values) );
84 | CMR_CALL( CMRfreeBlockArray(cmr, &indices) );
85 | CMR_CALL( CMRfreeBlockArray(cmr, &begin) );
86 | CMR_CALL( CMRdblmatFree(cmr, &matrix) );
87 | CMR_CALL( CMRfreeEnvironment(&cmr) );
88 |
89 | GRBfreemodel(model);
90 |
91 | GRBfreeenv(env);
92 |
93 | return CMR_OKAY;
94 | }
95 |
96 | /**
97 | * \brief Prints the usage of the \p program to stdout.
98 | *
99 | * \returns \c EXIT_FAILURE.
100 | */
101 |
102 | int printUsage(const char* program)
103 | {
104 | fputs("Usage:\n", stderr);
105 |
106 | fprintf(stderr, "%s MIPFILE [OPTION]...\n", program);
107 | fputs(" extracts the coefficient matrix of a mixed-integer program in MIPFILE and writes it to stdout.\n", stderr);
108 | fputs("\n", stderr);
109 |
110 | fputs("Options:\n", stderr);
111 | fputs(" -o FORMAT Format of output matrix; default: dense.\n", stderr);
112 | fputs("\n", stderr);
113 |
114 | fputs("Formats for matrices: dense, sparse\n", stderr);
115 | fputs("MIPFILE must refer to a file that Gurobi can read.\n", stderr);
116 |
117 | return EXIT_FAILURE;
118 | }
119 |
120 | int main(int argc, char** argv)
121 | {
122 | FileFormat outputFormat = FILEFORMAT_MATRIX_DENSE;
123 | char* mipFileName = NULL;
124 | for (int a = 1; a < argc; ++a)
125 | {
126 | if (!strcmp(argv[a], "-h"))
127 | {
128 | printUsage(argv[0]);
129 | return EXIT_SUCCESS;
130 | }
131 | else if (!strcmp(argv[a], "-o") && (a+1 < argc))
132 | {
133 | if (!strcmp(argv[a+1], "dense"))
134 | outputFormat = FILEFORMAT_MATRIX_DENSE;
135 | else if (!strcmp(argv[a+1], "sparse"))
136 | outputFormat = FILEFORMAT_MATRIX_SPARSE;
137 | else
138 | {
139 | printf("Error: unknown output format <%s>.\n\n", argv[a+1]);
140 | return printUsage(argv[0]);
141 | }
142 | ++a;
143 | }
144 | else if (!mipFileName)
145 | {
146 | mipFileName = argv[a];
147 | }
148 | else
149 | {
150 | printf("Error: more than two MIP file names: %s %s\n\n", mipFileName, argv[a]);
151 | return printUsage(argv[0]);
152 | }
153 | }
154 |
155 | if (!mipFileName)
156 | {
157 | puts("Error: no MIP file name specified.\n");
158 | return printUsage(argv[0]);
159 | }
160 |
161 | CMR_ERROR error = extractMatrixGurobi(mipFileName, outputFormat);
162 | switch (error)
163 | {
164 | case CMR_ERROR_INPUT:
165 | puts("Input error.");
166 | return EXIT_FAILURE;
167 | case CMR_ERROR_MEMORY:
168 | puts("Memory error.");
169 | return EXIT_FAILURE;
170 | default:
171 | return EXIT_SUCCESS;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/gen/wheel_gen.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | typedef enum
13 | {
14 | FILEFORMAT_UNDEFINED = 0, /**< Whether the file format of output was defined by the user. */
15 | FILEFORMAT_MATRIX_DENSE = 1, /**< Dense matrix format. */
16 | FILEFORMAT_MATRIX_SPARSE = 2, /**< Sparse matrix format. */
17 | } FileFormat;
18 |
19 | /**
20 | * \brief Writes the actual wheel matrix to stdout.
21 | */
22 |
23 | CMR_ERROR genMatrixWheel(
24 | size_t numRowsColumns, /**< Number of rows and columns of matrix. */
25 | bool change01, /**< In each column with two 0s in rows 1 and 2, replace them by 1s. */
26 | FileFormat outputFormat /**< Output file format. */
27 | )
28 | {
29 | clock_t startTime = clock();
30 | CMR* cmr = NULL;
31 | CMR_CALL( CMRcreateEnvironment(&cmr) );
32 |
33 | CMR_CHRMAT* matrix = NULL;
34 | CMRchrmatCreate(cmr, &matrix, numRowsColumns, numRowsColumns, 4 * numRowsColumns);
35 |
36 | /* Create the nonzeros. */
37 | matrix->numNonzeros = 0;
38 | for (size_t row = 0; row < numRowsColumns; ++row)
39 | {
40 | matrix->rowSlice[row] = matrix->numNonzeros;
41 | if (row + 1 == numRowsColumns)
42 | {
43 | matrix->entryValues[matrix->numNonzeros] = 1;
44 | matrix->entryColumns[matrix->numNonzeros++] = 0;
45 | }
46 | matrix->entryValues[matrix->numNonzeros] = 1;
47 | matrix->entryColumns[matrix->numNonzeros++] = row;
48 | if (row + 1 < numRowsColumns)
49 | {
50 | matrix->entryValues[matrix->numNonzeros] = 1;
51 | matrix->entryColumns[matrix->numNonzeros++] = row + 1;
52 | }
53 | if (change01 && row < 2)
54 | {
55 | for (size_t c = 3; c < numRowsColumns; ++c)
56 | {
57 | matrix->entryValues[matrix->numNonzeros] = 1;
58 | matrix->entryColumns[matrix->numNonzeros++] = c;
59 | }
60 | }
61 | }
62 | matrix->rowSlice[numRowsColumns] = matrix->numNonzeros;
63 |
64 | double generationTime = (clock() - startTime) * 1.0 / CLOCKS_PER_SEC;
65 | fprintf(stderr, "Generated a %zux%zu matrix with %zu nonzeros in %f seconds.\n", numRowsColumns, numRowsColumns,
66 | matrix->numNonzeros, generationTime);
67 |
68 | /* Print matrix. */
69 | if (outputFormat == FILEFORMAT_MATRIX_DENSE)
70 | CMR_CALL( CMRchrmatPrintDense(cmr, matrix, stdout, '0', false) );
71 | else if (outputFormat == FILEFORMAT_MATRIX_SPARSE)
72 | CMR_CALL( CMRchrmatPrintSparse(cmr, matrix, stdout) );
73 |
74 | /* Cleanup. */
75 | CMR_CALL( CMRchrmatFree(cmr, &matrix) );
76 |
77 | CMR_CALL( CMRfreeEnvironment(&cmr) );
78 |
79 | return CMR_OKAY;
80 | }
81 |
82 | /**
83 | * \brief Prints the usage of the \p program to stdout.
84 | *
85 | * \returns \c EXIT_FAILURE.
86 | */
87 |
88 | int printUsage(const char* program)
89 | {
90 | fputs("Usage:\n", stderr);
91 | fprintf(stderr, "%s ORDER [OPTION]...\n", program);
92 | fputs(" creates an ORDER-by-ORDER wheel matrix and writes it to stdout.\n", stderr);
93 | fputs("\n", stderr);
94 |
95 | fputs("Options:\n", stderr);
96 | fputs(" -01 In each column with two 0s in rows 1 and 2, replace them by 1s; default: off.\n", stderr);
97 | fputs(" -o FORMAT Format of output matrix; default: dense.\n", stderr);
98 | fputs("\n", stderr);
99 |
100 | fputs("Formats for matrices: dense, sparse\n", stderr);
101 |
102 | return EXIT_FAILURE;
103 | }
104 |
105 | int main(int argc, char** argv)
106 | {
107 | struct timeval curTime;
108 | gettimeofday(&curTime, NULL);
109 | srand(curTime.tv_usec);
110 |
111 | FileFormat outputFormat = FILEFORMAT_UNDEFINED;
112 | size_t numRowsColumns = SIZE_MAX;
113 | bool change01 = false;
114 | for (int a = 1; a < argc; ++a)
115 | {
116 | if (!strcmp(argv[a], "-h"))
117 | {
118 | printUsage(argv[0]);
119 | return EXIT_SUCCESS;
120 | }
121 | else if (!strcmp(argv[a], "-01"))
122 | change01 = true;
123 | else if (!strcmp(argv[a], "-o") && (a+1 < argc))
124 | {
125 | if (!strcmp(argv[a+1], "dense"))
126 | outputFormat = FILEFORMAT_MATRIX_DENSE;
127 | else if (!strcmp(argv[a+1], "sparse"))
128 | outputFormat = FILEFORMAT_MATRIX_SPARSE;
129 | else
130 | {
131 | fprintf(stderr, "Error: unknown output format <%s>.\n\n", argv[a+1]);
132 | return printUsage(argv[0]);
133 | }
134 | ++a;
135 | }
136 | else if (numRowsColumns == SIZE_MAX)
137 | {
138 | char* p = NULL;
139 | numRowsColumns = strtoull(argv[a], &p, 10);
140 | if (*p != '\0')
141 | {
142 | fprintf(stderr, "Error: invalid number of rows/columns <%s>.\n\n", argv[a]);
143 | printUsage(argv[0]);
144 | return EXIT_FAILURE;
145 | }
146 | }
147 | else
148 | {
149 | fprintf(stderr, "Error: more than one size indicator specified: %zu %s\n\n", numRowsColumns, argv[a]);
150 | return printUsage(argv[0]);
151 | }
152 | }
153 |
154 | if (numRowsColumns == SIZE_MAX)
155 | {
156 | fputs("Error: no size indicator specified.\n", stderr);
157 | return printUsage(argv[0]);
158 | }
159 | else if (numRowsColumns <= 0)
160 | {
161 | fputs("Error: matrix must have at least 1 row/column.\n", stderr);
162 | return printUsage(argv[0]);
163 | }
164 | if (outputFormat == FILEFORMAT_UNDEFINED)
165 | outputFormat = FILEFORMAT_MATRIX_DENSE;
166 |
167 | CMR_ERROR error = genMatrixWheel(numRowsColumns, change01, outputFormat);
168 | switch (error)
169 | {
170 | case CMR_ERROR_INPUT:
171 | fputs("Input error.\n", stderr);
172 | return EXIT_FAILURE;
173 | case CMR_ERROR_MEMORY:
174 | fputs("Memory error.\n", stderr);
175 | return EXIT_FAILURE;
176 | default:
177 | return EXIT_SUCCESS;
178 | }
179 | }
180 |
181 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | find_package(GTest)
2 | if(NOT GTEST_FOUND)
3 | find_package(GTestSources)
4 | if(NOT GTESTSOURCES_FOUND)
5 | find_package(GTestGit)
6 | endif()
7 | endif()
8 |
9 | # Target for the googletest.
10 | add_executable(cmr_gtest
11 | common.c
12 | test_balanced.cpp
13 | test_camion.cpp
14 | test_ctu.cpp
15 | test_equimodular.cpp
16 | test_graph.cpp
17 | test_graphic.cpp
18 | test_hashtable.cpp
19 | test_matrix.cpp
20 | test_matroid.cpp
21 | test_main.cpp
22 | test_network.cpp
23 | test_regular.cpp
24 | test_separation.cpp
25 | test_series_parallel.cpp
26 | test_tu.cpp)
27 |
28 | # Set standard to C++ 14.
29 | set_property(TARGET cmr_gtest PROPERTY CXX_STANDARD 14)
30 |
31 | # Add tests for non-exported functions only for static library.
32 | if(NOT SHARED)
33 | target_sources(cmr_gtest
34 | PRIVATE
35 | test_block_decomposition.cpp
36 | )
37 | target_include_directories(cmr_gtest
38 | PRIVATE
39 | $ # contains private headers.
40 | )
41 |
42 | endif()
43 |
44 | # Configure cmr_gtest target.
45 | target_compile_features(cmr_gtest PRIVATE cxx_auto_type)
46 | target_link_libraries(cmr_gtest gtest_main gtest CMR::cmr)
47 |
48 | include(GoogleTest)
49 | gtest_discover_tests(cmr_gtest)
50 |
--------------------------------------------------------------------------------
/test/common.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | CMR_ERROR stringToDoubleMatrix(CMR* cmr, CMR_DBLMAT** pmatrix, const char* string)
9 | {
10 | assert(cmr);
11 | char* end;
12 | int numRows, numColumns;
13 |
14 | /* Read size of matrix. */
15 | numRows = strtol(string, &end, 10);
16 | assert(end > string);
17 | string = end;
18 | numColumns = strtol(string, &end, 10);
19 | assert(end > string);
20 | string = end;
21 |
22 | CMRdblmatCreate(cmr, pmatrix, numRows, numColumns, numRows * numColumns);
23 |
24 | (*pmatrix)->numNonzeros = 0;
25 | for (size_t row = 0; row < (*pmatrix)->numRows; ++row)
26 | {
27 | (*pmatrix)->rowSlice[row] = (*pmatrix)->numNonzeros;
28 | for (size_t column = 0; column < (*pmatrix)->numColumns; ++column)
29 | {
30 | double x = strtod(string, &end);
31 | assert(end > string);
32 | string = end;
33 |
34 | if (x != 0.0)
35 | {
36 | (*pmatrix)->entryColumns[(*pmatrix)->numNonzeros] = column;
37 | (*pmatrix)->entryValues[(*pmatrix)->numNonzeros] = x;
38 | (*pmatrix)->numNonzeros++;
39 | }
40 | }
41 | }
42 | (*pmatrix)->rowSlice[numRows] = (*pmatrix)->numNonzeros;
43 |
44 | return CMR_OKAY;
45 | }
46 |
47 | CMR_ERROR stringToIntMatrix(CMR* cmr, CMR_INTMAT** pmatrix, const char* string)
48 | {
49 | assert(cmr);
50 | char* end;
51 | int numRows, numColumns;
52 |
53 | /* Read size of matrix. */
54 | numRows = strtol(string, &end, 10);
55 | assert(end > string);
56 | string = end;
57 | numColumns = strtol(string, &end, 10);
58 | assert(end > string);
59 | string = end;
60 |
61 | CMRintmatCreate(cmr, pmatrix, numRows, numColumns, numRows * numColumns);
62 |
63 | (*pmatrix)->numNonzeros = 0;
64 | for (size_t row = 0; row < (*pmatrix)->numRows; ++row)
65 | {
66 | (*pmatrix)->rowSlice[row] = (*pmatrix)->numNonzeros;
67 | for (size_t column = 0; column < (*pmatrix)->numColumns; ++column)
68 | {
69 | int x = strtol(string, &end, 10);
70 | assert(end > string);
71 | string = end;
72 |
73 | if (x != 0)
74 | {
75 | (*pmatrix)->entryColumns[(*pmatrix)->numNonzeros] = column;
76 | (*pmatrix)->entryValues[(*pmatrix)->numNonzeros] = x;
77 | (*pmatrix)->numNonzeros++;
78 | }
79 | }
80 | }
81 | (*pmatrix)->rowSlice[numRows] = (*pmatrix)->numNonzeros;
82 |
83 | return CMR_OKAY;
84 | }
85 |
86 | CMR_ERROR stringToCharMatrix(CMR* cmr, CMR_CHRMAT** pmatrix, const char* string)
87 | {
88 | assert(cmr);
89 | char* end;
90 | size_t numRows, numColumns;
91 |
92 | /* Read size of matrix. */
93 | numRows = strtol(string, &end, 10);
94 | assert(end > string);
95 | string = end;
96 | numColumns = strtol(string, &end, 10);
97 | assert(end > string);
98 | string = end;
99 |
100 | CMR_CALL( CMRchrmatCreate(cmr, pmatrix, numRows, numColumns, numRows * numColumns) );
101 |
102 | (*pmatrix)->numNonzeros = 0;
103 | for (size_t row = 0; row < (*pmatrix)->numRows; ++row)
104 | {
105 | (*pmatrix)->rowSlice[row] = (*pmatrix)->numNonzeros;
106 | for (size_t column = 0; column < (*pmatrix)->numColumns; ++column)
107 | {
108 | int x = strtol(string, &end, 10);
109 | if (end == string)
110 | return CMR_ERROR_INPUT;
111 | string = end;
112 |
113 | if (x != 0)
114 | {
115 | (*pmatrix)->entryColumns[(*pmatrix)->numNonzeros] = column;
116 | (*pmatrix)->entryValues[(*pmatrix)->numNonzeros] = x;
117 | (*pmatrix)->numNonzeros++;
118 | }
119 | }
120 | }
121 | (*pmatrix)->rowSlice[numRows] = (*pmatrix)->numNonzeros;
122 |
123 | return CMR_OKAY;
124 | }
125 |
--------------------------------------------------------------------------------
/test/common.h:
--------------------------------------------------------------------------------
1 | #ifndef CMR_TEST_COMMON_H
2 | #define CMR_TEST_COMMON_H
3 |
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | CMR_ERROR stringToDoubleMatrix(CMR* cmr, CMR_DBLMAT** matrix, const char* string);
12 |
13 | CMR_ERROR stringToIntMatrix(CMR* cmr, CMR_INTMAT** matrix, const char* string);
14 |
15 | CMR_ERROR stringToCharMatrix(CMR* cmr, CMR_CHRMAT** matrix, const char* string);
16 |
17 | #define ASSERT_CMR_CALL(x) \
18 | do \
19 | { \
20 | CMR_ERROR _error = (x); \
21 | ASSERT_EQ(_error, CMR_OKAY); \
22 | } \
23 | while (false)
24 |
25 | #ifdef __cplusplus
26 | }
27 | #endif
28 |
29 | #endif /* CMR_TEST_COMMON_H */
30 |
--------------------------------------------------------------------------------
/test/test_balanced.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 |
5 | #include
6 |
7 | TEST(Balanced, Submatrix)
8 | {
9 | CMR* cmr = NULL;
10 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
11 |
12 | {
13 | CMR_CHRMAT* matrix = NULL;
14 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "4 4 "
15 | " 1 0 0 1 "
16 | " 1 1 0 0 "
17 | " 0 1 1 0 "
18 | " 0 0 1 1 "
19 | ) );
20 |
21 | bool isBalanced;
22 | CMR_BALANCED_PARAMS params;
23 | ASSERT_CMR_CALL( CMRbalancedParamsInit(¶ms) );
24 | params.algorithm = CMR_BALANCED_ALGORITHM_SUBMATRIX;
25 | ASSERT_CMR_CALL( CMRbalancedTest(cmr, matrix, &isBalanced, NULL, ¶ms, NULL, DBL_MAX) );
26 |
27 | ASSERT_TRUE( isBalanced );
28 |
29 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
30 | }
31 |
32 | {
33 | CMR_CHRMAT* matrix = NULL;
34 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "4 4 "
35 | " 1 0 0 1 "
36 | " 1 1 0 0 "
37 | " 0 1 1 0 "
38 | " 0 0 1 -1 "
39 | ) );
40 |
41 | bool isBalanced;
42 | CMR_BALANCED_PARAMS params;
43 | ASSERT_CMR_CALL( CMRbalancedParamsInit(¶ms) );
44 | params.algorithm = CMR_BALANCED_ALGORITHM_SUBMATRIX;
45 | ASSERT_CMR_CALL( CMRbalancedTest(cmr, matrix, &isBalanced, NULL, ¶ms, NULL, DBL_MAX) );
46 |
47 | ASSERT_FALSE( isBalanced );
48 |
49 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
50 | }
51 |
52 | {
53 | CMR_CHRMAT* matrix = NULL;
54 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "5 5 "
55 | " 1 0 0 0 1 "
56 | " 1 1 0 0 0 "
57 | " 0 1 1 0 0 "
58 | " 0 0 1 1 0 "
59 | " 0 0 0 1 1 "
60 | ) );
61 |
62 | bool isBalanced;
63 | CMR_BALANCED_PARAMS params;
64 | ASSERT_CMR_CALL( CMRbalancedParamsInit(¶ms) );
65 | params.algorithm = CMR_BALANCED_ALGORITHM_SUBMATRIX;
66 | ASSERT_CMR_CALL( CMRbalancedTest(cmr, matrix, &isBalanced, NULL, ¶ms, NULL, DBL_MAX) );
67 |
68 | ASSERT_FALSE( isBalanced );
69 |
70 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
71 | }
72 |
73 | {
74 | CMR_CHRMAT* matrix = NULL;
75 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "5 5 "
76 | " 1 0 0 0 0 1 "
77 | " 1 1 0 0 0 0 "
78 | " 0 1 1 0 0 0 "
79 | " 0 0 1 1 0 0 "
80 | " 0 0 0 1 1 0 "
81 | " 0 0 0 0 1 1 "
82 | ) );
83 |
84 | bool isBalanced;
85 | CMR_BALANCED_PARAMS params;
86 | ASSERT_CMR_CALL( CMRbalancedParamsInit(¶ms) );
87 | params.algorithm = CMR_BALANCED_ALGORITHM_SUBMATRIX;
88 | ASSERT_CMR_CALL( CMRbalancedTest(cmr, matrix, &isBalanced, NULL, ¶ms, NULL, DBL_MAX) );
89 |
90 | ASSERT_TRUE( isBalanced );
91 |
92 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
93 | }
94 |
95 | {
96 | CMR_CHRMAT* matrix = NULL;
97 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "5 4 "
98 | " 1 1 0 0 "
99 | " 1 1 1 0 "
100 | " 1 0 0 -1 "
101 | " 0 1 1 1 "
102 | " 0 0 1 0 "
103 | ) );
104 |
105 | bool isBalanced;
106 | CMR_BALANCED_PARAMS params;
107 | ASSERT_CMR_CALL( CMRbalancedParamsInit(¶ms) );
108 | params.algorithm = CMR_BALANCED_ALGORITHM_SUBMATRIX;
109 | ASSERT_CMR_CALL( CMRbalancedTest(cmr, matrix, &isBalanced, NULL, ¶ms, NULL, DBL_MAX) );
110 |
111 | ASSERT_TRUE( isBalanced );
112 |
113 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
114 | }
115 |
116 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/test/test_camion.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 | #include
5 |
6 | TEST(Camion, Change)
7 | {
8 | CMR* cmr = NULL;
9 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
10 |
11 | CMR_CHRMAT* matrix = NULL;
12 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "10 10 "
13 | "+1 -1 0 0 0 0 0 0 0 0 "
14 | "-1 +1 0 0 0 0 0 0 0 0 "
15 | "0 0 +1 0 0 0 0 -1 0 0 "
16 | "0 0 0 0 -1 0 +1 0 0 0 "
17 | "0 0 0 0 0 0 -1 -1 -1 0 "
18 | "0 0 0 -1 0 +1 0 0 0 0 "
19 | "0 0 0 0 +1 -1 0 0 0 0 "
20 | "0 0 -1 +1 0 0 0 0 0 0 "
21 | "0 0 0 0 0 0 0 0 +1 -1 "
22 | "0 0 0 0 0 0 0 -1 0 +1 "
23 | ) );
24 | CMR_CHRMAT* check = NULL;
25 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &check, "10 10 "
26 | "+1 -1 0 0 0 0 0 0 0 0 "
27 | "-1 +1 0 0 0 0 0 0 0 0 "
28 | "0 0 +1 0 0 0 0 -1 0 0 "
29 | "0 0 0 0 -1 0 +1 0 0 0 "
30 | "0 0 0 0 0 0 -1 -1 -1 0 "
31 | "0 0 0 -1 0 +1 0 0 0 0 "
32 | "0 0 0 0 +1 -1 0 0 0 0 "
33 | "0 0 -1 -1 0 0 0 0 0 0 "
34 | "0 0 0 0 0 0 0 0 -1 -1 "
35 | "0 0 0 0 0 0 0 -1 0 +1 "
36 | ) );
37 | CMR_CHRMAT* checkViolator = NULL;
38 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &checkViolator, "3 3 "
39 | "-1 -1 0 "
40 | "0 1 -1 "
41 | "-1 0 1 "
42 | ) );
43 |
44 | CMR_SUBMAT* submatrix = NULL;
45 | CMR_CHRMAT* violator = NULL;
46 |
47 | bool alreadySigned;
48 | ASSERT_CMR_CALL( CMRcamionTestSigns(cmr, matrix, &alreadySigned, &submatrix, NULL, DBL_MAX) );
49 | ASSERT_FALSE(alreadySigned);
50 | ASSERT_TRUE(submatrix != NULL);
51 | ASSERT_CMR_CALL( CMRchrmatSlice(cmr, matrix, submatrix, &violator) );
52 | ASSERT_TRUE(CMRchrmatCheckEqual(violator, checkViolator));
53 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &violator) );
54 | ASSERT_CMR_CALL( CMRsubmatFree(cmr, &submatrix) );
55 |
56 | ASSERT_CMR_CALL( CMRcamionComputeSigns(cmr, matrix, &alreadySigned, NULL, NULL, DBL_MAX) );
57 | ASSERT_FALSE(alreadySigned);
58 | ASSERT_TRUE(CMRchrmatCheckEqual(matrix, check));
59 |
60 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &checkViolator) );
61 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &check) );
62 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
63 |
64 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
65 | }
66 |
67 |
68 | TEST(Camion, Issue10)
69 | {
70 | CMR* cmr = NULL;
71 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
72 |
73 | CMR_CHRMAT* matrix = NULL;
74 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "4 4 "
75 | "1 1 0 0 "
76 | "1 0 1 1 "
77 | "0 1 1 0 "
78 | "0 0 1 1 "
79 | ) );
80 | CMR_CHRMAT* check = NULL;
81 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &check, "4 4 "
82 | "1 1 0 0 "
83 | "1 0 -1 1 "
84 | "0 1 1 0 "
85 | "0 0 1 -1 "
86 | ) );
87 |
88 |
89 | bool alreadySigned;
90 | ASSERT_CMR_CALL( CMRcamionComputeSigns(cmr, matrix, &alreadySigned, NULL, NULL, DBL_MAX) );
91 | ASSERT_FALSE(alreadySigned);
92 | ASSERT_TRUE(CMRchrmatCheckEqual(matrix, check));
93 |
94 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &check) );
95 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
96 |
97 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
98 | }
99 |
--------------------------------------------------------------------------------
/test/test_ctu.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 | #include
5 |
6 | TEST(CTU, ExamplesSeymour)
7 | {
8 | CMR* cmr = NULL;
9 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
10 | CMR_CHRMAT* matrix = NULL;
11 |
12 | {
13 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, " 4 5 "
14 | "1 0 0 1 1 "
15 | "1 1 0 0 1 "
16 | "0 1 1 0 1 "
17 | "0 0 1 1 1 "
18 | ) );
19 |
20 | bool isCTU;
21 | CMR_CTU_PARAMS params;
22 | ASSERT_CMR_CALL( CMRctuParamsInit(¶ms) );
23 | params.tu.seymour.decomposeStrategy = CMR_SEYMOUR_DECOMPOSE_FLAG_SEYMOUR;
24 |
25 | ASSERT_CMR_CALL( CMRctuTest(cmr, matrix, &isCTU, NULL, NULL, ¶ms, NULL, DBL_MAX) );
26 |
27 | ASSERT_TRUE(isCTU);
28 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
29 | }
30 |
31 | {
32 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, " 5 5 "
33 | "0 1 0 1 0 "
34 | "1 1 1 0 1 "
35 | "0 1 0 0 1 "
36 | "1 0 0 0 1 "
37 | "0 1 1 1 1 "
38 | ) );
39 |
40 | bool isCTU;
41 | size_t complementRow;
42 | size_t complementColumn;
43 | CMR_CTU_PARAMS params;
44 | ASSERT_CMR_CALL( CMRctuParamsInit(¶ms) );
45 | params.tu.seymour.decomposeStrategy = CMR_SEYMOUR_DECOMPOSE_FLAG_SEYMOUR;
46 |
47 | ASSERT_CMR_CALL( CMRctuTest(cmr, matrix, &isCTU, &complementRow, &complementColumn, ¶ms, NULL, DBL_MAX) );
48 | ASSERT_FALSE(isCTU);
49 | ASSERT_EQ(complementRow, 0UL);
50 | ASSERT_EQ(complementColumn, 0UL);
51 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
52 | }
53 |
54 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
55 | }
56 |
--------------------------------------------------------------------------------
/test/test_equimodular.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | TEST(Equimodular, Examples)
10 | {
11 | CMR* cmr = NULL;
12 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
13 |
14 | {
15 | CMR_INTMAT* matrix = NULL;
16 | ASSERT_CMR_CALL( stringToIntMatrix(cmr, &matrix, "5 9 "
17 | " -2 -1 1 5 -3 -2 -7 5 6 "
18 | " 1 0 1 7 1 2 -6 8 8 "
19 | " -3 -1 1 4 -4 -3 -7 4 5 "
20 | " 6 2 0 4 8 8 2 6 4 "
21 | " 4 2 -2 -9 6 4 13 -9 -11 "
22 | ) );
23 |
24 |
25 | bool isEquimodular;
26 | int64_t k = 0;
27 | CMR_EQUIMODULAR_STATS stats;
28 | CMRequimodularStatsInit(&stats);
29 | ASSERT_CMR_CALL( CMRequimodularTest(cmr, matrix, &isEquimodular, &k, NULL, &stats, DBL_MAX) );
30 |
31 | ASSERT_TRUE(isEquimodular);
32 | ASSERT_EQ(k, 1);
33 | ASSERT_EQ(stats.totalCount, 1UL);
34 |
35 | ASSERT_CMR_CALL( CMRintmatFree(cmr, &matrix) );
36 | }
37 |
38 | {
39 | CMR_INTMAT* matrix = NULL;
40 | ASSERT_CMR_CALL( stringToIntMatrix(cmr, &matrix, "5 9 "
41 | " -2 -1 1 5 -3 -2 -7 5 6 "
42 | " 1 0 1 7 1 2 -6 8 8 "
43 | " -3 -1 1 4 -4 -3 -7 4 5 "
44 | " 6 2 0 4 8 8 2 6 4 "
45 | " 4 2 -2 -9 6 4 13 -9 -12 "
46 | ) );
47 |
48 | bool isEquimodular;
49 | int64_t k = 0;
50 | CMR_EQUIMODULAR_STATS stats;
51 | CMRequimodularStatsInit(&stats);
52 | ASSERT_CMR_CALL( CMRequimodularTest(cmr, matrix, &isEquimodular, &k, NULL, &stats, DBL_MAX) );
53 |
54 | ASSERT_FALSE(isEquimodular);
55 | ASSERT_EQ(k, 0);
56 | ASSERT_EQ(stats.totalCount, 1UL);
57 |
58 | ASSERT_CMR_CALL( CMRintmatFree(cmr, &matrix) );
59 | }
60 |
61 | {
62 | CMR_INTMAT* matrix = NULL;
63 | ASSERT_CMR_CALL( stringToIntMatrix(cmr, &matrix, "4 4 "
64 | " 1 1 1 1 "
65 | " 1 1 0 0 "
66 | " 1 0 1 0 "
67 | " 1 0 0 1 "
68 | ) );
69 |
70 |
71 | bool isEquimodular;
72 | int64_t k = 0;
73 | CMR_EQUIMODULAR_STATS stats;
74 | CMRequimodularStatsInit(&stats);
75 | ASSERT_CMR_CALL( CMRequimodularTest(cmr, matrix, &isEquimodular, &k, NULL, &stats, DBL_MAX) );
76 |
77 | ASSERT_TRUE(isEquimodular);
78 | ASSERT_EQ(k, 2);
79 | ASSERT_EQ(stats.totalCount, 1);
80 |
81 | ASSERT_CMR_CALL( CMRintmatFree(cmr, &matrix) );
82 | }
83 |
84 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
85 | }
86 |
87 | #if defined(CMR_WITH_GMP)
88 |
89 | TEST(Equimodular, GMP)
90 | {
91 | CMR* cmr = NULL;
92 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
93 |
94 | {
95 | CMR_INTMAT* matrix = NULL;
96 | ASSERT_CMR_CALL( stringToIntMatrix(cmr, &matrix, "9 9 "
97 | " 1 2 7 3 5 0 2 0 7 "
98 | " 0 0 8 1 0 7 0 4 8 "
99 | " 0 7 6 0 9 0 7 0 9 "
100 | " 2 0 9 0 2 5 8 0 1 "
101 | " 0 1 8 5 3 5 1 6 3 "
102 | " 0 9 0 4 8 1 5 2 0 "
103 | " 7 8 0 2 0 0 9 7 0 "
104 | " 4 0 7 0 0 7 5 0 2 "
105 | " 0 0 0 8 0 5 5 0 6 "
106 | ) );
107 |
108 | bool isEquimodular;
109 | int64_t k = 0;
110 | CMR_EQUIMODULAR_STATS stats;
111 | CMRequimodularStatsInit(&stats);
112 | CMR_ERROR error = CMRequimodularTest(cmr, matrix, &isEquimodular, &k, NULL, &stats, DBL_MAX);
113 |
114 | ASSERT_EQ(error, CMR_OKAY);
115 | ASSERT_FALSE(isEquimodular);
116 | ASSERT_EQ(k, 0);
117 | ASSERT_EQ(stats.totalCount, 1);
118 |
119 | ASSERT_CMR_CALL( CMRintmatFree(cmr, &matrix) );
120 | }
121 |
122 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
123 | }
124 |
125 | #else /* CMR_WITH_GMP */
126 |
127 | TEST(Equimodular, Overflow)
128 | {
129 | CMR* cmr = NULL;
130 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
131 |
132 | {
133 | CMR_INTMAT* matrix = NULL;
134 | ASSERT_CMR_CALL( stringToIntMatrix(cmr, &matrix, "9 9 "
135 | " 1 2 7 3 5 0 2 0 7 "
136 | " 0 0 8 1 0 7 0 4 8 "
137 | " 0 7 6 0 9 0 7 0 9 "
138 | " 2 0 9 0 2 5 8 0 1 "
139 | " 0 1 8 5 3 5 1 6 3 "
140 | " 0 9 0 4 8 1 5 2 0 "
141 | " 7 8 0 2 0 0 9 7 0 "
142 | " 4 0 7 0 0 7 5 0 2 "
143 | " 0 0 0 8 0 5 5 0 6 "
144 | ) );
145 |
146 | bool isEquimodular;
147 | int64_t k = 0;
148 | CMR_EQUIMODULAR_STATS stats;
149 | CMRequimodularStatsInit(&stats);
150 | CMR_ERROR error = CMRequimodularTest(cmr, matrix, &isEquimodular, &k, NULL, &stats, DBL_MAX);
151 |
152 | ASSERT_EQ(error, CMR_ERROR_OVERFLOW);
153 | ASSERT_EQ(k, 0);
154 |
155 | ASSERT_CMR_CALL( CMRintmatFree(cmr, &matrix) );
156 | }
157 |
158 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
159 | }
160 |
161 | #endif /* CMR_WITH_GMP */
162 |
163 |
--------------------------------------------------------------------------------
/test/test_graph.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 | #include
5 |
6 | TEST(Graph, Modifications)
7 | {
8 | CMR* cmr = NULL;
9 | CMRcreateEnvironment(&cmr);
10 |
11 | CMR_GRAPH* graph = NULL;
12 | CMRgraphCreateEmpty(cmr, &graph, 1, 1);
13 |
14 | CMR_GRAPH_NODE a,b,c,d;
15 | CMRgraphAddNode(cmr, graph, &a);
16 | CMRgraphAddNode(cmr, graph, &b);
17 | CMRgraphAddNode(cmr, graph, &c);
18 | CMRgraphAddNode(cmr, graph, &d);
19 |
20 | CMR_GRAPH_EDGE ab, ac, ad, bc, bd, cd;
21 | CMRgraphAddEdge(cmr, graph, a, b, &ab);
22 | CMRgraphAddEdge(cmr, graph, a, c, &ac);
23 | CMRgraphAddEdge(cmr, graph, a, d, &ad);
24 | CMRgraphAddEdge(cmr, graph, b, c, &bc);
25 | CMRgraphAddEdge(cmr, graph, b, d, &bd);
26 | CMRgraphAddEdge(cmr, graph, c, d, &cd);
27 |
28 | ASSERT_EQ(CMRgraphNumNodes(graph), 4UL);
29 | ASSERT_EQ(CMRgraphNumEdges(graph), 6UL);
30 |
31 | size_t countNodes = 0;
32 | for (CMR_GRAPH_NODE v = CMRgraphNodesFirst(graph); CMRgraphNodesValid(graph, v);
33 | v = CMRgraphNodesNext(graph, v))
34 | {
35 | ++countNodes;
36 | }
37 | ASSERT_EQ(countNodes, CMRgraphNumNodes(graph));
38 |
39 | int countIncidentEdges = 0;
40 | for (CMR_GRAPH_ITER i = CMRgraphIncFirst(graph, b);
41 | CMRgraphIncValid(graph, i); i = CMRgraphIncNext(graph, i))
42 | {
43 | CMR_GRAPH_EDGE e = CMRgraphIncEdge(graph, i);
44 | ASSERT_GE(e, 0);
45 | ASSERT_LT(e, (int) graph->memEdges);
46 | ++countIncidentEdges;
47 | }
48 | ASSERT_EQ(countIncidentEdges, 3);
49 |
50 | CMRgraphDeleteEdge(cmr, graph, bc);
51 |
52 | CMRgraphDeleteNode(cmr, graph, a);
53 |
54 | ASSERT_EQ(CMRgraphNumNodes(graph), 3UL);
55 | ASSERT_EQ(CMRgraphNumEdges(graph), 2UL);
56 |
57 | CMRgraphFree(cmr, &graph);
58 |
59 | CMRfreeEnvironment(&cmr);
60 | }
61 |
--------------------------------------------------------------------------------
/test/test_hashtable.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "common.h"
4 | #include "../src/cmr/hashtable.h"
5 |
6 | TEST(Hashtable, Functionality)
7 | {
8 | CMR* cmr = NULL;
9 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
10 |
11 | CMR_LINEARHASHTABLE_ARRAY* hashtable = NULL;
12 | ASSERT_CMR_CALL( CMRlinearhashtableArrayCreate(cmr, &hashtable, 16, 16) );
13 |
14 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "q", strlen("q"), (void*) 17) );
15 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "a", strlen("a"), (void*) 1) );
16 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "b", strlen("b"), (void*) 2) );
17 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "r", strlen("r"), (void*) 18) );
18 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "c", strlen("c"), (void*) 3) );
19 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "d", strlen("d"), (void*) 4) );
20 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "e", strlen("e"), (void*) 5) );
21 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "f", strlen("f"), (void*) 6) );
22 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "g", strlen("g"), (void*) 7) );
23 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "h", strlen("h"), (void*) 8) );
24 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "i", strlen("i"), (void*) 9) );
25 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "j", strlen("j"), (void*) 10) );
26 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "k", strlen("k"), (void*) 11) );
27 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "l", strlen("l"), (void*) 12) );
28 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "m", strlen("m"), (void*) 13) );
29 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "n", strlen("n"), (void*) 14) );
30 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "o", strlen("o"), (void*) 15) );
31 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "p", strlen("p"), (void*) 16) );
32 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "s", strlen("s"), (void*) 19) );
33 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "t", strlen("t"), (void*) 20) );
34 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "u", strlen("u"), (void*) 21) );
35 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "v", strlen("v"), (void*) 22) );
36 | ASSERT_CMR_CALL( CMRlinearhashtableArrayInsert(cmr, hashtable, "w", strlen("w"), (void*) 23) );
37 |
38 | ASSERT_CMR_CALL( CMRlinearhashtableArrayFree(cmr, &hashtable) );
39 |
40 | CMRfreeEnvironment(&cmr);
41 | }
42 |
--------------------------------------------------------------------------------
/test/test_main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(int argc, char **argv)
4 | {
5 | ::testing::InitGoogleTest(&argc, argv);
6 | return RUN_ALL_TESTS();
7 | }
8 |
--------------------------------------------------------------------------------
/test/test_network.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include "common.h"
6 |
7 | #include
8 |
9 | void testNetworkMatrix(
10 | CMR* cmr, /**< \ref CMR environment. */
11 | CMR_CHRMAT* matrix, /**< Matrix to be used for testing. */
12 | bool knownNetwork /**< Whether \p matrix is known to be network. */
13 | )
14 | {
15 | bool isNetwork;
16 | CMR_GRAPH* graph = NULL;
17 | CMR_GRAPH_EDGE* basis = NULL;
18 | CMR_GRAPH_EDGE* cobasis = NULL;
19 | bool* edgesReversed = NULL;
20 | CMR_SUBMAT* violatorSubmatrix = NULL;
21 |
22 | ASSERT_CMR_CALL( CMRnetworkTestMatrix(cmr, matrix, &isNetwork, NULL, &graph, &basis, &cobasis, &edgesReversed,
23 | &violatorSubmatrix, NULL, DBL_MAX) );
24 |
25 | ASSERT_EQ( isNetwork, knownNetwork );
26 | if (isNetwork)
27 | {
28 | ASSERT_TRUE( basis );
29 | ASSERT_TRUE( cobasis );
30 |
31 | CMR_CHRMAT* result = NULL;
32 | bool isCorrectBasis;
33 | ASSERT_CMR_CALL( CMRnetworkComputeMatrix(cmr, graph, &result, NULL, edgesReversed, matrix->numRows,
34 | basis, matrix->numColumns, cobasis, &isCorrectBasis) );
35 | ASSERT_TRUE( isCorrectBasis );
36 | ASSERT_TRUE( result );
37 |
38 | if (!CMRchrmatCheckEqual(matrix, result))
39 | {
40 | printf("Input matrix:\n");
41 | ASSERT_CMR_CALL( CMRchrmatPrintDense(cmr, matrix, stdout, '0', true) );
42 |
43 | printf("Graph:\n");
44 | ASSERT_CMR_CALL( CMRgraphPrint(graph, stdout) );
45 |
46 | printf("Representation matrix:\n");
47 | ASSERT_CMR_CALL( CMRchrmatPrintDense(cmr, result, stdout, '0', true) );
48 |
49 | printf("Basis:");
50 | for (size_t r = 0; r < matrix->numRows; ++r)
51 | printf(" %d", basis[r]);
52 | printf("\n");
53 |
54 | printf("Cobasis:");
55 | for (size_t c = 0; c < matrix->numColumns; ++c)
56 | printf(" %d", cobasis[c]);
57 | printf("\n");
58 | }
59 |
60 | ASSERT_TRUE( CMRchrmatCheckEqual(matrix, result) );
61 |
62 | ASSERT_CMR_CALL( CMRgraphFree(cmr, &graph) );
63 | ASSERT_CMR_CALL( CMRfreeBlockArray(cmr, &basis) );
64 | ASSERT_CMR_CALL( CMRfreeBlockArray(cmr, &cobasis) );
65 | ASSERT_CMR_CALL( CMRfreeBlockArray(cmr, &edgesReversed) );
66 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &result) );
67 | ASSERT_EQ( violatorSubmatrix, (CMR_SUBMAT*) NULL );
68 | }
69 | else
70 | {
71 | ASSERT_EQ( basis, (CMR_GRAPH_EDGE*) NULL );
72 | ASSERT_EQ( cobasis, (CMR_GRAPH_EDGE*) NULL );
73 | ASSERT_EQ( edgesReversed, (bool*) NULL );
74 |
75 | ASSERT_CMR_CALL( CMRsubmatPrint(cmr, violatorSubmatrix, matrix->numRows, matrix->numColumns, stdout) );
76 |
77 | ASSERT_CMR_CALL( CMRsubmatFree(cmr, &violatorSubmatrix) );
78 | }
79 | }
80 |
81 | TEST(Network, Basic)
82 | {
83 | CMR* cmr = NULL;
84 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
85 | CMR_CHRMAT* matrix = NULL;
86 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "6 7 "
87 | "-1 0 0 0 1 -1 0 "
88 | " 1 0 0 1 -1 1 0 "
89 | " 0 -1 0 -1 1 -1 0 "
90 | " 0 1 0 0 0 0 1 "
91 | " 0 0 1 -1 1 0 1 "
92 | " 0 0 -1 1 -1 0 0 "
93 | ) );
94 |
95 | testNetworkMatrix(cmr, matrix, true);
96 |
97 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
98 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
99 | }
100 |
101 | TEST(Network, NonCamion)
102 | {
103 | CMR* cmr = NULL;
104 | ASSERT_CMR_CALL( CMRcreateEnvironment(&cmr) );
105 | CMR_CHRMAT* matrix = NULL;
106 | ASSERT_CMR_CALL( stringToCharMatrix(cmr, &matrix, "6 7 "
107 | "-1 0 0 0 1 -1 0 "
108 | " 1 0 0 1 -1 1 0 "
109 | " 0 -1 0 -1 1 -1 0 "
110 | " 0 1 0 0 0 0 -1 "
111 | " 0 0 1 -1 1 0 1 "
112 | " 0 0 -1 1 -1 0 0 "
113 | ) );
114 |
115 | testNetworkMatrix(cmr, matrix, false);
116 |
117 | ASSERT_CMR_CALL( CMRchrmatFree(cmr, &matrix) );
118 | ASSERT_CMR_CALL( CMRfreeEnvironment(&cmr) );
119 | }
120 |
--------------------------------------------------------------------------------