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`.
This commit is contained in:
committed by
Corentin Le Molgat
parent
6a603cc183
commit
204b31a748
@@ -1417,7 +1417,8 @@ namespace {
|
||||
const void* const kRegisterGurobiLp ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
|
||||
[](MPSolver* solver) { return new GurobiInterface(solver, false); },
|
||||
MPSolver::GUROBI_LINEAR_PROGRAMMING);
|
||||
MPSolver::GUROBI_LINEAR_PROGRAMMING,
|
||||
[]() { return GurobiIsCorrectlyInstalled(); });
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
@@ -1425,7 +1426,8 @@ const void* const kRegisterGurobiLp ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
const void* const kRegisterGurobiMip ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
|
||||
[](MPSolver* solver) { return new GurobiInterface(solver, true); },
|
||||
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING);
|
||||
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING,
|
||||
[]() { return GurobiIsCorrectlyInstalled(); });
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
|
||||
@@ -412,26 +412,10 @@ MPSolver::MPSolver(const std::string& name,
|
||||
|
||||
MPSolver::~MPSolver() { Clear(); }
|
||||
|
||||
extern bool GurobiIsCorrectlyInstalled();
|
||||
extern bool XpressIsCorrectlyInstalled();
|
||||
|
||||
// static
|
||||
bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) {
|
||||
if (!MPSolverInterfaceFactoryRepository::GetInstance()->Supports(
|
||||
problem_type)) {
|
||||
return false;
|
||||
}
|
||||
switch (problem_type) {
|
||||
case GUROBI_LINEAR_PROGRAMMING:
|
||||
case GUROBI_MIXED_INTEGER_PROGRAMMING:
|
||||
return GurobiIsCorrectlyInstalled();
|
||||
case XPRESS_LINEAR_PROGRAMMING:
|
||||
case XPRESS_MIXED_INTEGER_PROGRAMMING:
|
||||
return XpressIsCorrectlyInstalled();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return MPSolverInterfaceFactoryRepository::GetInstance()->Supports(
|
||||
problem_type);
|
||||
}
|
||||
|
||||
// TODO(user): post c++ 14, instead use
|
||||
@@ -2238,9 +2222,14 @@ MPSolverInterfaceFactoryRepository::~MPSolverInterfaceFactoryRepository() {
|
||||
|
||||
void MPSolverInterfaceFactoryRepository::Register(
|
||||
MPSolverInterfaceFactory factory,
|
||||
MPSolver::OptimizationProblemType problem_type) {
|
||||
MPSolver::OptimizationProblemType problem_type,
|
||||
std::function<bool()> is_runtime_ready) {
|
||||
absl::MutexLock lock(mutex_);
|
||||
map_[problem_type] = std::move(factory);
|
||||
if (!is_runtime_ready) is_runtime_ready = []() { return true; };
|
||||
map_[problem_type] = Entry{
|
||||
.factory = std::move(factory),
|
||||
.is_runtime_ready = std::move(is_runtime_ready),
|
||||
};
|
||||
}
|
||||
|
||||
bool MPSolverInterfaceFactoryRepository::Unregister(
|
||||
@@ -2252,17 +2241,20 @@ bool MPSolverInterfaceFactoryRepository::Unregister(
|
||||
MPSolverInterface* MPSolverInterfaceFactoryRepository::Create(
|
||||
MPSolver* solver) const {
|
||||
absl::MutexLock lock(mutex_);
|
||||
const MPSolverInterfaceFactory factory =
|
||||
gtl::FindWithDefault(map_, solver->ProblemType(), nullptr);
|
||||
if (!factory) {
|
||||
return nullptr;
|
||||
}
|
||||
return factory(solver);
|
||||
const Entry* entry = gtl::FindOrNull(map_, solver->ProblemType());
|
||||
CHECK(entry != nullptr) << "No factory registered for problem type "
|
||||
<< ToString(solver->ProblemType());
|
||||
CHECK(entry->is_runtime_ready())
|
||||
<< "Solver for problem type " << ToString(solver->ProblemType())
|
||||
<< " is not ready.";
|
||||
return entry->factory(solver);
|
||||
}
|
||||
|
||||
bool MPSolverInterfaceFactoryRepository::Supports(
|
||||
MPSolver::OptimizationProblemType problem_type) const {
|
||||
return map_.count(problem_type) > 0;
|
||||
const Entry* entry = gtl::FindOrNull(map_, problem_type);
|
||||
if (entry == nullptr) return false;
|
||||
return entry->is_runtime_ready();
|
||||
}
|
||||
|
||||
std::vector<MPSolver::OptimizationProblemType>
|
||||
|
||||
@@ -152,6 +152,7 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/flags/declare.h"
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
@@ -1959,17 +1960,20 @@ class MPSolverInterfaceFactoryRepository {
|
||||
public:
|
||||
static MPSolverInterfaceFactoryRepository* GetInstance();
|
||||
|
||||
// Maps the given factory to the given problem type. If a factory was already
|
||||
// assigned to this problem type, it will be replaced.
|
||||
// Maps the given factory to the given problem type. For solver needing
|
||||
// runtime checks an additional `is_runtime_ready` argument can be set. If
|
||||
// a factory was already assigned to this problem type, it will be replaced.
|
||||
void Register(MPSolverInterfaceFactory factory,
|
||||
MPSolver::OptimizationProblemType problem_type);
|
||||
MPSolver::OptimizationProblemType problem_type,
|
||||
std::function<bool()> is_runtime_ready = {});
|
||||
|
||||
// Invokes the factory associated to the given solver's problem type,
|
||||
// or return NULL if no factory was found for it.
|
||||
// Invokes the factory associated to the given solver's problem type and fails
|
||||
// if no factory is registered or its runtime is not ready.
|
||||
// Use `Supports` below to check if `Create` succeeds.
|
||||
MPSolverInterface* Create(MPSolver* solver) const;
|
||||
|
||||
// Whether the implementation associated to the given problem type is
|
||||
// available.
|
||||
// available and ready to use.
|
||||
bool Supports(MPSolver::OptimizationProblemType problem_type) const;
|
||||
|
||||
// List all the problem types.
|
||||
@@ -1991,7 +1995,11 @@ class MPSolverInterfaceFactoryRepository {
|
||||
~MPSolverInterfaceFactoryRepository();
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
std::map<MPSolver::OptimizationProblemType, MPSolverInterfaceFactory> map_;
|
||||
struct Entry {
|
||||
MPSolverInterfaceFactory factory;
|
||||
std::function<bool()> is_runtime_ready;
|
||||
};
|
||||
std::map<MPSolver::OptimizationProblemType, Entry> map_;
|
||||
};
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -2289,7 +2289,8 @@ namespace {
|
||||
const void* const kRegisterXpress ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
|
||||
[](MPSolver* const solver) { return new XpressInterface(solver, false); },
|
||||
MPSolver::XPRESS_LINEAR_PROGRAMMING);
|
||||
MPSolver::XPRESS_LINEAR_PROGRAMMING,
|
||||
[]() { return XpressIsCorrectlyInstalled(); });
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
@@ -2297,7 +2298,8 @@ const void* const kRegisterXpress ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
const void* const kRegisterXpressMip ABSL_ATTRIBUTE_UNUSED = [] {
|
||||
MPSolverInterfaceFactoryRepository::GetInstance()->Register(
|
||||
[](MPSolver* const solver) { return new XpressInterface(solver, true); },
|
||||
MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING);
|
||||
MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING,
|
||||
[]() { return XpressIsCorrectlyInstalled(); });
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user