polish linear solver backend selection code

This commit is contained in:
Laurent Perron
2020-06-25 10:32:58 +02:00
parent 86057e169b
commit a8fc48e1fd
5 changed files with 144 additions and 162 deletions

View File

@@ -125,6 +125,7 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable)
%unignore operations_research::MPSolver::MPSolver;
%unignore operations_research::MPSolver::~MPSolver;
%unignore operations_research::MPSolver::CreateSolver;
%unignore operations_research::MPSolver::ParseAndCheckSupportForProblemType;
%unignore operations_research::MPSolver::MakeBoolVar;
%unignore operations_research::MPSolver::MakeIntVar;
%unignore operations_research::MPSolver::MakeNumVar;

View File

@@ -286,6 +286,9 @@ PROTO2_RETURN(
%unignore operations_research::MPSolver::MPSolver;
%unignore operations_research::MPSolver::~MPSolver;
%rename (createSolver) operations_research::MPSolver::CreateSolver;
%rename (parseAndCheckSupportForProblemType)
operations_research::MPSolver::ParseAndCheckSupportForProblemType;
%unignore operations_research::MPConstraint;
%unignore operations_research::MPVariable;
%unignore operations_research::MPObjective;

View File

@@ -460,14 +460,18 @@ bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) {
if (problem_type == CLP_LINEAR_PROGRAMMING) return true;
#endif
#ifdef USE_GLPK
if (problem_type == GLPK_LINEAR_PROGRAMMING) return true;
if (problem_type == GLPK_MIXED_INTEGER_PROGRAMMING) return true;
if (problem_type == GLPK_LINEAR_PROGRAMMING ||
problem_type == GLPK_MIXED_INTEGER_PROGRAMMING) {
return true;
}
#endif
if (problem_type == BOP_INTEGER_PROGRAMMING) return true;
if (problem_type == SAT_INTEGER_PROGRAMMING) return true;
if (problem_type == GLOP_LINEAR_PROGRAMMING) return true;
if (problem_type == GUROBI_LINEAR_PROGRAMMING) return true;
if (problem_type == GUROBI_MIXED_INTEGER_PROGRAMMING) return true;
if (problem_type == GUROBI_LINEAR_PROGRAMMING ||
problem_type == GUROBI_MIXED_INTEGER_PROGRAMMING) {
return MPSolver::GurobiIsCorrectlyInstalled();
}
#ifdef USE_SCIP
if (problem_type == SCIP_MIXED_INTEGER_PROGRAMMING) return true;
#endif
@@ -475,12 +479,16 @@ bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) {
if (problem_type == CBC_MIXED_INTEGER_PROGRAMMING) return true;
#endif
#ifdef USE_XPRESS
if (problem_type == XPRESS_MIXED_INTEGER_PROGRAMMING) return true;
if (problem_type == XPRESS_LINEAR_PROGRAMMING) return true;
if (problem_type == XPRESS_MIXED_INTEGER_PROGRAMMING ||
problem_type == XPRESS_LINEAR_PROGRAMMING) {
return true;
}
#endif
#ifdef USE_CPLEX
if (problem_type == CPLEX_LINEAR_PROGRAMMING) return true;
if (problem_type == CPLEX_MIXED_INTEGER_PROGRAMMING) return true;
if (problem_type == CPLEX_LINEAR_PROGRAMMING ||
problem_type == CPLEX_MIXED_INTEGER_PROGRAMMING) {
return true;
}
#endif
return false;
}
@@ -502,49 +510,82 @@ constexpr
#endif
NamedOptimizationProblemType kOptimizationProblemTypeNames[] = {
{MPSolver::GLOP_LINEAR_PROGRAMMING, "glop"},
#if defined(USE_GLPK)
{MPSolver::GLPK_LINEAR_PROGRAMMING, "glpk_lp"},
#endif
#if defined(USE_CLP)
{MPSolver::CLP_LINEAR_PROGRAMMING, "clp"},
#endif
{MPSolver::GUROBI_LINEAR_PROGRAMMING, "gurobi_lp"},
#if defined(USE_CPLEX)
{MPSolver::GLPK_LINEAR_PROGRAMMING, "glpk_lp"},
{MPSolver::CPLEX_LINEAR_PROGRAMMING, "cplex_lp"},
#endif
#if defined(USE_XPRESS)
{MPSolver::XPRESS_LINEAR_PROGRAMMING, "xpress_lp"},
#endif
#if defined(USE_SCIP)
{MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING, "scip"},
#endif
#if defined(USE_CBC)
{MPSolver::CBC_MIXED_INTEGER_PROGRAMMING, "cbc"},
#endif
#if defined(USE_GLPK)
{MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING, "glpk_mip"},
#endif
{MPSolver::BOP_INTEGER_PROGRAMMING, "bop"},
{MPSolver::SAT_INTEGER_PROGRAMMING, "sat"},
{MPSolver::BOP_INTEGER_PROGRAMMING, "bop"},
{MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING, "gurobi_mip"},
#if defined(USE_CPLEX)
{MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING, "glpk_mip"},
{MPSolver::KNAPSACK_MIXED_INTEGER_PROGRAMMING, "knapsack"},
{MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, "cplex_mip"},
#endif
#if defined(USE_XPRESS)
{MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, "xpress_mip"},
#endif
};
};
// static
bool MPSolver::ParseSolverType(absl::string_view solver,
bool MPSolver::ParseSolverType(absl::string_view solver_id,
MPSolver::OptimizationProblemType* type) {
for (const auto& named_solver : kOptimizationProblemTypeNames) {
if (named_solver.name == solver) {
*type = named_solver.problem_type;
return true;
}
// Normalize the solver id.
const std::string id =
absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{"-", "_"}});
if (id == "CLP_LINEAR_PROGRAMMING" || id == "CLP") {
*type = MPSolver::CLP_LINEAR_PROGRAMMING;
return true;
} else if (id == "CBC_MIXED_INTEGER_PROGRAMMING" || id == "CBC") {
*type = MPSolver::CBC_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "GLOP_LINEAR_PROGRAMMING" || id == "GLOP") {
*type = MPSolver::GLOP_LINEAR_PROGRAMMING;
return true;
} else if (id == "BOP_INTEGER_PROGRAMMING" || id == "BOP") {
*type = MPSolver::BOP_INTEGER_PROGRAMMING;
return true;
} else if (id == "SAT_INTEGER_PROGRAMMING" || id == "SAT" || id == "CP_SAT") {
*type = MPSolver::SAT_INTEGER_PROGRAMMING;
return true;
} else if (id == "SCIP_MIXED_INTEGER_PROGRAMMING" || id == "SCIP") {
*type = MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "GUROBI_LINEAR_PROGRAMMING" || id == "GUROBI_LP") {
*type = MPSolver::GUROBI_LINEAR_PROGRAMMING;
return true;
} else if (id == "GUROBI_MIXED_INTEGER_PROGRAMMING" || id == "GUROBI_MIP" ||
id == "GUROBI") {
*type = MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "CPLEX_MIXED_INTEGER_PROGRAMMING" || id == "CPLEX_MIP" ||
id == "CPLEX") {
*type = MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "CPLEX_LINEAR_PROGRAMMING" || id == "CPLEX_LP") {
*type = MPSolver::CPLEX_LINEAR_PROGRAMMING;
return true;
} else if (id == "XPRESS_MIXED_INTEGER_PROGRAMMING" || id == "XPRESS" ||
id == "XPRESS_MIP") {
*type = MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "XPRESS_LINEAR_PROGRAMMING" || id == "XPRESS_LP") {
*type = MPSolver::XPRESS_LINEAR_PROGRAMMING;
return true;
} else if (id == "GLPK_MIXED_INTEGER_PROGRAMMING" || id == "GLPK_MIP" ||
id == "GLPK") {
*type = MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING;
return true;
} else if (id == "GLPK_LINEAR_PROGRAMMING" || id == "GLPK_LP") {
*type = MPSolver::GLPK_LINEAR_PROGRAMMING;
return true;
} else if (id == "KNAPSACK_MIXED_INTEGER_PROGRAMMING" || id == "KNAPSACK") {
*type = MPSolver::KNAPSACK_MIXED_INTEGER_PROGRAMMING;
return true;
} else {
return false;
}
return false;
}
const absl::string_view ToString(
@@ -571,95 +612,37 @@ bool AbslParseFlag(const absl::string_view text,
return result;
}
/* static */
bool MPSolver::ParseAndCheckSupportForProblemType(
const std::string& solver_id) {
MPSolver::OptimizationProblemType problem_type;
return MPSolver::ParseSolverType(solver_id, &problem_type) &&
MPSolver::SupportsProblemType(problem_type);
}
/* static */
MPSolver::OptimizationProblemType MPSolver::ParseSolverTypeOrDie(
const std::string& solver_id) {
MPSolver::OptimizationProblemType problem_type;
CHECK(MPSolver::ParseSolverType(solver_id, &problem_type));
return problem_type;
}
/* static */
MPSolver* MPSolver::CreateSolver(const std::string& name,
const std::string& solver_id) {
// Normalize the solver id.
const std::string id =
absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{"-", "_"}});
if (id == "CLP_LINEAR_PROGRAMMING" || id == "CLP") {
#if defined(USE_CLP)
return new MPSolver(name, MPSolver::CLP_LINEAR_PROGRAMMING);
#else
MPSolver::OptimizationProblemType problem_type;
if (!MPSolver::ParseSolverType(solver_id, &problem_type)) {
LOG(WARNING) << "Unrecognized solver type: " << solver_id;
return nullptr;
#endif
} else if (id == "CBC_MIXED_INTEGER_PROGRAMMING" || id == "CBC") {
#if defined(USE_CBC)
return new MPSolver(name, MPSolver::CBC_MIXED_INTEGER_PROGRAMMING);
#else
}
if (!MPSolver::SupportsProblemType(problem_type)) {
LOG(WARNING) << "Support for " << solver_id
<< " not linked in, or the license was not found.";
return nullptr;
#endif
} else if (id == "GLOP_LINEAR_PROGRAMMING" || id == "GLOP") {
return new MPSolver(name, MPSolver::GLOP_LINEAR_PROGRAMMING);
} else if (id == "BOP_INTEGER_PROGRAMMING" || id == "BOP") {
return new MPSolver(name, MPSolver::BOP_INTEGER_PROGRAMMING);
} else if (id == "SAT_INTEGER_PROGRAMMING" || id == "SAT" || id == "CP_SAT") {
return new MPSolver(name, MPSolver::SAT_INTEGER_PROGRAMMING);
} else if (id == "SCIP_MIXED_INTEGER_PROGRAMMING" || id == "SCIP") {
#if defined(USE_SCIP)
return new MPSolver(name, MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING);
#else
return nullptr;
#endif
} else if (id == "GUROBI_LINEAR_PROGRAMMING" || id == "GUROBI_LP") {
return GurobiIsCorrectlyInstalled()
? new MPSolver(name, MPSolver::GUROBI_LINEAR_PROGRAMMING)
: nullptr;
} else if (id == "GUROBI_MIXED_INTEGER_PROGRAMMING" || id == "GUROBI_MIP" ||
id == "GUROBI") {
return GurobiIsCorrectlyInstalled()
? new MPSolver(name, MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING)
: nullptr;
} else if (id == "CPLEX_MIXED_INTEGER_PROGRAMMING" || id == "CPLEX_MIP" ||
id == "CPLEX") {
#if defined(USE_CPLEX)
return new MPSolver(name, MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING);
#else
return nullptr;
#endif
} else if (id == "CPLEX_LINEAR_PROGRAMMING" || id == "CPLEX_LP") {
#if defined(USE_CPLEX)
return new MPSolver(name, MPSolver::CPLEX_LINEAR_PROGRAMMING);
#else
return nullptr;
#endif
}
return new MPSolver(name, problem_type);
}
else if (id == "XPRESS_MIXED_INTEGER_PROGRAMMING" || id == "XPRESS" ||
id == "XPRESS_MIP") {
#if defined(USE_XPRESS)
return new MPSolver(name, MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING);
#else
return nullptr;
#endif
}
else if (id == "XPRESS_LINEAR_PROGRAMMING" || id == "XPRESS_LP") {
#if defined(USE_XPRESS)
return new MPSolver(name, MPSolver::XPRESS_LINEAR_PROGRAMMING);
#else
return nullptr;
#endif
}
else if (id == "GLPK_MIXED_INTEGER_PROGRAMMING" || id == "GLPK_MIP" ||
id == "GLPK") {
#if defined(USE_GLPK)
return new MPSolver(name, MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING);
#else
return nullptr;
#endif
}
else if (id == "GLPK_LINEAR_PROGRAMMING" || id == "GLPK_LP") {
#if defined(USE_GLPK)
return new MPSolver(name, MPSolver::GLPK_LINEAR_PROGRAMMING);
#else
return nullptr;
#endif
}
else {
LOG(WARNING) << "Unrecognized solver id '" << solver_id << "'";
return nullptr;
}
} // namespace operations_research
MPVariable* MPSolver::LookupVariableOrNull(const std::string& var_name) const {
if (!variable_name_to_index_) GenerateVariableNameIndex();

View File

@@ -183,56 +183,37 @@ class MPSolver {
* (take particular care of the open-source version).
*/
enum OptimizationProblemType {
#ifdef USE_CLP
/// Linear Programming solver using Coin CBC.
// Linear programming problems.
// ----------------------------
CLP_LINEAR_PROGRAMMING = 0,
#endif
#ifdef USE_GLPK
/// Linear Programming solver using GLPK.
GLPK_LINEAR_PROGRAMMING = 1,
#endif
/// Linear Programming solver using GLOP (Recommended solver).
GLOP_LINEAR_PROGRAMMING = 2,
/// Linear Programming solver using GUROBI.
GUROBI_LINEAR_PROGRAMMING = 6,
#ifdef USE_CPLEX
/// Linear Programming solver using CPLEX.
CPLEX_LINEAR_PROGRAMMING = 10,
#endif
#if defined(USE_XPRESS)
/// Linear Programming solver using XPRESS-MP.
XPRESS_LINEAR_PROGRAMMING = 101,
#endif
GLOP_LINEAR_PROGRAMMING = 2, // Recommended default value. Made in Google.
// Integer programming problems.
#ifdef USE_SCIP
/// Mixed integer Programming Solver using SCIP.
// Integer programming problems.
// -----------------------------
SCIP_MIXED_INTEGER_PROGRAMMING = 3, // Recommended default value.
#endif
#ifdef USE_GLPK
/// Mixed integer Programming Solver using SCIP.
GLPK_MIXED_INTEGER_PROGRAMMING = 4,
#endif
#ifdef USE_CBC
/// Mixed integer Programming Solver using Coin CBC.
CBC_MIXED_INTEGER_PROGRAMMING = 5,
#endif
/// Mixed integer Programming Solver using GUROBI.
// Commercial software (need license).
GUROBI_LINEAR_PROGRAMMING = 6,
GUROBI_MIXED_INTEGER_PROGRAMMING = 7,
#if defined(USE_CPLEX)
/// Mixed integer Programming Solver using CPLEX.
CPLEX_LINEAR_PROGRAMMING = 10,
CPLEX_MIXED_INTEGER_PROGRAMMING = 11,
#endif
/// Linear Boolean Programming Solver.
BOP_INTEGER_PROGRAMMING = 12,
/// SAT based solver (requires only integer and Boolean variables).
/// If you pass it mixed integer problems, it will scale coefficients to
/// integer values, and solve continuous variables as integral variables.
SAT_INTEGER_PROGRAMMING = 14,
#if defined(USE_XPRESS)
/// Mixed integer Programming solver using XPRESS-MP.
XPRESS_LINEAR_PROGRAMMING = 101,
XPRESS_MIXED_INTEGER_PROGRAMMING = 102,
#endif
// Boolean optimization problem (requires only integer variables and works
// best with only Boolean variables).
BOP_INTEGER_PROGRAMMING = 12,
// SAT based solver (requires only integer and Boolean variables).
// If you pass it mixed integer problems, it will scale coefficients to
// integer values, and solver continuous variables as integral variables.
SAT_INTEGER_PROGRAMMING = 14,
// Dedicated knapsack solvers.
KNAPSACK_MIXED_INTEGER_PROGRAMMING = 13,
};
/// Create a solver with the given name and underlying solver backend.
@@ -278,9 +259,22 @@ class MPSolver {
* Parses the name of the solver. Returns true if the solver type is
* successfully parsed as one of the OptimizationProblemType.
*/
static bool ParseSolverType(absl::string_view solver,
static bool ParseSolverType(absl::string_view solver_id,
OptimizationProblemType* type);
/**
* Parses the name of the solver and returns the correct optimization type or
* dies.
*/
static OptimizationProblemType ParseSolverTypeOrDie(
const std::string& solver_id);
/**
* Parses the name of the solver. Returns true if the solver type is
* recognized and support for the solver is actually linked in.
*/
static bool ParseAndCheckSupportForProblemType(const std::string& solver_id);
bool IsMIP() const;
/// Returns the name of the model set at construction.

View File

@@ -301,6 +301,7 @@ PY_CONVERT(MPVariable);
%rename (Constraint) operations_research::MPSolver::MakeRowConstraint(const std::string&);
%unignore operations_research::MPSolver::~MPSolver;
%unignore operations_research::MPSolver::CreateSolver;
%unignore operations_research::MPSolver::ParseAndCheckSupportForProblemType;
%unignore operations_research::MPSolver::Solve;
%unignore operations_research::MPSolver::VerifySolution;
%unignore operations_research::MPSolver::infinity;