From 4c60a56fa3734557fdee4ebf1cca2a2d7812bc9d Mon Sep 17 00:00:00 2001 From: Mizux Seiha Date: Mon, 12 May 2025 12:57:50 +0200 Subject: [PATCH] backport from main branch --- .github/dependabot.yml | 13 + cmake/README.md | 2 +- cmake/docker/ubuntu/python.Dockerfile | 4 +- cmake/docker/web/Dockerfile | 3 +- cmake/docs/cmake.svg | 1100 +++++++++-------- cmake/docs/deps.svg | 621 ++++++---- cmake/docs/docker.svg | 386 +++--- examples/contrib/permutation_flow_shop.py | 191 +++ examples/dotnet/README.md | 2 +- ortools/graph/README.md | 123 ++ ortools/graph/generic_max_flow_test.cc | 10 +- ortools/graph/graph_generator.h | 119 ++ ortools/graph/graph_generator_test.cc | 129 ++ ortools/graph/graph_test.cc | 2 - ortools/math_opt/elemental/BUILD.bazel | 1 - .../math_opt/elemental/derived_data_test.cc | 3 +- ortools/math_opt/solver_tests/CMakeLists.txt | 4 +- ortools/set_cover/CMakeLists.txt | 3 + 18 files changed, 1792 insertions(+), 924 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 examples/contrib/permutation_flow_shop.py create mode 100644 ortools/graph/graph_generator.h create mode 100644 ortools/graph/graph_generator_test.cc diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..be006de9a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + groups: + github-actions: + patterns: + - "*" # Group all Actions updates into a single larger pull request + schedule: + interval: weekly diff --git a/cmake/README.md b/cmake/README.md index 157e9cbfeb..9d18ecbd56 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -43,7 +43,7 @@ [windows_dotnet_svg]: ./../../../actions/workflows/amd64_windows_cmake_dotnet.yml/badge.svg?branch=main [windows_dotnet_link]: ./../../../actions/workflows/amd64_windows_cmake_dotnet.yml -Dockers \[Alpine, Archlinux, Centos, Debian, Fedora, OpenSuse, Ubuntu\]x +Dockers \[AlmaLinux, Alpine, Archlinux, Debian, Fedora, OpenSuse, RockyLinux, Ubuntu\]x \[C++, Python, Java, .Net\]: [![Status][docker_svg]][docker_link] [docker_svg]: ./../../../actions/workflows/amd64_docker_cmake.yml/badge.svg?branch=main diff --git a/cmake/docker/ubuntu/python.Dockerfile b/cmake/docker/ubuntu/python.Dockerfile index 9130256e3d..18ba08ae1f 100644 --- a/cmake/docker/ubuntu/python.Dockerfile +++ b/cmake/docker/ubuntu/python.Dockerfile @@ -6,11 +6,11 @@ RUN apt-get update -qq \ python3-dev python3-pip \ python3-setuptools python3-wheel \ python3-venv python3-virtualenv \ - python3-numpy python3-pandas python3-typing-extensions \ + python3-numpy python3-pandas \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN python3 -m pip install --break-system-package \ - absl-py mypy mypy-protobuf + absl-py mypy mypy-protobuf typing-extensions FROM env AS devel WORKDIR /home/project diff --git a/cmake/docker/web/Dockerfile b/cmake/docker/web/Dockerfile index 1dcefb864f..98e32e9622 100644 --- a/cmake/docker/web/Dockerfile +++ b/cmake/docker/web/Dockerfile @@ -18,13 +18,14 @@ COPY . . FROM devel AS build RUN emcmake cmake -S. -Bbuild \ -DCMAKE_BUILD_TYPE=Release -DBUILD_DEPS=ON \ + -DBUILD_TESTING=OFF \ -DBUILD_EXAMPLES=OFF \ -DUSE_COINOR=OFF \ -DUSE_GLPK=OFF \ -DUSE_HIGHS=OFF \ -DUSE_PDLP=OFF \ -DUSE_SCIP=OFF -RUN cmake --build build --target all -v +RUN cmake --build build --target all -v -j 4 #RUN cmake --build build --target install -v FROM build AS test diff --git a/cmake/docs/cmake.svg b/cmake/docs/cmake.svg index 147cde2667..b837c5b6b6 100644 --- a/cmake/docs/cmake.svg +++ b/cmake/docs/cmake.svg @@ -1,164 +1,190 @@ - - - + + CMake - + clusterPrerequisite - -Prerequisite + +Prerequisite clusterOR - -OR-Tools (CMake) + +OR-Tools (CMake) clusterDeps - -Dependencies -(-DBUILD_DEPS=ON) + +Dependencies +(-DBUILD_DEPS=ON) clusterZLIB - -madler/zlib.git + cmake patch + +madler/zlib.git + cmake patch -clusterAbsl - -abseil/abseil-cpp.git +clusterBZIP2 + +bzip2/bzip2.git + cmake patch -clusterProtobuf - -protocolbuffers/protobuf.git +clusterAbsl + +abseil/abseil-cpp.git -clusterCoinOR - -Coin-OR Solver -(-DUSE_COINOR=ON) +clusterRe2 + +google/re2.git -clusterCoinUtils - -Mizux/CoinUtils.git +clusterProtobuf + +protocolbuffers/protobuf.git -clusterOsi - -Mizux/Osi.git +clusterCoinOR + +Coin-OR Solver +(-DUSE_COINOR=ON) -clusterClp - -Mizux/Clp.git +clusterCoinUtils + +Mizux/CoinUtils.git -clusterCgl - -Mizux/Cgl.git +clusterOsi + +Mizux/Osi.git -clusterCbc - -Mizux/Cbc.git +clusterClp + +Mizux/Clp.git -clusterGLPKSolver - -GLPK Solver -(-DUSE_GLPK=ON) +clusterCgl + +Mizux/Cgl.git -clusterGLPK - -Mizux/GLPK.git +clusterCbc + +Mizux/Cbc.git -clusterSCIPSolver - -SCIP Solver -(-DUSE_SCIP=ON) +clusterGLPKSolver + +GLPK Solver +(-DUSE_GLPK=ON) -clusterSCIP - -scipopt/scip.git +clusterGLPK + +Mizux/GLPK.git -clusterCXX - -C++ -(-DBUILD_CXX=ON) +clusterHIGHSSolver + +HIGHS Solver +(-DUSE_HIGHS=ON) -clusterCXXTest - -Examples -(-DBUILD_TESTING=ON) +clusterHIGHS + +ERGO-Code/HIGHS.git -clusterPython - -Python -(-DBUILD_PYTHON=ON) +clusterSCIPSolver + +SCIP Solver +(-DUSE_SCIP=ON) -clusterPythonTest - -Examples -(-DBUILD_TESTING=ON) +clusterSoplex + +scipopt/soplex.git -clusterJava - -Java -(-DBUILD_JAVA=ON) +clusterSCIP + +scipopt/scip.git -clusterJavaTest - -Examples -(-DBUILD_TESTING=ON) +clusterCXX + +C++ +(-DBUILD_CXX=ON) -clusterNet - -.Net -(-DBUILD_DOTNET=ON) +clusterCXXTest + +Examples +(-DBUILD_TESTING=ON) +clusterPython + +Python +(-DBUILD_PYTHON=ON) + + +clusterPythonTest + +Examples +(-DBUILD_TESTING=ON) + + +clusterJava + +Java +(-DBUILD_JAVA=ON) + + +clusterJavaTest + +Examples +(-DBUILD_TESTING=ON) + + +clusterNet + +.Net +(-DBUILD_DOTNET=ON) + + clusterNetTest - -Examples -(-DBUILD_TESTING=ON) + +Examples +(-DBUILD_TESTING=ON) CM - - - - -CMake + + + + +CMake SWIG - - - - -Swig -(Unix) + + + + +Swig +(Unix) @@ -167,12 +193,12 @@ PY - - - - -Python -(3.6+) + + + + +Python +(3.6+) @@ -181,12 +207,12 @@ JV - - - - -Java -(openJDK 8+) + + + + +Java +(openJDK 8+) @@ -195,12 +221,12 @@ DN - - - - -.Net Core SDK -(3.1) + + + + +.Net Core SDK +(3.1) @@ -209,11 +235,11 @@ FS - - - - -.Net F# + + + + +.Net F# @@ -222,518 +248,584 @@ ZLIB - -ZLIB::ZLIB + +ZLIB::ZLIB - + Protobuf - -protobuf::libprotobuf + +protobuf::libprotobuf - -ZLIB->Protobuf - - - - - -OR_SRC - -OR-Tools src -ortools/... - - - -ZLIB->OR_SRC - - - - - -Absl - -absl::absl_* - - -Absl->Protobuf - - +ZLIB->Protobuf + + - - -Absl->OR_SRC - - + + +SPX + +libsoplex-pic - + -Protobuf->OR_SRC - - - - - -CoinUtils - -Coin::CoinUtils - - - -Osi - -Coin::Osi - - - -CoinUtils->Osi - - - - - -Clp - -Coin::Clp - - - -CoinUtils->Clp - - - - - -OsiClp - -Coin::OsiClp - - - -CoinUtils->OsiClp - - - - - -Cgl - -Coin::Cgl - - - -CoinUtils->Cgl - - - - - -Cbc - -Coin::Cbc - - - -CoinUtils->Cbc - - - - - -OsiCbc - -Coin::OsiCbc - - - -CoinUtils->OsiCbc - - - - - -Osi->Clp - - - - - -Osi->OsiClp - - - - - -Osi->Cgl - - - - - -Osi->Cbc - - - - - -Osi->OsiCbc - - - - - -Clp->OsiClp - - - - - -ClpSolver - -Coin::ClpSolver - - - -Clp->ClpSolver - - - - - -Clp->Cbc - - - - - -OsiClp->Cgl - - - - - -ClpSolver->OR_SRC - - - - - -Cgl->Cbc - - - - - -Cbc->OsiCbc - - - - - -CbcSolver - -Coin::CbcSolver - - - -Cbc->CbcSolver - - - - - -CbcSolver->OR_SRC - - - - - -GLPK - -glpk::glpk - - - -GLPK->OR_SRC - - +ZLIB->SPX + + - + SCIP - -scip::scip + +SCIP::libscip + + + +ZLIB->SCIP + + + + + +OR_SRC + +OR-Tools src +ortools/... + + + +ZLIB->OR_SRC + + + + + +BZip2 + +BZip2::BZip2 + + + +BZip2->OR_SRC + + + + + +Absl + +absl::absl_* + + + +Re2 + +re2::re2 + + + +Absl->Re2 + + + + + +Absl->Protobuf + + + + + +Absl->OR_SRC + + + + + +Re2->Protobuf + + + + + +Re2->OR_SRC + + + + + +Protobuf->OR_SRC + + + + + +CoinUtils + +Coin::CoinUtils + + + +Osi + +Coin::Osi + + + +CoinUtils->Osi + + + + + +Clp + +Coin::Clp + + + +CoinUtils->Clp + + + + + +OsiClp + +Coin::OsiClp + + + +CoinUtils->OsiClp + + + + + +Cgl + +Coin::Cgl + + + +CoinUtils->Cgl + + + + + +Cbc + +Coin::Cbc + + + +CoinUtils->Cbc + + + + + +OsiCbc + +Coin::OsiCbc + + + +CoinUtils->OsiCbc + + + + + +Osi->Clp + + + + + +Osi->OsiClp + + + + + +Osi->Cgl + + + + + +Osi->Cbc + + + + + +Osi->OsiCbc + + + + + +Clp->OsiClp + + + + + +ClpSolver + +Coin::ClpSolver + + + +Clp->ClpSolver + + + + + +Clp->Cbc + + + + + +OsiClp->Cgl + + + + + +ClpSolver->OR_SRC + + + + + +Cgl->Cbc + + + + + +Cbc->OsiCbc + + + + + +CbcSolver + +Coin::CbcSolver + + + +Cbc->CbcSolver + + + + + +CbcSolver->OR_SRC + + + + + +GLPK + +glpk::glpk + + + +GLPK->OR_SRC + + + + + +HIGHS + +highs::highs + + + +SPX->SCIP + + - + SCIP->OR_SRC - - + + - + SWIG_WIN - -swigwin -(Windows) + +swigwin +(Windows) - + OR_CPP - -ortools::ortools + +ortools::ortools - + OR_SRC->OR_CPP - - + + - + OR_WPY - - - -C++ Python wrappers + + + +C++ Python wrappers - + OR_SRC->OR_WPY - - -swig + + +swig - + OR_PY - - - -Python files + + + +Python files - + OR_SRC->OR_PY - - -swig + + +swig - + OR_WJAVA - - - -C++ Java wrappers + + + +C++ Java wrappers - + OR_SRC->OR_WJAVA - - -swig + + +swig - + OR_JAVA - - - -Java files + + + +Java files - + OR_SRC->OR_JAVA - - -swig + + +swig - + OR_WNET - - - -C++ .Net wrappers + + + +C++ .Net wrappers - + OR_SRC->OR_WNET - - -swig + + +swig - + OR_NET - - - -.Net files + + + +.Net files - + OR_SRC->OR_NET - - -swig + + +swig - + PKG_CPP - - - - -CMake Package + + + + +CMake Package - + OR_CPP->PKG_CPP - - -install + + +install - + EX_CPP - -C++ samples + +C++ samples - + PKG_CPP->EX_CPP - - + + - + OR_WPY->OR_PY - - + + - + PKG_PY - - - - -Wheel package + + + + +Wheel package - + OR_PY->PKG_PY - - -python setup.py + + +python setup.py - + EX_PY - -Python samples + +Python samples - + PKG_PY->EX_PY - - + + - + OR_WJAVA->OR_JAVA - - + + - + PKG_JAVA - - - - -Maven package + + + + +Maven package - + OR_JAVA->PKG_JAVA - - -maven (WIP) + + +maven - + EX_JAVA - -Java samples + +Java samples - + PKG_JAVA->EX_JAVA - - + + - + OR_WNET->OR_NET - - + + - + PKG_NET_RT - - - - -Nuget runtime package -Google.OrTools.runtime.rid.nupkg + + + + +Nuget runtime package +Google.OrTools.runtime.rid.nupkg - + OR_WNET->PKG_NET_RT - - -dotnet package + + +dotnet package - + PKG_NET - - - - -Nuget package -Google.OrTools.nupkg + + + + +Nuget package +Google.OrTools.nupkg - + OR_NET->PKG_NET - - -dotnet package + + +dotnet package - + PKG_NET_RT->PKG_NET - - + + - + EX_NET - -.Net samples + +.Net samples - + PKG_NET->EX_NET - - + + diff --git a/cmake/docs/deps.svg b/cmake/docs/deps.svg index a683b73eb7..812629c5dc 100644 --- a/cmake/docs/deps.svg +++ b/cmake/docs/deps.svg @@ -1,329 +1,528 @@ - - - + + CMakeDeps - + clusterZLIB - -madler/zlib.git + cmake patch + +madler/zlib.git + cmake patch -clusterAbsl - -abseil/abseil-cpp.git +clusterBZip2 + +bzip2/bzip2.git + cmake patch -clusterProtobuf - -protocolbuffers/protobuf.git +clusterAbsl + +abseil/abseil-cpp.git -clusterRe2 - -google/re2.git +clusterProtobuf + +protocolbuffers/protobuf.git -clusterEigen3 - -libeigen/eigen.git +clusterRe2 + +google/re2.git -clusterPybind11 - -pybind/pybind11.git +clusterEigen3 + +libeigen/eigen.git clusterCoinOR - --DUSE_COINOR=ON AND -DBUILD_DEPS=ON + +-DUSE_COINOR=ON AND -DBUILD_DEPS=ON clusterCoinUtils - -Mizux/CoinUtils.git + +Mizux/CoinUtils.git clusterOsi - -Mizux/Osi.git + +Mizux/Osi.git clusterClp - -Mizux/Clp.git + +Mizux/Clp.git clusterCgl - -Mizux/Cgl.git + +Mizux/Cgl.git clusterCbc - -Mizux/Cbc.git + +Mizux/Cbc.git clusterGLPKSolver - --DUSE_GLPK=ON AND -DBUILD_GLPK=ON + +-DUSE_GLPK=ON AND -DBUILD_GLPK=ON clusterGLPK - -Mizux/GLPK.git + +Mizux/GLPK.git -clusterSCIPSolver - --DUSE_SCIP=ON AND -DBUILD_SCIP=ON +clusterHIGHSSolver + +-DUSE_HIGHS=ON AND -DBUILD_HIGHS=ON +clusterHIGHS + +ERGO-Code/HIGHS.git + + +clusterSCIPSolver + +-DUSE_SCIP=ON AND -DBUILD_SCIP=ON + + +clusterSoplex + +scipopt/soplex.git + + clusterSCIP - -scipopt/scip.git + +scipopt/scip.git + + +clusterTesting + +-DBUILD_TESTING=ON + + +clusterGTest + +google/googletest.git + + +clusterBenchmark + +google/benchmark.git + + +clusterFuzzTest + +google/fuzztest.git + + +clusterPython + +-DBUILD_PYTHON=ON + + +clusterPybind11 + +pybind/pybind11.git + + +clusterPybind11Absl + +pybind/pybind11_abseil.git + + +clusterPybind11Protobuf + +pybind/pybind11_protobuf.git ZLIB - -ZLIB::ZLIB + +ZLIB::ZLIB - - -Protobuf - -protobuf::libprotobuf - - - -ZLIB->Protobuf - - - - - -Cbc - -Coin::Cbc - - - -ZLIB->Cbc - - + + +BZip2 + +BZip2::BZip2 - + Absl - -absl::absl_* + +absl::absl_* - - -Absl->Protobuf - - - - + -Protoc - - - -protobuf::protoc +Protobuf + +protobuf::libprotobuf + + + +Protobuf->ZLIB + + + + + +Protobuf->Absl + + - + Re2 - -re2::re2 + +re2::re2 + + + +Protobuf->Re2 + + + + + +Protoc + + + +protobuf::protoc + + + +Re2->Absl + + - -Eigen3 - -Eigen3::eigen - - -Pybind11 - -pybind11::pybind11 +Eigen3 + +Eigen3::eigen CoinUtils - -Coin::CoinUtils + +Coin::CoinUtils Osi - -Coin::Osi + +Coin::Osi - + -CoinUtils->Osi - - +Osi->CoinUtils + + Clp - -Coin::Clp + +Coin::Clp - + -CoinUtils->Clp - - +Clp->CoinUtils + + + + + +Clp->Osi + + OsiClp - -Coin::OsiClp + +Coin::OsiClp - + -CoinUtils->OsiClp - - +OsiClp->CoinUtils + + - - -Cgl - -Coin::Cgl - - - -CoinUtils->Cgl - - - - - -CoinUtils->Cbc - - - - - -OsiCbc - -Coin::OsiCbc - - - -CoinUtils->OsiCbc - - - - - -Osi->Clp - - - - + -Osi->OsiClp - - +OsiClp->Osi + + - - -Osi->Cgl - - - - - -Osi->Cbc - - - - - -Osi->OsiCbc - - - - + -Clp->OsiClp - - +OsiClp->Clp + + ClpSolver - -Coin::ClpSolver + +Coin::ClpSolver - + -Clp->ClpSolver - - +ClpSolver->Clp + + - - -Clp->Cbc - - + + +Cgl + +Coin::Cgl - + + +Cgl->CoinUtils + + + + + +Cgl->Osi + + + + -OsiClp->Cgl - - +Cgl->OsiClp + + - + + +Cbc + +Coin::Cbc + + + +Cbc->ZLIB + + + + + +Cbc->CoinUtils + + + + + +Cbc->Osi + + + + + +Cbc->Clp + + + + -Cgl->Cbc - - +Cbc->Cgl + + - + + +OsiCbc + +Coin::OsiCbc + + + +OsiCbc->CoinUtils + + + + + +OsiCbc->Osi + + + + -Cbc->OsiCbc - - +OsiCbc->Cbc + + CbcSolver - -Coin::CbcSolver + +Coin::CbcSolver - + -Cbc->CbcSolver - - +CbcSolver->Cbc + + GLPK - -glpk::glpk + +glpk::glpk + + + +HIGHS + +highs::highs + + + +SPX + +libsoplex + + + +SPX->ZLIB + + - + SCIP - -scip::scip + +SCIP::libscip + + + +SCIP->ZLIB + + + + + +SCIP->SPX + + + + + +gtest + +GTest::gtest + + + +gtest->Absl + + + + + +gtest->Re2 + + + + + +bench + +benchmark::benchmark + + + +bench->gtest + + + + + +fuzz + +fuzztest::fuzztest + + + +fuzz->Absl + + + + + +fuzz->Protobuf + + + + + +fuzz->Re2 + + + + + +fuzz->gtest + + + + + +Pybind11 + +pybind11::pybind11 + + + +Pybind11Absl + +pybind11::pybind11_abseil + + + +Pybind11Absl->Absl + + + + + +Pybind11Absl->Pybind11 + + + + + +Pybind11Protobuf + +pybind11::pybind11_protobuf + + + +Pybind11Protobuf->Protobuf + + + + + +Pybind11Protobuf->Pybind11 + + diff --git a/cmake/docs/docker.svg b/cmake/docs/docker.svg index 742134b824..bdc54dfc8c 100644 --- a/cmake/docs/docker.svg +++ b/cmake/docs/docker.svg @@ -1,426 +1,426 @@ - - - + + DockerDeps - + clusterDockerfile - -docker/<distro>/Dockerfile + +docker/<distro>/Dockerfile clusterLang - -docker/<distro>/<lang>.Dockerfile + +docker/<distro>/<lang>.Dockerfile clusterCache - -cache/<distro>/ + +cache/<distro>/ DISTRO_IMG - - -<distro>:latest + + +<distro>:latest BASE_IMG - - -ortools/cmake:<distro>_base -base + + +ortools/cmake:<distro>_base +base DISTRO_IMG->BASE_IMG - - + + PKG - - - - -Build packages -e.g. cmake, g++ + + + + +Build packages +e.g. cmake, g++ PKG->BASE_IMG - - -install + + +install PYPKG - - - - -Python packages -e.g. python-dev + + + + +Python packages +e.g. python-dev LANGENV_IMG - - -ortools/cmake:<distro>_<lang>_env -env + + +ortools/cmake:<distro>_<lang>_env +env PYPKG->LANGENV_IMG - - -install + + +install JAVAPKG - - - - -Java packages -e.g. openjdk + + + + +Java packages +e.g. openjdk JAVAPKG->LANGENV_IMG - - -install + + +install DOTNETPKG - - - - -.Net packages -e.g. dotnet-cli + + + + +.Net packages +e.g. dotnet-cli DOTNETPKG->LANGENV_IMG - - -install + + +install SRC - -git repo + +git repo LANGDEVEL_IMG - - -ortools/cmake:<distro>_<lang>_devel -devel + + +ortools/cmake:<distro>_<lang>_devel +devel SRC->LANGDEVEL_IMG - - -copy + + +copy SAMPLE - -sample + +sample LANGINSTALLDEVEL_IMG - - -ortools/cmake:<distro>_<lang>_install_devel -install_devel + + +ortools/cmake:<distro>_<lang>_install_devel +install_devel SAMPLE->LANGINSTALLDEVEL_IMG - - -copy + + +copy SWIG_IMG - - -ortools/cmake:<distro>_swig -swig + + +ortools/cmake:<distro>_swig +swig BASE_IMG->SWIG_IMG - - + + BASE_TAR - - - -docker_base.tar + + + +docker_base.tar BASE_IMG->BASE_TAR - - -make save_<distro>_base + + +make save_<distro>_base SWIG_IMG->LANGENV_IMG - - + + SWIG_TAR - - - -docker_swig.tar + + + +docker_swig.tar SWIG_IMG->SWIG_TAR - - -make save_<distro>_swig + + +make save_<distro>_swig LANGENV_IMG->LANGDEVEL_IMG - - + + LANGINSTALLENV_IMG - - -ortools/cmake:<distro>_<lang>_install_env -install_env + + +ortools/cmake:<distro>_<lang>_install_env +install_env LANGENV_IMG->LANGINSTALLENV_IMG - - + + LANGENV_TAR - - - -docker_<lang>_env.tar + + + +docker_<lang>_env.tar LANGENV_IMG->LANGENV_TAR - - -make save_<distro>_<lang>_env + + +make save_<distro>_<lang>_env LANGBUILD_IMG - - -ortools/cmake:<distro>_<lang>_build -build + + +ortools/cmake:<distro>_<lang>_build +build LANGDEVEL_IMG->LANGBUILD_IMG - - + + LANGDEVEL_TAR - - - -docker_<lang>_devel.tar + + + +docker_<lang>_devel.tar LANGDEVEL_IMG->LANGDEVEL_TAR - - -make save_<distro>_<lang>_devel + + +make save_<distro>_<lang>_devel LANGTEST_IMG - - -ortools/cmake:<distro>_<lang>_test -test + + +ortools/cmake:<distro>_<lang>_test +test LANGBUILD_IMG->LANGTEST_IMG - - + + LANGBUILD_IMG->LANGINSTALLENV_IMG - - -copy install + + +copy install LANGBUILD_TAR - - - -docker_<lang>_build.tar + + + +docker_<lang>_build.tar LANGBUILD_IMG->LANGBUILD_TAR - - -make save_<distro>_<lang>_build + + +make save_<distro>_<lang>_build LANGTEST_TAR - - - -docker_<lang>_test.tar + + + +docker_<lang>_test.tar LANGTEST_IMG->LANGTEST_TAR - - -make save_<distro>_<lang>_test + + +make save_<distro>_<lang>_test LANGINSTALLENV_IMG->LANGINSTALLDEVEL_IMG - - + + LANGINSTALLENV_TAR - - - -docker_<lang>_install_env.tar + + + +docker_<lang>_install_env.tar LANGINSTALLENV_IMG->LANGINSTALLENV_TAR - - -make save_<distro>_<lang>_install_env + + +make save_<distro>_<lang>_install_env LANGINSTALLBUILD_IMG - - -ortools/cmake:<distro>_<lang>_install_build -install_build + + +ortools/cmake:<distro>_<lang>_install_build +install_build LANGINSTALLDEVEL_IMG->LANGINSTALLBUILD_IMG - - + + LANGINSTALLDEVEL_TAR - - - -docker_<lang>_install_devel.tar + + + +docker_<lang>_install_devel.tar LANGINSTALLDEVEL_IMG->LANGINSTALLDEVEL_TAR - - -make save_<distro>_<lang>_install_devel + + +make save_<distro>_<lang>_install_devel LANGINSTALLTEST_IMG - - -ortools/cmake:<distro>_<lang>_install_test -install_test + + +ortools/cmake:<distro>_<lang>_install_test +install_test LANGINSTALLBUILD_IMG->LANGINSTALLTEST_IMG - - + + LANGINSTALLBUILD_TAR - - - -docker_<lang>_install_build.tar + + + +docker_<lang>_install_build.tar LANGINSTALLBUILD_IMG->LANGINSTALLBUILD_TAR - - -make save_<distro>_<lang>_install_build + + +make save_<distro>_<lang>_install_build LANGINSTALLTEST_TAR - - - -docker_<lang>_install_test.tar + + + +docker_<lang>_install_test.tar LANGINSTALLTEST_IMG->LANGINSTALLTEST_TAR - - -make save_<distro>_<lang>_install_test + + +make save_<distro>_<lang>_install_test diff --git a/examples/contrib/permutation_flow_shop.py b/examples/contrib/permutation_flow_shop.py new file mode 100644 index 0000000000..505ce7dbfd --- /dev/null +++ b/examples/contrib/permutation_flow_shop.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +# Copyright 2010-2025 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This model implements the permutation flow shop problem (PFSP). + +In the PFSP, a set of jobs has to be processed on a set of machines. Each job +must be processed on each machine in sequence and all jobs have to be processed +in the same order on every machine. The objective is to minimize the makespan. +""" + +from typing import Sequence +from dataclasses import dataclass +from itertools import product + +import numpy as np + +from absl import app +from absl import flags +from google.protobuf import text_format +from ortools.sat.python import cp_model + +_PARAMS = flags.DEFINE_string( + "params", + "num_search_workers:16", + "Sat solver parameters.", +) + +_TIME_LIMIT = flags.DEFINE_float( + "time_limit", + 60.0, + "Time limit in seconds. Default is 60s.", +) + +_LOG = flags.DEFINE_boolean( + "log", + False, + "Whether to log the solver output.", +) + + +@dataclass +class TaskType: + """ + Small wrapper to hold the start, end, and interval variables of a task. + """ + + start: cp_model.IntVar + end: cp_model.IntVar + interval: cp_model.IntervalVar + + +def permutation_flow_shop( + processing_times: np.ndarray, + time_limit: float, + log: bool, + params: str +): + """ + Solves the given permutation flow shop problem instance with OR-Tools. + + Parameters + ---------- + processing_times + An n-by-m matrix of processing times of the jobs on the machines. + time_limit + The time limit in seconds. If not set, the solver runs until an + optimal solution is found. + log + Whether to log the solver output. Default is False. + + Raises + ------ + ValueError + If the number of lines is greater than 1, i.e., the instance is a + distributed permutation flow shop problem. + """ + m = cp_model.CpModel() + num_jobs, num_machines = processing_times.shape + horizon = processing_times.sum() + + # Create interval variables for all tasks (each job/machine pair). + tasks = {} + for job, machine in product(range(num_jobs), range(num_machines)): + start = m.new_int_var(0, horizon, "") + end = m.new_int_var(0, horizon, "") + duration = processing_times[job][machine] + interval = m.new_interval_var(start, duration, end, "") + tasks[job, machine] = TaskType(start, end, interval) + + # No overlap for all job intervals on this machine. + for machine in range(num_machines): + intervals = [tasks[job, machine].interval for job in range(num_jobs)] + m.add_no_overlap(intervals) + + # Add precedence constraints between tasks of the same job. + for job, machine in product(range(num_jobs), range(num_machines - 1)): + pred = tasks[job, machine] + succ = tasks[job, machine + 1] + m.add(pred.end <= succ.start) + + # Create arcs for circuit constraints. + arcs = [] + for idx1 in range(num_jobs): + arcs.append((0, idx1 + 1, m.new_bool_var("start"))) + arcs.append((idx1 + 1, 0, m.new_bool_var("end"))) + + lits = {} + for idx1, idx2 in product(range(num_jobs), repeat=2): + if idx1 != idx2: + lit = m.new_bool_var(f"{idx1} -> {idx2}") + lits[idx1, idx2] = lit + arcs.append((idx1 + 1, idx2 + 1, lit)) + + m.add_circuit(arcs) + + # Enforce that the permutation of jobs is the same on all machines. + for machine in range(num_machines): + starts = [tasks[job, machine].start for job in range(num_jobs)] + ends = [tasks[job, machine].end for job in range(num_jobs)] + + for idx1, idx2 in product(range(num_jobs), repeat=2): + if idx1 == idx2: + continue + + # Since all machines share the same arc literals, if the literal + # i -> j is True, this enforces that job i is always scheduled + # before job j on all machines. + lit = lits[idx1, idx2] + m.add(ends[idx1] <= starts[idx2]).only_enforce_if(lit) + + # Set minimizing makespan as objective. + obj_var = m.new_int_var(0, horizon, "makespan") + completion_times = [ + tasks[(job, num_machines - 1)].end for job in range(num_jobs) + ] + m.add_max_equality(obj_var, completion_times) + m.minimize(obj_var) + + solver = cp_model.CpSolver() + if params: + text_format.Parse(params, solver.parameters) + solver.parameters.log_search_progress = log + solver.parameters.max_time_in_seconds = time_limit + + status_code = solver.Solve(m) + status = solver.StatusName(status_code) + + print(f"Status: {status}") + print(f"Makespan: {solver.ObjectiveValue()}") + + if status in ["OPTIMAL", "FEASIBLE"]: + start = [solver.Value(tasks[job, 0].start) for job in range(num_jobs)] + solution = np.argsort(start) + 1 + print(f"Solution: {solution}") + + +def main(argv: Sequence[str]) -> None: + """Creates the data and calls the solving procedure.""" + # VRF_10_5_2 instance from http://soa.iti.es/problem-instances. + # Optimal makespan is 698. + processing_times = [ + [79, 67, 10, 48, 52], + [40, 40, 57, 21, 54], + [48, 93, 49, 11, 79], + [16, 23, 19, 2, 38], + [38, 90, 57, 73, 3], + [76, 13, 99, 98, 55], + [73, 85, 40, 20, 85], + [34, 6, 27, 53, 21], + [38, 6, 35, 28, 44], + [32, 11, 11, 34, 27], + ] + + permutation_flow_shop( + np.array(processing_times), _TIME_LIMIT.value, _LOG.value, _PARAMS.value + ) + + +if __name__ == "__main__": + app.run(main) diff --git a/examples/dotnet/README.md b/examples/dotnet/README.md index dda7130553..fde3c18e7a 100644 --- a/examples/dotnet/README.md +++ b/examples/dotnet/README.md @@ -3,7 +3,7 @@ The following examples showcase how to use OrTools.
The project solution has examples for C#. -We recommend that all projects you create target `net6.0`, +We recommend that all projects you create target `net8.0`, as this allows you to compile for various frameworks and keep up-to-date with the latest frameworks. diff --git a/ortools/graph/README.md b/ortools/graph/README.md index 1f11415710..4831200355 100644 --- a/ortools/graph/README.md +++ b/ortools/graph/README.md @@ -76,6 +76,129 @@ Flow algorithms: supplies/demands at nodes, based on the Goldberg-Tarjan push-relabel algorithm. +## Class design + +`BaseGraph` is a generic graph interface on which most algorithms can be built +and provides efficient implementations with a fast construction time. Its design +is based on the experience acquired in various graph algorithm implementations. + +The main ideas are: + +- Graph nodes and arcs are represented by integers. + +- Node or arc annotations (weight, cost, ...) are not part of the graph class, + they can be stored outside in one or more arrays and can be easily retrieved + using a node or arc as an index. + +### Terminology + +An *arc* (or *forward arc*) of a graph is directed and going from a *tail node* +to a *head node*. + +```mermaid +graph TD; +tail -->|arc| head; +``` + +Node and arc indices are of type `NodeIndexType` and `ArcIndexType` +respectively. Those default to `int32_t`, which allows representing most +practical graphs, but applications that have smaller graphs can improve memory +usage and locality by parameterizing the graph type (e.g. `BaseGraph` allows representing graphs with up to 65k nodes and arcs). + +A node or arc index is *valid* if it represents a node or arc of the graph. The +validity ranges are always `[0, num_nodes())` for nodes and `[0, num_arcs())` +for forward arcs. For example, the following graph has 4 nodes numbered 0 +through 3 and 5 forward arcs numbered 0 through 4: + +```mermaid +graph TD; +0-->|0| 1; +2-->|1| 1; +0-->|2| 2; +3-->|3| 3; +1-->|4| 2; +``` + +Some graph implementations also store *reverse arcs* and can be used for +undirected graphs or flow-like algorithms. Reverse arcs are elements of +`[-num_arcs(), 0)` and are also considered valid by the implementations that +store them. In the following diagram, reverse arcs are represented with dashed +lines. A reverse arc is created for each forward arc (the forward and +reverse arc in this pair are called *opposite* of each other). This possibly +results in multiarcs: + +```mermaid +graph TD; +0-->|0| 1; +1-.->|-1| 0; +2-->|1| 1; +1-.->|-2| 2; +0-->|2| 2; +2-.->|-3| 0; +3-->|3| 3; +3-.->|-4| 3; +1-->|4| 2; +2-.->|-5| 1; +``` + +#### Graph traversal + +- The *outgoing arcs* of a node `v` are the forward arcs whose tail is `v`. +- The *incoming arcs* of `v` are the forward arcs whose head is `v`. +- The *opposite incoming* arcs of `v` are the opposite arcs of the incoming + arcs for `v`. + +Forward graph classes allow iteration on outgoing arcs using accessor +`OutgoingArcs()`. Graph classes with both forward and reverse arcs additionally +provide `IncomingArcs` and `OppositeIncomingArcs()`, that return iterators for +the two other categories. They also provide `OutgoingOrOppositeIncomingArcs()`, +which allows iterating both outgoing and opposite incoming arcs at the same +time, which corresponds to iterating forward and reverse arcs *leaving* the +node. + +`v` | `OutgoingArcs(v)` | `IncomingArcs(v)` | `OppositeIncomingArcs(v)` | `OutgoingOrOppositeIncoming(v)` +--- | ----------------- | ----------------- | ------------------------- | ------------------------------- +0 | {0,2} | {} | {} | {0,2} +1 | {4} | {0,1} | {-2,-1} | {-2,-1,4} +2 | {1} | {2,4} | {-5,-3} | {-5,-3,1} +3 | {3} | {3} | {-4} | {-4,3} + +### Graph implementations + +- `ListGraph<>`: Simplest API. Iterating outgoing arcs requires `2 + degree` + memory loads. + +- `StaticGraph<>`: More memory and speed efficient than `ListGraph<>`, but + requires calling `Build()` once after adding all nodes and arcs. Iterating + outgoing arcs requires only `2` memory loads. + +- `ReverseArcListGraph<>` adds reverse arcs to `ListGraph<>`. Iterating + neighboring arcs for a node requires `O(degree)` memory loads. + +- `ReverseArcStaticGraph<>` adds reverse arcs to `StaticGraph<>`. Iterating + neighboring arcs for a node requires `O(1)` memory loads. + +- `CompleteGraph<>`: If you need a fully connected graph. O(1) memory usage + and much faster than explicitly storing nodes and arcs using + `StaticGraph<>`. + +- `CompleteBipartiteGraph<>`: If you need a fully connected bipartite graph. + O(1) memory usage and much faster than explicitly storing nodes and arcs + using `StaticGraph<>`. + +- `FlowGraph<>`: A graph specialized for max-flow/min-cost-flow algorithms. + For max-flow or min-cost-flow we need a directed graph where each arc from + tail to head has a reverse arc from head to tail. In practice many input + graphs already have such reverse arc and it can make a big difference just + to reuse them. This is similar to `ReverseArcStaticGraph` but handles + reverse arcs in a different way. Instead of always creating a *new* reverse + arc for each arc of the input graph, this detects if a reverse arc is + already present in the input, and does not create a new one when this is the + case. In the best case, this can gain a factor 2 in the final graph size, + note however that the graph construction is slightly slower because of this + detection. + ## Wrappers * [`python`](python): the SWIG code that makes the wrapper available in Python diff --git a/ortools/graph/generic_max_flow_test.cc b/ortools/graph/generic_max_flow_test.cc index fd9f307886..5fa975ac78 100644 --- a/ortools/graph/generic_max_flow_test.cc +++ b/ortools/graph/generic_max_flow_test.cc @@ -352,9 +352,9 @@ void AddSourceAndSink(const typename Graph::NodeIndex num_tails, } template -void GenerateCompleteGraph(const typename Graph::NodeIndex num_tails, - const typename Graph::NodeIndex num_heads, - Graph* graph) { +void GenerateCompleteGraphWithSourceAndSink( + const typename Graph::NodeIndex num_tails, + const typename Graph::NodeIndex num_heads, Graph* graph) { const typename Graph::NodeIndex num_nodes = num_tails + num_heads + 2; const typename Graph::ArcIndex num_arcs = num_tails * num_heads + num_tails + num_heads; @@ -470,7 +470,7 @@ void FullAssignment(std::optional unused, typename Graph::NodeIndex num_tails, typename Graph::NodeIndex num_heads) { Graph graph; - GenerateCompleteGraph(num_tails, num_heads, &graph); + GenerateCompleteGraphWithSourceAndSink(num_tails, num_heads, &graph); graph.Build(); std::vector arc_capacity(graph.num_arcs(), 1); std::unique_ptr> max_flow(new GenericMaxFlow( @@ -590,7 +590,7 @@ void FullRandomFlow(std::optional expected_flow, const FlowQuantity kCapacityRange = 10000; const FlowQuantity kCapacityDelta = 1000; Graph graph; - GenerateCompleteGraph(num_tails, num_heads, &graph); + GenerateCompleteGraphWithSourceAndSink(num_tails, num_heads, &graph); std::vector arc_capacity(graph.num_arcs()); GenerateRandomArcValuations(random, graph, kCapacityRange, &arc_capacity); diff --git a/ortools/graph/graph_generator.h b/ortools/graph/graph_generator.h new file mode 100644 index 0000000000..5bff71576f --- /dev/null +++ b/ortools/graph/graph_generator.h @@ -0,0 +1,119 @@ +// Copyright 2010-2025 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef UTIL_GRAPH_GRAPH_GENERATOR_H_ +#define UTIL_GRAPH_GRAPH_GENERATOR_H_ + +// Generates a complete undirected graph with `num_nodes` nodes. +// +// A complete graph is a graph in which all pairs of distinct nodes are +// connected by an edge. +// The graph is represented using the provided `Graph` template. +// If the chosen graph type requires a call to `Build()`, the user is expected +// to perform this call, possibly after tweaking the graph. +// +// Consider using `CompleteGraph` (util/graph/graph.h) instead of this function +// in production code, as it uses constant memory to store the graph. Instead, +// this function explicitly creates the graph using the template type, which is +// mostly useful for tests or when you have to tweak the graph after creation +// (i.e. a complete graph is just the core of your final graph). +// +// Args: +// num_nodes: The number of nodes in the graph. +// +// Returns: +// A complete undirected graph. +template +Graph GenerateCompleteUndirectedGraph( + const typename Graph::NodeIndex num_nodes) { + Graph graph; + graph.Reserve(num_nodes, num_nodes * (num_nodes - 1)); + graph.AddNode(num_nodes - 1); // Only for degenerate cases with no arcs. + for (typename Graph::NodeIndex src = 0; src < num_nodes; ++src) { + for (typename Graph::NodeIndex dst = src + 1; dst < num_nodes; ++dst) { + graph.AddArc(src, dst); + graph.AddArc(dst, src); + } + } + return graph; +} + +// Generates a complete undirected bipartite graph with `num_nodes_1` and +// `num_nodes_2` nodes in each part. +// +// A complete bipartite graph is a graph in which all pairs of distinct nodes, +// one in each part, are connected by an edge. +// The graph is represented using the provided `Graph` template. +// If the chosen graph type requires a call to `Build()`, the user is expected +// to perform this call, possibly after tweaking the graph. +// +// Args: +// num_nodes_1: The number of nodes in the first part of the graph. +// num_nodes_2: The number of nodes in the second part of the graph. +// +// Returns: +// A complete undirected bipartite graph. +template +Graph GenerateCompleteUndirectedBipartiteGraph( + const typename Graph::NodeIndex num_nodes_1, + const typename Graph::NodeIndex num_nodes_2) { + Graph graph; + graph.Reserve(num_nodes_1 + num_nodes_2, 2 * num_nodes_1 * num_nodes_2); + graph.AddNode(num_nodes_1 + num_nodes_2 - 1); // Only for degenerate cases. + for (typename Graph::NodeIndex src = 0; src < num_nodes_1; ++src) { + for (typename Graph::NodeIndex dst = 0; dst < num_nodes_2; ++dst) { + graph.AddArc(src, num_nodes_1 + dst); + graph.AddArc(num_nodes_1 + dst, src); + } + } + return graph; +} + +// Generates a complete directed bipartite graph with `num_nodes_1` and +// `num_nodes_2` nodes in each part. +// +// A complete bipartite graph is a graph in which all pairs of distinct nodes, +// one in each part, are connected by an edge. Edges are directed from the first +// part towards the second part. +// The graph is represented using the provided `Graph` template. +// If the chosen graph type requires a call to `Build()`, the user is expected +// to perform this call, possibly after tweaking the graph. +// +// Consider using `CompleteBipartiteGraph` (util/graph/graph.h) instead of this +// function in production code, as it uses constant memory to store the graph. +// Instead, this function explicitly creates the graph using the template type, +// which is mostly useful for tests or when you have to tweak the graph after +// creation (i.e. a complete graph is just the core of your final graph). +// +// Args: +// num_nodes_1: The number of nodes in the first part of the graph. +// num_nodes_2: The number of nodes in the second part of the graph. +// +// Returns: +// A complete directed bipartite graph. +template +Graph GenerateCompleteDirectedBipartiteGraph( + const typename Graph::NodeIndex num_nodes_1, + const typename Graph::NodeIndex num_nodes_2) { + Graph graph; + graph.Reserve(num_nodes_1 + num_nodes_2, num_nodes_1 * num_nodes_2); + graph.AddNode(num_nodes_1 + num_nodes_2 - 1); // Only for degenerate cases. + for (typename Graph::NodeIndex src = 0; src < num_nodes_1; ++src) { + for (typename Graph::NodeIndex dst = 0; dst < num_nodes_2; ++dst) { + graph.AddArc(src, num_nodes_1 + dst); + } + } + return graph; +} + +#endif // UTIL_GRAPH_GRAPH_GENERATOR_H_ diff --git a/ortools/graph/graph_generator_test.cc b/ortools/graph/graph_generator_test.cc new file mode 100644 index 0000000000..7935e4fed5 --- /dev/null +++ b/ortools/graph/graph_generator_test.cc @@ -0,0 +1,129 @@ +// Copyright 2010-2025 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ortools/graph/graph_generator.h" + +#include + +#include "gtest/gtest.h" +#include "ortools/base/gmock.h" +#include "ortools/graph/graph.h" + +namespace { + +using ::testing::IsEmpty; +using ::testing::UnorderedElementsAre; + +template +std::vector OutgoingNodes(const Graph& graph, + typename Graph::NodeIndex src) { + std::vector nodes; + for (const typename Graph::ArcIndex arc : graph.OutgoingArcs(src)) { + nodes.push_back(graph.Head(arc)); + } + return nodes; +} + +template +class GenerateCompleteUndirectedGraphTest : public testing::Test {}; + +using GenerateCompleteUndirectedGraphTypes = + ::testing::Types, util::StaticGraph>; +TYPED_TEST_SUITE(GenerateCompleteUndirectedGraphTest, + GenerateCompleteUndirectedGraphTypes); + +TYPED_TEST(GenerateCompleteUndirectedGraphTest, SimpleGraph) { + TypeParam graph = GenerateCompleteUndirectedGraph(3); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 3); + EXPECT_EQ(graph.num_arcs(), 6); + EXPECT_THAT(graph.OutDegree(0), 2); + EXPECT_THAT(graph.OutDegree(1), 2); + EXPECT_THAT(graph.OutDegree(2), 2); + EXPECT_THAT(OutgoingNodes(graph, 0), UnorderedElementsAre(1, 2)); + EXPECT_THAT(OutgoingNodes(graph, 1), UnorderedElementsAre(0, 2)); + EXPECT_THAT(OutgoingNodes(graph, 2), UnorderedElementsAre(0, 1)); +} + +TYPED_TEST(GenerateCompleteUndirectedGraphTest, SmallestGraph) { + TypeParam graph = GenerateCompleteUndirectedGraph(1); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 1); + EXPECT_EQ(graph.num_arcs(), 0); + EXPECT_THAT(OutgoingNodes(graph, 0), IsEmpty()); +} + +template +class GenerateCompleteUndirectedBipartiteGraphTest : public testing::Test {}; + +using GenerateCompleteUndirectedBipartiteGraphTypes = + ::testing::Types, util::StaticGraph>; +TYPED_TEST_SUITE(GenerateCompleteUndirectedBipartiteGraphTest, + GenerateCompleteUndirectedBipartiteGraphTypes); + +TYPED_TEST(GenerateCompleteUndirectedBipartiteGraphTest, SimpleGraph) { + TypeParam graph = GenerateCompleteUndirectedBipartiteGraph(2, 3); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 5); + EXPECT_EQ(graph.num_arcs(), 12); + EXPECT_THAT(OutgoingNodes(graph, 0), UnorderedElementsAre(2, 3, 4)); + EXPECT_THAT(OutgoingNodes(graph, 1), UnorderedElementsAre(2, 3, 4)); + EXPECT_THAT(OutgoingNodes(graph, 2), UnorderedElementsAre(0, 1)); + EXPECT_THAT(OutgoingNodes(graph, 3), UnorderedElementsAre(0, 1)); + EXPECT_THAT(OutgoingNodes(graph, 4), UnorderedElementsAre(0, 1)); +} + +template +class GenerateCompleteDirectedBipartiteGraphTest : public testing::Test {}; + +using GenerateCompleteDirectedBipartiteGraphTypes = + ::testing::Types, util::StaticGraph>; +TYPED_TEST_SUITE(GenerateCompleteDirectedBipartiteGraphTest, + GenerateCompleteDirectedBipartiteGraphTypes); + +TYPED_TEST(GenerateCompleteDirectedBipartiteGraphTest, SimpleGraph) { + TypeParam graph = GenerateCompleteDirectedBipartiteGraph(2, 3); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 5); + EXPECT_EQ(graph.num_arcs(), 6); + EXPECT_THAT(OutgoingNodes(graph, 0), UnorderedElementsAre(2, 3, 4)); + EXPECT_THAT(OutgoingNodes(graph, 1), UnorderedElementsAre(2, 3, 4)); + EXPECT_THAT(OutgoingNodes(graph, 2), IsEmpty()); + EXPECT_THAT(OutgoingNodes(graph, 3), IsEmpty()); + EXPECT_THAT(OutgoingNodes(graph, 4), IsEmpty()); +} + +TYPED_TEST(GenerateCompleteDirectedBipartiteGraphTest, SimplSmallestGraphLeft) { + TypeParam graph = GenerateCompleteDirectedBipartiteGraph(1, 0); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 1); + EXPECT_EQ(graph.num_arcs(), 0); + EXPECT_THAT(OutgoingNodes(graph, 0), IsEmpty()); +} + +TYPED_TEST(GenerateCompleteDirectedBipartiteGraphTest, + SimplSmallestGraphRight) { + TypeParam graph = GenerateCompleteDirectedBipartiteGraph(0, 1); + graph.Build(); + + EXPECT_EQ(graph.num_nodes(), 1); + EXPECT_EQ(graph.num_arcs(), 0); + EXPECT_THAT(OutgoingNodes(graph, 0), IsEmpty()); +} + +} // namespace diff --git a/ortools/graph/graph_test.cc b/ortools/graph/graph_test.cc index 66103c8103..29e85240e2 100644 --- a/ortools/graph/graph_test.cc +++ b/ortools/graph/graph_test.cc @@ -715,7 +715,6 @@ TYPED_TEST(GenericGraphInterfaceTest, EmptyGraphAlternateSyntax) { EXPECT_EQ(ArcIndex(0), graph.num_arcs()); } -#if !defined(_MSC_VER) TYPED_TEST(GenericGraphInterfaceTest, GraphWithNodesButNoArc) { using NodeIndex = typename TypeParam::NodeIndex; using ArcIndex = typename TypeParam::ArcIndex; @@ -737,7 +736,6 @@ TYPED_TEST(GenericGraphInterfaceTest, GraphWithNodesButNoArc) { } EXPECT_EQ(0, count); } -#endif // !defined(_MSC_VER) TYPED_TEST(GenericGraphInterfaceTest, BuildWithRandomArc) { using NodeIndex = typename TypeParam::NodeIndex; diff --git a/ortools/math_opt/elemental/BUILD.bazel b/ortools/math_opt/elemental/BUILD.bazel index 4a86322701..1fbe3dbf27 100644 --- a/ortools/math_opt/elemental/BUILD.bazel +++ b/ortools/math_opt/elemental/BUILD.bazel @@ -129,7 +129,6 @@ cc_test( ":symmetry", "//ortools/base:gmock_main", "//ortools/math_opt/testing:stream", - "@abseil-cpp//absl/strings", ], ) diff --git a/ortools/math_opt/elemental/derived_data_test.cc b/ortools/math_opt/elemental/derived_data_test.cc index 2aa30b94bc..5135308303 100644 --- a/ortools/math_opt/elemental/derived_data_test.cc +++ b/ortools/math_opt/elemental/derived_data_test.cc @@ -165,7 +165,8 @@ TEST(FormatAttrValueTest, FormatsInt64) { } TEST(FormatAttrValueTest, FormatsDouble) { - EXPECT_EQ(FormatAttrValue(absl::SixDigits(4.2)), "4.2"); + // need a double with an exact binary representation + EXPECT_EQ(FormatAttrValue(4.5), "4.5"); } } // namespace diff --git a/ortools/math_opt/solver_tests/CMakeLists.txt b/ortools/math_opt/solver_tests/CMakeLists.txt index e8e5020182..5bc081ca76 100644 --- a/ortools/math_opt/solver_tests/CMakeLists.txt +++ b/ortools/math_opt/solver_tests/CMakeLists.txt @@ -324,6 +324,7 @@ ortools_cxx_library( TESTING ) +if(USE_SCIP AND USE_GLOP) ortools_cxx_test( NAME ${_PREFIX}_test_models_test @@ -334,9 +335,8 @@ ortools_cxx_test( GTest::gmock_main ortools::math_opt_test_models ortools::math_opt_matchers - #ortools::math_opt_glop_solver - #ortools::math_opt_gscipt_solver ) +endif() ortools_cxx_library( NAME diff --git a/ortools/set_cover/CMakeLists.txt b/ortools/set_cover/CMakeLists.txt index 74879b33c5..3f83ed41e9 100644 --- a/ortools/set_cover/CMakeLists.txt +++ b/ortools/set_cover/CMakeLists.txt @@ -33,6 +33,9 @@ target_link_libraries(${NAME} PRIVATE if(BUILD_TESTING) file(GLOB _TEST_SRCS "*_test.cc") + if(NOT USE_SCIP) + list(FILTER _TEST_SRCS EXCLUDE REGEX ".*/set_cover_test.cc") + endif() foreach(_FULL_FILE_NAME IN LISTS _TEST_SRCS) get_filename_component(_NAME ${_FULL_FILE_NAME} NAME_WE) get_filename_component(_FILE_NAME ${_FULL_FILE_NAME} NAME)