Skip to content

Commit 204b31a

Browse files
gchateletMizux
authored andcommitted
Refactor MPSolver interface registration to include runtime readiness checks. (#4973)
This PR is removing the need for `linear_solver` to depend on `GurobiIsCorrectlyInstalled` and `XpressIsCorrectlyInstalled`.
1 parent 6a603cc commit 204b31a

4 files changed

Lines changed: 42 additions & 38 deletions

File tree

ortools/linear_solver/gurobi_interface.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,15 +1417,17 @@ namespace {
14171417
const void* const kRegisterGurobiLp ABSL_ATTRIBUTE_UNUSED = [] {
14181418
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
14191419
[](MPSolver* solver) { return new GurobiInterface(solver, false); },
1420-
MPSolver::GUROBI_LINEAR_PROGRAMMING);
1420+
MPSolver::GUROBI_LINEAR_PROGRAMMING,
1421+
[]() { return GurobiIsCorrectlyInstalled(); });
14211422
return nullptr;
14221423
}();
14231424

14241425
// See MpSolverInterfaceFactoryRepository for details.
14251426
const void* const kRegisterGurobiMip ABSL_ATTRIBUTE_UNUSED = [] {
14261427
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
14271428
[](MPSolver* solver) { return new GurobiInterface(solver, true); },
1428-
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING);
1429+
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING,
1430+
[]() { return GurobiIsCorrectlyInstalled(); });
14291431
return nullptr;
14301432
}();
14311433

ortools/linear_solver/linear_solver.cc

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -412,26 +412,10 @@ MPSolver::MPSolver(const std::string& name,
412412

413413
MPSolver::~MPSolver() { Clear(); }
414414

415-
extern bool GurobiIsCorrectlyInstalled();
416-
extern bool XpressIsCorrectlyInstalled();
417-
418415
// static
419416
bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) {
420-
if (!MPSolverInterfaceFactoryRepository::GetInstance()->Supports(
421-
problem_type)) {
422-
return false;
423-
}
424-
switch (problem_type) {
425-
case GUROBI_LINEAR_PROGRAMMING:
426-
case GUROBI_MIXED_INTEGER_PROGRAMMING:
427-
return GurobiIsCorrectlyInstalled();
428-
case XPRESS_LINEAR_PROGRAMMING:
429-
case XPRESS_MIXED_INTEGER_PROGRAMMING:
430-
return XpressIsCorrectlyInstalled();
431-
default:
432-
break;
433-
}
434-
return true;
417+
return MPSolverInterfaceFactoryRepository::GetInstance()->Supports(
418+
problem_type);
435419
}
436420

437421
// TODO(user): post c++ 14, instead use
@@ -2238,9 +2222,14 @@ MPSolverInterfaceFactoryRepository::~MPSolverInterfaceFactoryRepository() {
22382222

22392223
void MPSolverInterfaceFactoryRepository::Register(
22402224
MPSolverInterfaceFactory factory,
2241-
MPSolver::OptimizationProblemType problem_type) {
2225+
MPSolver::OptimizationProblemType problem_type,
2226+
std::function<bool()> is_runtime_ready) {
22422227
absl::MutexLock lock(mutex_);
2243-
map_[problem_type] = std::move(factory);
2228+
if (!is_runtime_ready) is_runtime_ready = []() { return true; };
2229+
map_[problem_type] = Entry{
2230+
.factory = std::move(factory),
2231+
.is_runtime_ready = std::move(is_runtime_ready),
2232+
};
22442233
}
22452234

22462235
bool MPSolverInterfaceFactoryRepository::Unregister(
@@ -2252,17 +2241,20 @@ bool MPSolverInterfaceFactoryRepository::Unregister(
22522241
MPSolverInterface* MPSolverInterfaceFactoryRepository::Create(
22532242
MPSolver* solver) const {
22542243
absl::MutexLock lock(mutex_);
2255-
const MPSolverInterfaceFactory factory =
2256-
gtl::FindWithDefault(map_, solver->ProblemType(), nullptr);
2257-
if (!factory) {
2258-
return nullptr;
2259-
}
2260-
return factory(solver);
2244+
const Entry* entry = gtl::FindOrNull(map_, solver->ProblemType());
2245+
CHECK(entry != nullptr) << "No factory registered for problem type "
2246+
<< ToString(solver->ProblemType());
2247+
CHECK(entry->is_runtime_ready())
2248+
<< "Solver for problem type " << ToString(solver->ProblemType())
2249+
<< " is not ready.";
2250+
return entry->factory(solver);
22612251
}
22622252

22632253
bool MPSolverInterfaceFactoryRepository::Supports(
22642254
MPSolver::OptimizationProblemType problem_type) const {
2265-
return map_.count(problem_type) > 0;
2255+
const Entry* entry = gtl::FindOrNull(map_, problem_type);
2256+
if (entry == nullptr) return false;
2257+
return entry->is_runtime_ready();
22662258
}
22672259

22682260
std::vector<MPSolver::OptimizationProblemType>

ortools/linear_solver/linear_solver.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
#include "absl/container/flat_hash_map.h"
153153
#include "absl/flags/declare.h"
154154
#include "absl/log/check.h"
155+
#include "absl/log/log.h"
155156
#include "absl/status/status.h"
156157
#include "absl/strings/str_format.h"
157158
#include "absl/strings/string_view.h"
@@ -1959,17 +1960,20 @@ class MPSolverInterfaceFactoryRepository {
19591960
public:
19601961
static MPSolverInterfaceFactoryRepository* GetInstance();
19611962

1962-
// Maps the given factory to the given problem type. If a factory was already
1963-
// assigned to this problem type, it will be replaced.
1963+
// Maps the given factory to the given problem type. For solver needing
1964+
// runtime checks an additional `is_runtime_ready` argument can be set. If
1965+
// a factory was already assigned to this problem type, it will be replaced.
19641966
void Register(MPSolverInterfaceFactory factory,
1965-
MPSolver::OptimizationProblemType problem_type);
1967+
MPSolver::OptimizationProblemType problem_type,
1968+
std::function<bool()> is_runtime_ready = {});
19661969

1967-
// Invokes the factory associated to the given solver's problem type,
1968-
// or return NULL if no factory was found for it.
1970+
// Invokes the factory associated to the given solver's problem type and fails
1971+
// if no factory is registered or its runtime is not ready.
1972+
// Use `Supports` below to check if `Create` succeeds.
19691973
MPSolverInterface* Create(MPSolver* solver) const;
19701974

19711975
// Whether the implementation associated to the given problem type is
1972-
// available.
1976+
// available and ready to use.
19731977
bool Supports(MPSolver::OptimizationProblemType problem_type) const;
19741978

19751979
// List all the problem types.
@@ -1991,7 +1995,11 @@ class MPSolverInterfaceFactoryRepository {
19911995
~MPSolverInterfaceFactoryRepository();
19921996

19931997
mutable absl::Mutex mutex_;
1994-
std::map<MPSolver::OptimizationProblemType, MPSolverInterfaceFactory> map_;
1998+
struct Entry {
1999+
MPSolverInterfaceFactory factory;
2000+
std::function<bool()> is_runtime_ready;
2001+
};
2002+
std::map<MPSolver::OptimizationProblemType, Entry> map_;
19952003
};
19962004

19972005
} // namespace operations_research

ortools/linear_solver/xpress_interface.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,15 +2289,17 @@ namespace {
22892289
const void* const kRegisterXpress ABSL_ATTRIBUTE_UNUSED = [] {
22902290
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
22912291
[](MPSolver* const solver) { return new XpressInterface(solver, false); },
2292-
MPSolver::XPRESS_LINEAR_PROGRAMMING);
2292+
MPSolver::XPRESS_LINEAR_PROGRAMMING,
2293+
[]() { return XpressIsCorrectlyInstalled(); });
22932294
return nullptr;
22942295
}();
22952296

22962297
// See MpSolverInterfaceFactoryRepository for details.
22972298
const void* const kRegisterXpressMip ABSL_ATTRIBUTE_UNUSED = [] {
22982299
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
22992300
[](MPSolver* const solver) { return new XpressInterface(solver, true); },
2300-
MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING);
2301+
MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING,
2302+
[]() { return XpressIsCorrectlyInstalled(); });
23012303
return nullptr;
23022304
}();
23032305

0 commit comments

Comments
 (0)