Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 17 additions & 0 deletions include/scippp/iis.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <string>
#include <vector>

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<std::string> consIds;
};

}
9 changes: 9 additions & 0 deletions include/scippp/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <vector>

#include "scippp/constant_coefficient.hpp"
#include "scippp/iis.hpp"
#include "scippp/initial_solution.hpp"
#include "scippp/lin_expr.hpp"
#include "scippp/lin_ineq.hpp"
Expand Down Expand Up @@ -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.
*/
[[nodiscard]] IIS generateIIS() const;
};
}
23 changes: 23 additions & 0 deletions source/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,27 @@ 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) };

IIS result;
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;
}

}
52 changes: 52 additions & 0 deletions test/test_iis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <boost/test/unit_test.hpp>

#include "scippp/model.hpp"
#include "scippp/parameters.hpp"

#include <algorithm>

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()
Loading