From 1c3b79acab3de7bc7ab010624d88e901c38da370 Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 16:59:46 +0100 Subject: [PATCH 1/8] Add new IIS data structure --- include/scippp/iis.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 include/scippp/iis.hpp diff --git a/include/scippp/iis.hpp b/include/scippp/iis.hpp new file mode 100644 index 00000000..e489c320 --- /dev/null +++ b/include/scippp/iis.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +namespace scippp { + +/** + * A data structure to hold an %IIS (%Irreducible %Infeasible %Subsystem). + * @since 1.4.0 + */ +struct IIS { + //! Ids of the constraints in the %IIS. + std::vector consIds; +}; + +} From 3514e244f98385ede282e1ce3b54f6e67f5e3f85 Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 17:00:16 +0100 Subject: [PATCH 2/8] Implement Model::generateIIS --- include/scippp/model.hpp | 9 +++++++++ source/model.cpp | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/scippp/model.hpp b/include/scippp/model.hpp index cac360ea..7f81156b 100644 --- a/include/scippp/model.hpp +++ b/include/scippp/model.hpp @@ -11,6 +11,7 @@ #include #include "scippp/constant_coefficient.hpp" +#include "scippp/iis.hpp" #include "scippp/initial_solution.hpp" #include "scippp/lin_expr.hpp" #include "scippp/lin_ineq.hpp" @@ -347,5 +348,13 @@ class Model { bool checkBounds = true, bool checkIntegrality = true, bool checkLpRows = true); + + /** + * Creates an %Irreducible %Infeasible %Subsystem (%IIS) of the current model. + * + * @since 1.4.0 + * @return The generated %IIS. + */ + IIS generateIIS() const; }; } diff --git a/source/model.cpp b/source/model.cpp index 84117cbd..96ff6aef 100644 --- a/source/model.cpp +++ b/source/model.cpp @@ -175,4 +175,24 @@ bool Model::addSolution( return isStored; } +IIS Model::generateIIS() const +{ + m_scipCallWrapper(SCIPgenerateIIS(m_scip)); + auto* iis { SCIPgetIIS(m_scip) }; + assert(iis); // GCOVR_EXCL_LINE + auto* subscip { SCIPiisGetSubscip(iis) }; + assert(subscip); // GCOVR_EXCL_LINE + auto nConss { SCIPgetNOrigConss(subscip) }; + auto** conss { SCIPgetOrigConss(subscip) }; + + IIS result; + result.consIds.reserve(nConss); + for (size_t i { 0 }; i < nConss; ++i) { + SCIP_CONS* cons = conss[i]; + assert(cons); // GCOVR_EXCL_LINE + result.consIds.emplace_back(SCIPconsGetName(cons)); + } + return result; +} + } From 6c1f2ab4aa17bb2b5dbcc9e7aafc89c0417360e5 Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 17:00:43 +0100 Subject: [PATCH 3/8] Add test cases --- test/test_iis.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 test/test_iis.cpp diff --git a/test/test_iis.cpp b/test/test_iis.cpp new file mode 100644 index 00000000..286656ac --- /dev/null +++ b/test/test_iis.cpp @@ -0,0 +1,52 @@ +#include + +#include "scippp/model.hpp" +#include "scippp/parameters.hpp" + +#include + +using namespace scippp; +using namespace std; + +BOOST_AUTO_TEST_SUITE(IIS) + +BOOST_AUTO_TEST_CASE(CanBeCreated) +{ + Model model("Simple"); + const auto& [x1, x2] = model.addVars<2>("x_"); + model.addConstr(x1 + x2 >= 2, "lower"); + model.addConstr(x1 + x2 <= 1, "upper"); + model.addConstr(x1 + x2 >= 0, "useless"); + model.setObjsense(Sense::MINIMIZE); + + model.setParam(params::IIS::SILENT, true); // to avoid output during testing + model.solve(); + BOOST_REQUIRE(model.getStatus() == SCIP_STATUS_INFEASIBLE); + auto iis { model.generateIIS() }; + BOOST_TEST(model.getLastReturnCode() == SCIP_OKAY); + + const auto& icons { iis.consIds }; + BOOST_TEST(icons.size() == 2); + BOOST_TEST((std::find(icons.begin(), icons.end(), "lower") != iis.consIds.end())); + BOOST_TEST((std::find(icons.begin(), icons.end(), "upper") != iis.consIds.end())); + BOOST_TEST((std::find(icons.begin(), icons.end(), "useless") == iis.consIds.end())); +} + +BOOST_AUTO_TEST_CASE(WorksOnEmptyProblem) +{ + Model model("Simple"); + model.solve(); + auto iis { model.generateIIS() }; + BOOST_TEST(model.getLastReturnCode() == SCIP_OKAY); + BOOST_TEST(iis.consIds.size() == 0); +} + +BOOST_AUTO_TEST_CASE(WorksWithoutSolving) +{ + Model model("Simple"); + auto iis { model.generateIIS() }; + BOOST_TEST(model.getLastReturnCode() == SCIP_OKAY); + BOOST_TEST(iis.consIds.size() == 0); +} + +BOOST_AUTO_TEST_SUITE_END() From 16fdfe63cc01bd69a6e1d98422f30be0fdf83abe Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 17:14:56 +0100 Subject: [PATCH 4/8] Also check if conss is not null --- source/model.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/source/model.cpp b/source/model.cpp index 96ff6aef..130f311c 100644 --- a/source/model.cpp +++ b/source/model.cpp @@ -183,14 +183,17 @@ IIS Model::generateIIS() const auto* subscip { SCIPiisGetSubscip(iis) }; assert(subscip); // GCOVR_EXCL_LINE auto nConss { SCIPgetNOrigConss(subscip) }; - auto** conss { SCIPgetOrigConss(subscip) }; IIS result; - result.consIds.reserve(nConss); - for (size_t i { 0 }; i < nConss; ++i) { - SCIP_CONS* cons = conss[i]; - assert(cons); // GCOVR_EXCL_LINE - result.consIds.emplace_back(SCIPconsGetName(cons)); + if (nConss > 0) { + auto** conss { SCIPgetOrigConss(subscip) }; + assert(conss); // GCOVR_EXCL_LINE + result.consIds.reserve(nConss); + for (size_t i { 0 }; i < nConss; ++i) { + SCIP_CONS* cons = conss[i]; + assert(cons); // GCOVR_EXCL_LINE + result.consIds.emplace_back(SCIPconsGetName(cons)); + } } return result; } From 4658312faecca62bcc6556593eeb65f56c9aeeca Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 17:19:58 +0100 Subject: [PATCH 5/8] Make generateIIS nodiscard --- include/scippp/model.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/scippp/model.hpp b/include/scippp/model.hpp index 7f81156b..2d4e6af5 100644 --- a/include/scippp/model.hpp +++ b/include/scippp/model.hpp @@ -355,6 +355,6 @@ class Model { * @since 1.4.0 * @return The generated %IIS. */ - IIS generateIIS() const; + [[nodiscard]] IIS generateIIS() const; }; } From 8df68239f86e828daf3a77539b1dd759be02903c Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Mon, 8 Dec 2025 17:30:52 +0100 Subject: [PATCH 6/8] Update changelog --- changelog.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/changelog.md b/changelog.md index 3c84d97e..edf49a50 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - [Doc:Unreleased] +### Added + +- [PR41](https://github.com/scipopt/SCIPpp/pull/41) Basic support of IIS extraction via `Model::generateIIS`. + This requires that the plugin `IISfinderGreedy` is loaded (which is done by default) or any other plugin that can + find IIS'. Example usage: + ```cpp + Model model = ...; + auto iis { model.generateIIS() }; + std::cout << "Contradicting are:\n"; + for (const auto& consId : iis.consIds) { + std::cout << " " << consId << "\n"; + } + ``` + ### Changed - [PR38](https://github.com/scipopt/SCIPpp/pull/38) Update to SCIP 10.0.0. From 5993592fed82c387bbc14542416e4d6e8a73caaa Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Thu, 18 Dec 2025 12:30:13 +0100 Subject: [PATCH 7/8] Enhance wording in changelog --- changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index edf49a50..011797f1 100644 --- a/changelog.md +++ b/changelog.md @@ -8,11 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [PR41](https://github.com/scipopt/SCIPpp/pull/41) Basic support of IIS extraction via `Model::generateIIS`. This requires that the plugin `IISfinderGreedy` is loaded (which is done by default) or any other plugin that can - find IIS'. Example usage: + find an IIS. Example usage: ```cpp Model model = ...; auto iis { model.generateIIS() }; - std::cout << "Contradicting are:\n"; + std::cout << "Contradicting constraints are:\n"; for (const auto& consId : iis.consIds) { std::cout << " " << consId << "\n"; } From 69cb3b7b7286d4ab733cc770484389b56201a1d9 Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Thu, 18 Dec 2025 12:32:35 +0100 Subject: [PATCH 8/8] Use auto instead of SCIP_CONS --- source/model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/model.cpp b/source/model.cpp index 130f311c..c827955c 100644 --- a/source/model.cpp +++ b/source/model.cpp @@ -190,7 +190,7 @@ IIS Model::generateIIS() const assert(conss); // GCOVR_EXCL_LINE result.consIds.reserve(nConss); for (size_t i { 0 }; i < nConss; ++i) { - SCIP_CONS* cons = conss[i]; + auto* cons = conss[i]; assert(cons); // GCOVR_EXCL_LINE result.consIds.emplace_back(SCIPconsGetName(cons)); }