do not use temp files for local params with SCIP

This commit is contained in:
Laurent Perron
2019-07-24 16:46:19 -07:00
parent 758667daf9
commit de01aacae4
3 changed files with 113 additions and 15 deletions

View File

@@ -21,6 +21,7 @@
#include <string>
#include <vector>
#include "absl/strings/str_format.h"
#include "absl/types/optional.h"
#include "ortools/base/canonical_errors.h"
#include "ortools/base/commandlineflags.h"
@@ -36,6 +37,7 @@
#include "ortools/linear_solver/scip_proto_solver.h"
#include "scip/cons_indicator.h"
#include "scip/scip.h"
#include "scip/scip_prob.h"
#include "scip/scipdefplugins.h"
DEFINE_bool(scip_feasibility_emphasis, false,
@@ -123,8 +125,8 @@ class SCIPInterface : public MPSolverInterface {
// necessery to enable multi-threading.
util::Status SetNumThreads(int num_threads) override;
bool ReadParameterFile(const std::string& filename) override;
std::string ValidFileExtensionForParameterFile() const override;
bool SetSolverSpecificParametersAsString(
const std::string& parameters) override;
void SetUnsupportedIntegerParam(
MPSolverParameters::IntegerParam param) override;
@@ -722,6 +724,9 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters& param) {
absl::optional<MPSolutionResponse> SCIPInterface::DirectlySolveProto(
const MPModelRequest& request) {
// ScipSolveProto doesn't solve concurrently.
if (solver_->GetNumThreads() > 1) return absl::nullopt;
const auto status_or = ScipSolveProto(request);
if (status_or.ok()) return status_or.ValueOrDie();
// Special case: if something is not implemented yet, fall back to solving
@@ -900,12 +905,10 @@ util::Status SCIPInterface::SetNumThreads(int num_threads) {
"indicate that SCIP API has changed.");
}
bool SCIPInterface::ReadParameterFile(const std::string& filename) {
return SCIPreadParams(scip_, filename.c_str()) == SCIP_OKAY;
}
std::string SCIPInterface::ValidFileExtensionForParameterFile() const {
return ".set";
bool SCIPInterface::SetSolverSpecificParametersAsString(
const std::string& parameters) {
return operations_research::ScipSetSolverSpecificParameters(parameters, scip_)
.ok();
}
MPSolverInterface* BuildSCIPInterface(MPSolver* const solver) {

View File

@@ -22,6 +22,8 @@
#include <string>
#include <vector>
#include "absl/strings/ascii.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_split.h"
@@ -33,11 +35,99 @@
#include "ortools/linear_solver/model_validator.h"
#include "ortools/linear_solver/scip_helper_macros.h"
#include "scip/scip.h"
#include "scip/scip_param.h"
#include "scip/scipdefplugins.h"
#include "scip/set.h"
#include "scip/struct_paramset.h"
#include "scip/struct_scip.h"
#include "scip/type_cons.h"
#include "scip/type_paramset.h"
namespace operations_research {
util::Status ScipSetSolverSpecificParameters(const std::string& parameters,
SCIP* scip) {
for (const auto parameter :
absl::StrSplit(parameters, '\n', absl::SkipWhitespace())) {
std::vector<std::string> key_value =
absl::StrSplit(parameter, '=', absl::SkipWhitespace());
if (key_value.size() != 2) {
return util::InvalidArgumentError(
absl::StrFormat("Cannot parse parameter '%s'. Expected format is "
"'parameter/name = value'",
parameter));
}
std::string name = key_value[0];
absl::RemoveExtraAsciiWhitespace(&name);
std::string value = key_value[1];
absl::RemoveExtraAsciiWhitespace(&value);
SCIP_PARAM* param = SCIPgetParam(scip, name.c_str());
if (param == nullptr) {
return util::InvalidArgumentError(
absl::StrFormat("Invalid parameter name '%s'", name));
}
switch (param->paramtype) {
case SCIP_PARAMTYPE_BOOL: {
bool parsed_value;
if (absl::SimpleAtob(value, &parsed_value)) {
RETURN_IF_SCIP_ERROR(
SCIPsetBoolParam(scip, name.c_str(), parsed_value));
continue;
}
break;
}
case SCIP_PARAMTYPE_INT: {
int parsed_value;
if (absl::SimpleAtoi(value, &parsed_value)) {
RETURN_IF_SCIP_ERROR(
SCIPsetIntParam(scip, name.c_str(), parsed_value));
continue;
}
break;
}
case SCIP_PARAMTYPE_LONGINT: {
int64 parsed_value;
if (absl::SimpleAtoi(value, &parsed_value)) {
RETURN_IF_SCIP_ERROR(
SCIPsetLongintParam(scip, name.c_str(), parsed_value));
continue;
}
break;
}
case SCIP_PARAMTYPE_REAL: {
double parsed_value;
if (absl::SimpleAtod(value, &parsed_value)) {
RETURN_IF_SCIP_ERROR(
SCIPsetRealParam(scip, name.c_str(), parsed_value));
continue;
}
break;
}
case SCIP_PARAMTYPE_CHAR: {
if (value.size() == 1) {
RETURN_IF_SCIP_ERROR(SCIPsetCharParam(scip, name.c_str(), value[0]));
continue;
}
break;
}
case SCIP_PARAMTYPE_STRING: {
if (value.front() == '"' && value.back() == '"') {
value.erase(value.begin());
value.erase(value.end() - 1);
}
RETURN_IF_SCIP_ERROR(
SCIPsetStringParam(scip, name.c_str(), value.c_str()));
continue;
}
}
return util::InvalidArgumentError(
absl::StrFormat("Invalid parameter value '%s'", parameter));
}
return util::OkStatus();
}
namespace {
util::Status AddSosConstraint(const MPGeneralConstraintProto& gen_cst,
const std::vector<SCIP_VAR*>& scip_variables,
@@ -153,12 +243,6 @@ util::StatusOr<MPSolutionResponse> ScipSolveProto(
}
const MPModelProto& model = request.model();
if (request.has_solver_specific_parameters()) {
// TODO(user): Support solver-specific parameters without duplicating
// all of the write file / read file code in linear_solver.cc.
return util::UnimplementedError(
"Solver-specific parameters not supported.");
}
if (model.has_solution_hint()) {
// TODO(user): Support solution hints.
return util::UnimplementedError("Solution hint not supported.");
@@ -194,6 +278,13 @@ util::StatusOr<MPSolutionResponse> ScipSolveProto(
RETURN_IF_SCIP_ERROR(SCIPcreate(&scip));
RETURN_IF_SCIP_ERROR(SCIPincludeDefaultPlugins(scip));
const auto parameters_status = ScipSetSolverSpecificParameters(
request.solver_specific_parameters(), scip);
if (!parameters_status.ok()) {
response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
response.set_status_str(parameters_status.error_message());
return response;
}
if (request.solver_time_limit_seconds() > 0 &&
request.solver_time_limit_seconds() < 1e20) {
RETURN_IF_SCIP_ERROR(SCIPsetRealParam(scip, "limits/time",
@@ -331,4 +422,4 @@ util::StatusOr<MPSolutionResponse> ScipSolveProto(
} // namespace operations_research
#endif // #if defined(USE_SCIP)
#endif // #if defined(USE_SCIP)

View File

@@ -16,9 +16,13 @@
#include "ortools/base/statusor.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "scip/type_scip.h"
namespace operations_research {
util::Status ScipSetSolverSpecificParameters(const std::string& parameters,
SCIP* scip);
util::StatusOr<MPSolutionResponse> ScipSolveProto(
const MPModelRequest& request);